├── .github └── workflows │ ├── CI.yml │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── Makefile ├── config ├── app_config.h ├── custom_board.h └── sdk_config.h ├── crazyflie2_nrf_firmware.ld ├── module.json ├── readme.md ├── src ├── atomic.h ├── ble_crazyflie.c ├── ble_crazyflie.h ├── bootloader.c ├── bootloader.h ├── button.c ├── button.h ├── crazyflie2_pm.c ├── crazyflie2_pm.h ├── crc.c ├── crc.h ├── crtp.h ├── esb.c ├── esb.h ├── main.c ├── platform.c ├── platform.h ├── syslink.c ├── syslink.h ├── systick.c ├── systick.h ├── timeslot.c ├── timeslot.h ├── uart.c └── uart.h └── tools ├── build ├── build ├── build-update-binary ├── fetch-dependencies └── generateVersionHeader.py ├── debug └── send_syslink.py ├── generate_update_binary.py └── nrf5sdk.patch /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # Build the project using the Bitcraze builder docker image 2 | name: CI 3 | 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | schedule: 10 | # Weekly build to make sure dependencies are OK 11 | - cron: '30 12 * * 1' 12 | 13 | jobs: 14 | build: 15 | uses: bitcraze/workflows/.github/workflows/basic_build.yml@b59a297ee5a6105780d4ac832100f8990f243d04 16 | with: 17 | builder_image: 'bitcraze/builder' -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Release jobs 2 | 3 | name: Release 4 | 5 | on: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | uses: bitcraze/workflows/.github/workflows/basic_release.yml@b06a0f369e637f5f5a5f83f5e86d9b1f9e173289 11 | with: 12 | builder_image: 'bitcraze/builder' 13 | build_script: './tools/build/build-update-binary' 14 | artifacts: '_build/sd130_bootloader.bin _build/nrf_bootloader.bin' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | *.o 3 | *.d 4 | _build/ -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Cortex Debug", 9 | "cwd": "${workspaceFolder}", 10 | "executable": "./_build/nrf51422_xxaa.out", 11 | "request": "launch", 12 | "type": "cortex-debug", 13 | "runToEntryPoint": "main", 14 | "servertype": "jlink", 15 | "device": "nRF51422_xxAC", 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.c": "c", 4 | "nrf_atomic.h": "c", 5 | "type_traits": "cpp", 6 | "softdevice_handler.h": "c", 7 | "app_button.h": "c", 8 | "crazyflie2_pm.h": "c", 9 | "boards.h": "c", 10 | "timeslot.h": "c", 11 | "button.h": "c", 12 | "ble_hci.h": "c", 13 | "nrf_mbr.h": "c", 14 | "crtp.h": "c", 15 | "systick.h": "c" 16 | }, 17 | "cortex-debug.variableUseNaturalFormat": false 18 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := crazyflie2_nrf_firmware 2 | TARGETS := nrf51422_xxaa 3 | OUTPUT_DIRECTORY := _build 4 | 5 | ifeq ($(DEVBOARD),1) 6 | BOARD ?= PCA10028 7 | else 8 | BOARD ?= CUSTOM 9 | endif 10 | 11 | SDK_ROOT := vendor/nrf5sdk 12 | PROJ_DIR := src 13 | 14 | $(OUTPUT_DIRECTORY)/nrf51422_xxaa.out: \ 15 | LINKER_SCRIPT := crazyflie2_nrf_firmware.ld 16 | 17 | # Source files common to all targets 18 | SRC_FILES += \ 19 | $(SDK_ROOT)/components/libraries/log/src/nrf_log_backend_serial.c \ 20 | $(SDK_ROOT)/components/libraries/log/src/nrf_log_frontend.c \ 21 | $(SDK_ROOT)/components/libraries/util/app_error.c \ 22 | $(SDK_ROOT)/components/libraries/util/app_error_weak.c \ 23 | $(SDK_ROOT)/components/libraries/timer/app_timer.c \ 24 | $(SDK_ROOT)/components/libraries/util/app_util_platform.c \ 25 | $(SDK_ROOT)/components/libraries/crc16/crc16.c \ 26 | $(SDK_ROOT)/components/libraries/fstorage/fstorage.c \ 27 | $(SDK_ROOT)/components/libraries/hardfault/hardfault_implementation.c \ 28 | $(SDK_ROOT)/components/libraries/util/nrf_assert.c \ 29 | $(SDK_ROOT)/components/libraries/util/sdk_errors.c \ 30 | $(SDK_ROOT)/components/libraries/util/sdk_mapped_flags.c \ 31 | $(SDK_ROOT)/components/libraries/mailbox/app_mailbox.c \ 32 | $(SDK_ROOT)/components/boards/boards.c \ 33 | $(SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \ 34 | $(SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \ 35 | $(SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \ 36 | $(PROJ_DIR)/main.c \ 37 | $(PROJ_DIR)/ble_crazyflie.c \ 38 | $(PROJ_DIR)/syslink.c \ 39 | $(PROJ_DIR)/crazyflie2_pm.c \ 40 | $(PROJ_DIR)/esb.c \ 41 | $(PROJ_DIR)/timeslot.c \ 42 | $(PROJ_DIR)/button.c \ 43 | $(PROJ_DIR)/systick.c \ 44 | $(PROJ_DIR)/uart.c \ 45 | $(PROJ_DIR)/bootloader.c \ 46 | $(PROJ_DIR)/crc.c \ 47 | $(PROJ_DIR)/platform.c \ 48 | $(SDK_ROOT)/external/segger_rtt/RTT_Syscalls_GCC.c \ 49 | $(SDK_ROOT)/external/segger_rtt/SEGGER_RTT.c \ 50 | $(SDK_ROOT)/external/segger_rtt/SEGGER_RTT_printf.c \ 51 | $(SDK_ROOT)/components/ble/common/ble_advdata.c \ 52 | $(SDK_ROOT)/components/ble/ble_advertising/ble_advertising.c \ 53 | $(SDK_ROOT)/components/ble/common/ble_conn_params.c \ 54 | $(SDK_ROOT)/components/ble/common/ble_conn_state.c \ 55 | $(SDK_ROOT)/components/ble/common/ble_srv_common.c \ 56 | $(SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf51.S \ 57 | $(SDK_ROOT)/components/toolchain/system_nrf51.c \ 58 | $(SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c \ 59 | $(SDK_ROOT)/components/ble/ble_services/ble_dis/ble_dis.c 60 | 61 | # Include folders common to all targets 62 | INC_FOLDERS += \ 63 | $(SDK_ROOT)/components/drivers_nrf/comp \ 64 | $(SDK_ROOT)/components/drivers_nrf/twi_master \ 65 | $(SDK_ROOT)/components/ble/ble_services/ble_ancs_c \ 66 | $(SDK_ROOT)/components/ble/ble_services/ble_ias_c \ 67 | $(SDK_ROOT)/components/softdevice/s130/headers \ 68 | $(SDK_ROOT)/components/libraries/pwm \ 69 | $(SDK_ROOT)/components/libraries/usbd/class/cdc/acm \ 70 | $(SDK_ROOT)/components/libraries/usbd/class/hid/generic \ 71 | $(SDK_ROOT)/components/libraries/usbd/class/msc \ 72 | $(SDK_ROOT)/components/libraries/usbd/class/hid \ 73 | $(SDK_ROOT)/components/libraries/log \ 74 | $(SDK_ROOT)/components/libraries/mailbox \ 75 | $(SDK_ROOT)/components/ble/ble_services/ble_gls \ 76 | $(SDK_ROOT)/components/libraries/fstorage \ 77 | $(SDK_ROOT)/components/drivers_nrf/i2s \ 78 | $(SDK_ROOT)/components/libraries/gpiote \ 79 | $(SDK_ROOT)/components/drivers_nrf/gpiote \ 80 | $(SDK_ROOT)/components/boards \ 81 | $(SDK_ROOT)/components/drivers_nrf/common \ 82 | $(SDK_ROOT)/components/ble/ble_advertising \ 83 | $(SDK_ROOT)/components/drivers_nrf/adc \ 84 | $(SDK_ROOT)/components/softdevice/s130/headers/nrf51 \ 85 | $(SDK_ROOT)/components/ble/ble_services/ble_bas_c \ 86 | $(SDK_ROOT)/components/ble/ble_services/ble_hrs_c \ 87 | $(SDK_ROOT)/components/libraries/queue \ 88 | $(SDK_ROOT)/components/ble/ble_dtm \ 89 | $(SDK_ROOT)/components/toolchain/cmsis/include \ 90 | $(SDK_ROOT)/components/ble/ble_services/ble_rscs_c \ 91 | $(SDK_ROOT)/components/drivers_nrf/uart \ 92 | $(SDK_ROOT)/components/ble/common \ 93 | $(SDK_ROOT)/components/ble/ble_services/ble_lls \ 94 | $(SDK_ROOT)/components/drivers_nrf/wdt \ 95 | $(SDK_ROOT)/components/libraries/bsp \ 96 | $(SDK_ROOT)/components/ble/ble_services/ble_bas \ 97 | $(SDK_ROOT)/components/libraries/experimental_section_vars \ 98 | $(SDK_ROOT)/components/ble/ble_services/ble_ans_c \ 99 | $(SDK_ROOT)/components/libraries/slip \ 100 | $(SDK_ROOT)/components/libraries/mem_manager \ 101 | $(SDK_ROOT)/external/segger_rtt \ 102 | $(SDK_ROOT)/components/libraries/csense_drv \ 103 | $(SDK_ROOT)/components/drivers_nrf/hal \ 104 | $(SDK_ROOT)/components/ble/ble_services/ble_nus_c \ 105 | $(SDK_ROOT)/components/drivers_nrf/rtc \ 106 | $(SDK_ROOT)/components/ble/ble_services/ble_ias \ 107 | $(SDK_ROOT)/components/libraries/usbd/class/hid/mouse \ 108 | $(SDK_ROOT)/components/drivers_nrf/ppi \ 109 | $(SDK_ROOT)/components/ble/ble_services/ble_dfu \ 110 | $(SDK_ROOT)/components/drivers_nrf/twis_slave \ 111 | $(SDK_ROOT)/components \ 112 | $(SDK_ROOT)/components/libraries/scheduler \ 113 | $(SDK_ROOT)/components/ble/ble_services/ble_lbs \ 114 | $(SDK_ROOT)/components/ble/ble_services/ble_hts \ 115 | $(SDK_ROOT)/components/drivers_nrf/delay \ 116 | $(SDK_ROOT)/components/libraries/crc16 \ 117 | $(SDK_ROOT)/components/drivers_nrf/timer \ 118 | $(SDK_ROOT)/components/libraries/util \ 119 | $(SDK_ROOT)/components/drivers_nrf/pwm \ 120 | $(PROJ_DIR)/../config \ 121 | $(SDK_ROOT)/components/libraries/usbd/class/cdc \ 122 | $(SDK_ROOT)/components/libraries/csense \ 123 | $(SDK_ROOT)/components/drivers_nrf/rng \ 124 | $(SDK_ROOT)/components/libraries/low_power_pwm \ 125 | $(SDK_ROOT)/components/libraries/hardfault \ 126 | $(SDK_ROOT)/components/ble/ble_services/ble_cscs \ 127 | $(SDK_ROOT)/components/libraries/uart \ 128 | $(SDK_ROOT)/components/libraries/hci \ 129 | $(SDK_ROOT)/components/libraries/usbd/class/hid/kbd \ 130 | $(SDK_ROOT)/components/drivers_nrf/spi_slave \ 131 | $(SDK_ROOT)/components/drivers_nrf/lpcomp \ 132 | $(SDK_ROOT)/components/libraries/timer \ 133 | $(SDK_ROOT)/components/drivers_nrf/power \ 134 | $(SDK_ROOT)/components/libraries/usbd/config \ 135 | $(SDK_ROOT)/components/toolchain \ 136 | $(SDK_ROOT)/components/libraries/led_softblink \ 137 | $(SDK_ROOT)/components/drivers_nrf/qdec \ 138 | $(SDK_ROOT)/components/ble/ble_services/ble_cts_c \ 139 | $(SDK_ROOT)/components/drivers_nrf/spi_master \ 140 | $(SDK_ROOT)/components/ble/ble_services/ble_nus \ 141 | $(SDK_ROOT)/components/ble/ble_services/ble_hids \ 142 | $(SDK_ROOT)/components/drivers_nrf/pdm \ 143 | $(SDK_ROOT)/components/libraries/crc32 \ 144 | $(SDK_ROOT)/components/libraries/usbd/class/audio \ 145 | $(SDK_ROOT)/components/libraries/sensorsim \ 146 | $(SDK_ROOT)/components/ble/peer_manager \ 147 | $(SDK_ROOT)/components/drivers_nrf/swi \ 148 | $(SDK_ROOT)/components/ble/ble_services/ble_tps \ 149 | $(SDK_ROOT)/components/ble/ble_services/ble_dis \ 150 | $(SDK_ROOT)/components/device \ 151 | $(SDK_ROOT)/components/ble/nrf_ble_qwr \ 152 | $(SDK_ROOT)/components/libraries/button \ 153 | $(SDK_ROOT)/components/libraries/usbd \ 154 | $(SDK_ROOT)/components/drivers_nrf/saadc \ 155 | $(SDK_ROOT)/components/ble/ble_services/ble_lbs_c \ 156 | $(SDK_ROOT)/components/ble/ble_racp \ 157 | $(SDK_ROOT)/components/toolchain/gcc \ 158 | $(SDK_ROOT)/components/libraries/fds \ 159 | $(SDK_ROOT)/components/libraries/twi \ 160 | $(SDK_ROOT)/components/drivers_nrf/clock \ 161 | $(SDK_ROOT)/components/ble/ble_services/ble_rscs \ 162 | $(SDK_ROOT)/components/drivers_nrf/usbd \ 163 | $(SDK_ROOT)/components/softdevice/common/softdevice_handler \ 164 | $(SDK_ROOT)/components/ble/ble_services/ble_hrs \ 165 | $(SDK_ROOT)/components/libraries/log/src \ 166 | $(SDK_ROOT)/components/ble/ble_services/ble_dis \ 167 | $(OUTPUT_DIRECTORY) \ 168 | 169 | # Libraries common to all targets 170 | LIB_FILES += \ 171 | 172 | # C flags common to all targets 173 | CFLAGS += -DBOARD_${BOARD} 174 | CFLAGS += -DSOFTDEVICE_PRESENT 175 | CFLAGS += -DNRF51 176 | CFLAGS += -DS130 177 | CFLAGS += -DBLE_STACK_SUPPORT_REQD 178 | CFLAGS += -DSWI_DISABLE0 179 | CFLAGS += -DNRF51422 180 | CFLAGS += -DNRF_SD_BLE_API_VERSION=2 181 | CFLAGS += -mcpu=cortex-m0 182 | CFLAGS += -mthumb -mabi=aapcs 183 | CFLAGS += -Wall -Werror -Os -g3 184 | CFLAGS += -mfloat-abi=soft 185 | # keep every function in separate section, this allows linker to discard unused ones 186 | CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing 187 | CFLAGS += -fno-builtin --short-enums 188 | # Disable checks of newer compilers that the SDK does not pass 189 | CFLAGS += -Wno-error=array-bounds 190 | 191 | # Enable app config 192 | CFLAGS += -DUSE_APP_CONFIG 193 | 194 | # C++ flags common to all targets 195 | CXXFLAGS += \ 196 | 197 | # Assembler flags common to all targets 198 | ASMFLAGS += -x assembler-with-cpp 199 | ASMFLAGS += -DBOARD_${BOARD} 200 | ASMFLAGS += -DSOFTDEVICE_PRESENT 201 | ASMFLAGS += -DNRF51 202 | ASMFLAGS += -DS130 203 | ASMFLAGS += -DBLE_STACK_SUPPORT_REQD 204 | ASMFLAGS += -DSWI_DISABLE0 205 | ASMFLAGS += -DNRF51422 206 | ASMFLAGS += -DNRF_SD_BLE_API_VERSION=2 207 | ASMFLAGS += -D__STACK_SIZE=512 208 | ASMFLAGS += -D__HEAP_SIZE=512 209 | 210 | # Linker flags 211 | LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) 212 | LDFLAGS += -mcpu=cortex-m0 213 | # let linker to dump unused sections 214 | LDFLAGS += -Wl,--gc-sections 215 | # use newlib in nano version 216 | LDFLAGS += --specs=nano.specs -lc -lnosys 217 | 218 | 219 | .PHONY: $(TARGETS) default all clean help flash flash_softdevice version.h 220 | 221 | # Default target - first one defined 222 | default: nrf51422_xxaa 223 | 224 | # Print all targets that can be built 225 | help: 226 | @echo following targets are available: 227 | @echo nrf51422_xxaa 228 | 229 | TEMPLATE_PATH := $(SDK_ROOT)/components/toolchain/gcc 230 | 231 | include $(TEMPLATE_PATH)/Makefile.common 232 | 233 | $(foreach target, $(TARGETS), $(call define_target, $(target))) 234 | 235 | # Flash the program 236 | flash: $(OUTPUT_DIRECTORY)/nrf51422_xxaa.hex 237 | @echo Flashing: $< 238 | nrfjprog --program $< -f nrf51 --sectorerase 239 | nrfjprog --reset -f nrf51 240 | 241 | # Flash softdevice 242 | flash_softdevice: 243 | @echo Flashing: s130_nrf51_2.0.1_softdevice.hex 244 | nrfjprog --program $(SDK_ROOT)/components/softdevice/s130/hex/s130_nrf51_2.0.1_softdevice.hex -f nrf51 --sectorerase 245 | nrfjprog --reset -f nrf51 246 | 247 | flash_mbs: 248 | nrfjprog --program nrf_mbs_cf21.hex -f nrf51 --sectorerase 249 | nrfjprog --memwr 0x10001014 --val 0x3F000 -f nrf51 250 | nrfjprog --memwr 0x4001e504 --val 0x01 -f nrf51 251 | nrfjprog --memwr 0x10001080 --val 0x3A000 -f nrf51 252 | nrfjprog --reset -f nrf51 253 | 254 | erase: 255 | nrfjprog --eraseall -f nrf52 256 | 257 | 258 | $(OUTPUT_DIRECTORY)/$(TARGETS)_bootloader.c.o: version.h 259 | 260 | version.h: 261 | ./tools/build/generateVersionHeader.py --output _build/version.h 262 | -------------------------------------------------------------------------------- /config/app_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NRF_LOG_ENABLED 0 4 | #define NRF_LOG_DEFAULT_LEVEL 0 5 | 6 | #define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 7 | #define NRF_LOG_BACKEND_SERIAL_USES_UART 0 8 | 9 | #define APP_MAILBOX_ENABLED 1 10 | 11 | #define UART_CONFIG_LOG_ENABLED 0 12 | #define UART_CONFIG_LOG_LEVEL 0 13 | 14 | #define PEER_MANAGER_ENABLED 0 15 | 16 | #define GPIOTE_ENABLED 0 17 | 18 | #define BUTTON_ENABLED 0 19 | 20 | #define CRC16_ENABLED 0 21 | 22 | #define FDS_ENABLED 0 23 | 24 | #define APP_TIMER_ENABLED 1 25 | 26 | #define BLE_DIS_ENABLED 1 -------------------------------------------------------------------------------- /config/custom_board.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nrf.h" 4 | 5 | #define LEDS_NUMBER 1 6 | 7 | #define LED_START 13 8 | #define LED_1 13 9 | 10 | #define LEDS_ACTIVE_STATE 1 11 | 12 | #define LEDS_LIST { LED_1 } 13 | 14 | #define LEDS_INV_MASK 0x00000000 15 | 16 | #define BUTTONS_NUMBER 1 17 | 18 | #define BUTTON_START 17 19 | #define BUTTON_1 17 20 | #define BUTTON_PULL NRF_GPIO_PIN_PULLUP 21 | 22 | #define BUTTONS_ACTIVE_STATE 0 23 | 24 | #define BUTTONS_LIST { BUTTON_1 } 25 | 26 | #define RX_PIN_NUMBER 30 27 | #define TX_PIN_NUMBER 29 28 | #define CTS_PIN_NUMBER NRF_UART_PSEL_DISCONNECTED 29 | #define RTS_PIN_NUMBER 14 30 | #define HWFC NRF_UART_HWFC_ENABLED 31 | 32 | // #define BSP_BUTTON_0 BUTTON_1 33 | 34 | #define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_SYNTH, \ 35 | .rc_ctiv = 0, \ 36 | .rc_temp_ctiv = 0, \ 37 | .xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM} 38 | 39 | 40 | // Power management pins 41 | #define PM_CHG 0 42 | #define PM_VBAT 1 43 | #define PM_VBAT_SYNC 2 44 | #define PM_ISET 3 45 | #define PM_PGOOD 4 46 | #define PM_EN1 5 47 | #define PM_EN2 6 48 | #define PM_CHG_EN 7 49 | #define VEN_D 10 50 | 51 | #define STM_NRST_PIN 21 52 | 53 | #define RADIO_PAEN_PIN 19 54 | #define RADIO_PATX_DIS_PIN 20 55 | 56 | // Pins if RFX2411N is used 57 | #define RADIO_PA_RX_EN 20 58 | #define RADIO_PA_ANT_SW 18 59 | #define RADIO_PA_MODE 19 60 | 61 | #define HAS_TI_CHARGER 1 -------------------------------------------------------------------------------- /crazyflie2_nrf_firmware.ld: -------------------------------------------------------------------------------- 1 | /* Linker script to configure memory regions. */ 2 | 3 | SEARCH_DIR(.) 4 | GROUP(-lgcc -lc -lnosys) 5 | 6 | MEMORY 7 | { 8 | FLASH (rx) : ORIGIN = 0x0003A000, LENGTH = 0x5000 9 | RAM (rwx) : ORIGIN = 0x20001fe8, LENGTH = 0x2018 10 | } 11 | 12 | SECTIONS 13 | { 14 | .fs_data : 15 | { 16 | PROVIDE(__start_fs_data = .); 17 | KEEP(*(.fs_data)) 18 | PROVIDE(__stop_fs_data = .); 19 | } > RAM 20 | .pwr_mgmt_data : 21 | { 22 | PROVIDE(__start_pwr_mgmt_data = .); 23 | KEEP(*(.pwr_mgmt_data)) 24 | PROVIDE(__stop_pwr_mgmt_data = .); 25 | } > RAM 26 | } INSERT AFTER .data; 27 | 28 | INCLUDE "nrf5x_common.ld" 29 | -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "environmentReqs": { 4 | "build": ["arm-none-eabi"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Crazyflie 2.0 nRF51 Bootloader [![CI](https://github.com/bitcraze/crazyflie2-nrf-bootloader/workflows/CI/badge.svg)](https://github.com/bitcraze/crazyflie2-nrf-bootloader/actions?query=workflow%3ACI) 2 | 3 | 4 | Crazflie 2.0 bootloader firmware that runs in the nRF51. See readme.md in 5 | crazyflie-nrf-firmware repos for more information about flash and boot 6 | architecture. 7 | 8 | Just after clonning the repository: 9 | ``` bash 10 | ./tools/build/fetch_dependencies 11 | ``` 12 | 13 | This will download and patch the Nordic's nrf5 bootloader 14 | 15 | Working with the bootloader 16 | --------------------------- 17 | 18 | In order to work on this bootloader you must have a debug probe and your Crazyflie fited with the nRF debug port from the debug adapter kit. 19 | This is because, the bootloader is part of the safe boot sequence of the Crazyflie and so flashing a non-functional bootloader will require a debug probe to get the Crazyflie back to work. 20 | 21 | 22 | Once a stable version of the bootloader has been produced, it is possible to make an update binary that will flash both the bootloader and the bluetooth softdevice. 23 | This update binary can be flashed over radio like a normal firmware. 24 | 25 | Compiling 26 | --------- 27 | 28 | To compile you must hase arm-none-eabi- tools in the path, Python 3 and git. 29 | 30 | Flashing requires a jlink debug probe and nrfjprog. 31 | ``` bash 32 | make 33 | make flash 34 | ``` 35 | 36 | Architecture 37 | -------- 38 | 39 | Check out the readme of the [crazyflie-stm-bootloader repository](https://github.com/bitcraze/crazyflie2-stm-bootloader) to understand the interplay between the stm and nrf bootloaders. 40 | -------------------------------------------------------------------------------- /src/atomic.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2014 The Chromium OS Authors. All rights reserved. 2 | * Use of this source code is governed by a BSD-style license that can be 3 | * found in the LICENSE file. 4 | */ 5 | 6 | /* Atomic operations for ARMv6-M */ 7 | 8 | #ifndef __CROS_EC_ATOMIC_H 9 | #define __CROS_EC_ATOMIC_H 10 | 11 | typedef int atomic_t; 12 | typedef atomic_t atomic_val_t; 13 | 14 | /** 15 | * Implements atomic arithmetic operations on 32-bit integers. 16 | * 17 | * There is no load/store exclusive on ARMv6-M, just disable interrupts 18 | */ 19 | #define ATOMIC_OP(asm_op, a, v) \ 20 | ({ \ 21 | uint32_t reg0, reg1; \ 22 | \ 23 | __asm__ __volatile__(" cpsid i\n" \ 24 | " ldr %0, [%2]\n" \ 25 | " mov %1, %0\n" \ 26 | #asm_op" %0, %0, %3\n" \ 27 | " str %0, [%2]\n" \ 28 | " cpsie i\n" \ 29 | : "=&b"(reg0), "=&b"(reg1) \ 30 | : "b"(a), "r"(v) \ 31 | : "cc", "memory"); \ 32 | reg1; \ 33 | }) 34 | 35 | static inline void atomic_clear_bits(atomic_t *addr, atomic_val_t bits) 36 | { 37 | ATOMIC_OP(bic, addr, bits); 38 | } 39 | 40 | static inline atomic_val_t atomic_or(atomic_t *addr, atomic_val_t bits) 41 | { 42 | return ATOMIC_OP(orr, addr, bits); 43 | } 44 | 45 | static inline atomic_val_t atomic_add(atomic_t *addr, atomic_val_t value) 46 | { 47 | return ATOMIC_OP(add, addr, value); 48 | } 49 | 50 | static inline atomic_val_t atomic_sub(atomic_t *addr, atomic_val_t value) 51 | { 52 | return ATOMIC_OP(sub, addr, value); 53 | } 54 | 55 | static inline atomic_val_t atomic_clear(atomic_t *addr) 56 | { 57 | atomic_t ret; 58 | 59 | __asm__ __volatile__(" mov %2, #0\n" 60 | " cpsid i\n" 61 | " ldr %0, [%1]\n" 62 | " str %2, [%1]\n" 63 | " cpsie i\n" 64 | : "=&b" (ret) 65 | : "b" (addr), "r" (0) 66 | : "cc", "memory"); 67 | 68 | return ret; 69 | } 70 | 71 | #endif /* __CROS_EC_ATOMIC_H */ 72 | -------------------------------------------------------------------------------- /src/ble_crazyflie.c: -------------------------------------------------------------------------------- 1 | #include "sdk_common.h" 2 | #include "ble_crazyflie.h" 3 | 4 | #define NRF_LOG_MODULE_NAME "CRAZYFLIE_SRV" 5 | #include "nrf_log.h" 6 | 7 | #define CRAZYFLIE_BASE_UUID {{0x08, 0x9A, 0x0A, 0xC0, 0xB7, 0x43, 0x7B, 0x94, 0x9E, 0x4F, 0x7F, 0x1C, 0x00, 0x00, 0x00, 0x00}} 8 | 9 | 10 | static void on_write(ble_crazyflie_t* p_crazyflie, ble_evt_t const* p_ble_evt) { 11 | ble_gatts_evt_write_t * p_evt_write = (void*) &p_ble_evt->evt.gatts_evt.params.write; 12 | 13 | if (p_evt_write->handle == p_crazyflie->crtp_char_handles.value_handle) { 14 | p_crazyflie->data_handler(p_crazyflie, p_evt_write->data, p_evt_write->len); 15 | } else if (p_evt_write->handle == p_crazyflie->crtpup_char_handles.value_handle) { 16 | if (p_evt_write->len > 0 && ((p_evt_write->data[0] & 0x80) == 0x80)) { 17 | p_crazyflie->packet_length = p_evt_write->data[0] & 0x1F; 18 | p_crazyflie->packet_index = p_evt_write->len - 1; 19 | memcpy(p_crazyflie->packet_buffer, p_evt_write->data+1, p_evt_write->len-1); 20 | } else { 21 | memcpy(p_crazyflie->packet_buffer+p_crazyflie->packet_index, p_evt_write->data+1, p_evt_write->len-1); 22 | p_crazyflie->data_handler(p_crazyflie, p_crazyflie->packet_buffer, p_crazyflie->packet_length); 23 | } 24 | } else if (p_evt_write->handle == p_crazyflie->crtpdown_char_handles.cccd_handle) { 25 | if (p_evt_write->len == 2) { 26 | if (ble_srv_is_notification_enabled(p_evt_write->data)) { 27 | p_crazyflie->crtpdown_notification_enabled = true; 28 | } else { 29 | p_crazyflie->crtpdown_notification_enabled = false; 30 | } 31 | } 32 | } 33 | } 34 | 35 | static void on_connect(ble_crazyflie_t* p_crazyflie, ble_evt_t const* p_ble_evt) { 36 | p_crazyflie->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; 37 | sd_ble_tx_packet_count_get(p_crazyflie->conn_handle, &p_crazyflie->tx_pk_free); 38 | } 39 | 40 | static void on_disconnect(ble_crazyflie_t* p_crazyflie, ble_evt_t const* p_ble_evt) { 41 | UNUSED_PARAMETER(p_ble_evt); 42 | p_crazyflie->conn_handle = BLE_CONN_HANDLE_INVALID; 43 | } 44 | 45 | static uint32_t crtp_char_add(ble_crazyflie_t* p_crazyflie, const ble_crazyflie_init_t* p_crazyflie_init) { 46 | ble_gatts_char_md_t char_md; 47 | ble_gatts_attr_md_t cccd_md; 48 | ble_gatts_attr_t attr_char_value; 49 | ble_uuid_t ble_uuid; 50 | ble_gatts_attr_md_t attr_md; 51 | 52 | memset(&cccd_md, 0, sizeof(cccd_md)); 53 | 54 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 55 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 56 | 57 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 58 | 59 | memset(&char_md, 0, sizeof(char_md)); 60 | 61 | char_md.char_props.read = 1; 62 | char_md.char_props.notify = 1; 63 | char_md.char_props.write = 1; 64 | char_md.char_props.write_wo_resp = 1; 65 | char_md.p_char_user_desc = NULL; 66 | char_md.p_char_pf = NULL; 67 | char_md.p_user_desc_md = NULL; 68 | char_md.p_cccd_md = &cccd_md; 69 | char_md.p_sccd_md = NULL; 70 | 71 | ble_uuid.type = p_crazyflie->uuid_type; 72 | ble_uuid.uuid = 0x0202; 73 | 74 | memset(&attr_md, 0, sizeof(attr_md)); 75 | 76 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); 77 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 78 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 79 | attr_md.rd_auth = 0; 80 | attr_md.wr_auth = 0; 81 | attr_md.vlen = 1; 82 | 83 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 84 | 85 | attr_char_value.p_uuid = &ble_uuid; 86 | attr_char_value.p_attr_md = &attr_md; 87 | attr_char_value.init_len = 0; 88 | attr_char_value.init_offs = 0; 89 | attr_char_value.max_len = 20; 90 | 91 | return sd_ble_gatts_characteristic_add(p_crazyflie->service_handle, 92 | &char_md, 93 | &attr_char_value, 94 | &p_crazyflie->crtp_char_handles); 95 | 96 | } 97 | 98 | static uint32_t crtpup_char_add(ble_crazyflie_t* p_crazyflie, const ble_crazyflie_init_t* p_crazyflie_init) { 99 | ble_gatts_char_md_t char_md; 100 | ble_gatts_attr_md_t cccd_md; 101 | ble_gatts_attr_t attr_char_value; 102 | ble_uuid_t ble_uuid; 103 | ble_gatts_attr_md_t attr_md; 104 | 105 | memset(&cccd_md, 0, sizeof(cccd_md)); 106 | 107 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 108 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 109 | 110 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 111 | 112 | memset(&char_md, 0, sizeof(char_md)); 113 | 114 | char_md.char_props.write = 1; 115 | char_md.char_props.write_wo_resp = 1; 116 | char_md.p_char_user_desc = NULL; 117 | char_md.p_char_pf = NULL; 118 | char_md.p_user_desc_md = NULL; 119 | char_md.p_cccd_md = &cccd_md; 120 | char_md.p_sccd_md = NULL; 121 | 122 | ble_uuid.type = p_crazyflie->uuid_type; 123 | ble_uuid.uuid = 0x0203; 124 | 125 | memset(&attr_md, 0, sizeof(attr_md)); 126 | 127 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); 128 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 129 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 130 | attr_md.rd_auth = 0; 131 | attr_md.wr_auth = 0; 132 | attr_md.vlen = 1; 133 | 134 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 135 | 136 | attr_char_value.p_uuid = &ble_uuid; 137 | attr_char_value.p_attr_md = &attr_md; 138 | attr_char_value.init_len = 0; 139 | attr_char_value.init_offs = 0; 140 | attr_char_value.max_len = 20; 141 | 142 | return sd_ble_gatts_characteristic_add(p_crazyflie->service_handle, 143 | &char_md, 144 | &attr_char_value, 145 | &p_crazyflie->crtpup_char_handles); 146 | 147 | } 148 | 149 | uint32_t crtpdown_char_add(ble_crazyflie_t* p_crazyflie, const ble_crazyflie_init_t* p_crazyflie_init) { 150 | ble_gatts_char_md_t char_md; 151 | ble_gatts_attr_md_t cccd_md; 152 | ble_gatts_attr_t attr_char_value; 153 | ble_uuid_t ble_uuid; 154 | ble_gatts_attr_md_t attr_md; 155 | 156 | memset(&cccd_md, 0, sizeof(cccd_md)); 157 | 158 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 159 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); 160 | 161 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 162 | 163 | memset(&char_md, 0, sizeof(char_md)); 164 | 165 | char_md.char_props.notify = 1; 166 | char_md.char_props.read = 1; 167 | char_md.p_char_user_desc = NULL; 168 | char_md.p_char_pf = NULL; 169 | char_md.p_user_desc_md = NULL; 170 | char_md.p_cccd_md = &cccd_md; 171 | char_md.p_sccd_md = NULL; 172 | 173 | ble_uuid.type = p_crazyflie->uuid_type; 174 | ble_uuid.uuid = 0x0204; 175 | 176 | memset(&attr_md, 0, sizeof(attr_md)); 177 | 178 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); 179 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 180 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 181 | attr_md.rd_auth = 0; 182 | attr_md.wr_auth = 0; 183 | attr_md.vlen = 1; 184 | 185 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 186 | 187 | attr_char_value.p_uuid = &ble_uuid; 188 | attr_char_value.p_attr_md = &attr_md; 189 | attr_char_value.init_len = 0; 190 | attr_char_value.init_offs = 0; 191 | attr_char_value.max_len = 20; 192 | 193 | return sd_ble_gatts_characteristic_add(p_crazyflie->service_handle, 194 | &char_md, 195 | &attr_char_value, 196 | &p_crazyflie->crtpdown_char_handles); 197 | } 198 | 199 | uint32_t ble_crazyflie_init(ble_crazyflie_t *p_crazyflie, const ble_crazyflie_init_t *p_crazyflie_init) { 200 | uint32_t err_code; 201 | ble_uuid_t ble_uuid; 202 | ble_uuid128_t crazyflie_base_uuid = CRAZYFLIE_BASE_UUID; 203 | 204 | VERIFY_PARAM_NOT_NULL(p_crazyflie); 205 | VERIFY_PARAM_NOT_NULL(p_crazyflie_init); 206 | VERIFY_PARAM_NOT_NULL(p_crazyflie_init->data_handler); 207 | 208 | // Add Crazyflie serive UUID 209 | err_code = sd_ble_uuid_vs_add(&crazyflie_base_uuid, &p_crazyflie->uuid_type); 210 | VERIFY_SUCCESS(err_code); 211 | 212 | ble_uuid.type = p_crazyflie->uuid_type; 213 | ble_uuid.uuid = 0x0201; 214 | 215 | // Add Crazyflie service 216 | err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, 217 | &ble_uuid, 218 | &p_crazyflie->service_handle); 219 | VERIFY_SUCCESS(err_code); 220 | 221 | err_code = crtp_char_add(p_crazyflie, p_crazyflie_init); 222 | VERIFY_SUCCESS(err_code); 223 | 224 | err_code = crtpup_char_add(p_crazyflie, p_crazyflie_init); 225 | VERIFY_SUCCESS(err_code); 226 | 227 | err_code = crtpdown_char_add(p_crazyflie, p_crazyflie_init); 228 | VERIFY_SUCCESS(err_code); 229 | 230 | p_crazyflie->conn_handle = BLE_CONN_HANDLE_INVALID; 231 | p_crazyflie->data_handler = p_crazyflie_init->data_handler; 232 | p_crazyflie->crtpdown_notification_enabled = false; 233 | 234 | return NRF_SUCCESS; 235 | } 236 | 237 | void ble_crazyflie_on_ble_evt(ble_crazyflie_t *p_crazyflie, ble_evt_t const *p_ble_evt) { 238 | if (p_crazyflie == NULL || p_ble_evt == NULL) { 239 | return; 240 | } 241 | 242 | switch (p_ble_evt->header.evt_id) { 243 | case BLE_GAP_EVT_CONNECTED: 244 | on_connect(p_crazyflie, p_ble_evt); 245 | break; 246 | case BLE_GAP_EVT_DISCONNECTED: 247 | on_disconnect(p_crazyflie, p_ble_evt); 248 | break; 249 | case BLE_GATTS_EVT_WRITE: 250 | on_write(p_crazyflie, p_ble_evt); 251 | break; 252 | case BLE_EVT_TX_COMPLETE: 253 | p_crazyflie->tx_pk_free++; 254 | break; 255 | default: 256 | break; 257 | } 258 | } 259 | 260 | static uint32_t send_crtpdown_notification(ble_crazyflie_t *p_crazyflie, uint8_t *p_data, uint16_t length) { 261 | uint32_t err_code; 262 | ble_gatts_hvx_params_t hvx_params; 263 | 264 | VERIFY_PARAM_NOT_NULL(p_crazyflie); 265 | 266 | if ((p_crazyflie->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_crazyflie->crtpdown_notification_enabled)) { 267 | return NRF_ERROR_INVALID_STATE; 268 | } 269 | 270 | if (p_crazyflie->crtpdown_char_handles.value_handle == BLE_GATT_HANDLE_INVALID) { 271 | return NRF_ERROR_INVALID_STATE; 272 | } 273 | 274 | memset(&hvx_params, 0, sizeof(hvx_params)); 275 | 276 | hvx_params.handle = p_crazyflie->crtpdown_char_handles.value_handle; 277 | hvx_params.type = BLE_GATT_HVX_NOTIFICATION; 278 | hvx_params.offset = 0; 279 | hvx_params.p_len = &length; 280 | hvx_params.p_data = p_data; 281 | 282 | err_code = sd_ble_gatts_hvx(p_crazyflie->conn_handle, &hvx_params); 283 | if (err_code == NRF_SUCCESS) { 284 | NRF_LOG_INFO("Sent %d bytes\n", length); 285 | p_crazyflie->tx_pk_free--; 286 | } else { 287 | NRF_LOG_ERROR("Failed to send %d bytes: %d\n", length, err_code); 288 | } 289 | 290 | return err_code; 291 | } 292 | 293 | uint32_t ble_crazyflie_send_packet(ble_crazyflie_t *p_crazyflie, uint8_t *p_data, uint16_t length) { 294 | uint32_t err_code; 295 | uint8_t packet[32]; 296 | 297 | if (length > 31) { 298 | return NRF_ERROR_INVALID_PARAM; 299 | } 300 | 301 | NRF_LOG_DEBUG("Tx Pk free: %d\n", p_crazyflie->tx_pk_free); 302 | 303 | packet[0] = 0x80 | length; 304 | 305 | if (length > GATT_MTU_SIZE_DEFAULT - 3 - 1) { 306 | if (p_crazyflie->tx_pk_free < 2) { 307 | return NRF_ERROR_NO_MEM; 308 | } 309 | 310 | memcpy(packet+1, p_data, GATT_MTU_SIZE_DEFAULT - 3 - 1); 311 | err_code = send_crtpdown_notification(p_crazyflie, packet, GATT_MTU_SIZE_DEFAULT - 3 - 1 + 1); 312 | VERIFY_SUCCESS(err_code); 313 | packet[0] &= ~(0x80); // Clear start flag 314 | memcpy(packet+1, p_data+GATT_MTU_SIZE_DEFAULT - 3, length - (GATT_MTU_SIZE_DEFAULT - 3 - 1)); 315 | err_code = send_crtpdown_notification(p_crazyflie, packet, length - (GATT_MTU_SIZE_DEFAULT - 3 - 1) + 1); 316 | VERIFY_SUCCESS(err_code); 317 | } else { 318 | if (p_crazyflie->tx_pk_free < 1) { 319 | return NRF_ERROR_NO_MEM; 320 | } 321 | 322 | memcpy(packet+1, p_data, length); 323 | err_code = send_crtpdown_notification(p_crazyflie, packet, length+1); 324 | VERIFY_SUCCESS(err_code); 325 | } 326 | 327 | return NRF_SUCCESS; 328 | } -------------------------------------------------------------------------------- /src/ble_crazyflie.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ble.h" 4 | #include "ble_srv_common.h" 5 | #include 6 | #include 7 | 8 | #define BLE_CRAZYFLIE_SERVICE_UUID "00000201-1C7F-4F9E-947B-43B7C00A9A08" 9 | 10 | typedef struct ble_crazyflie_s ble_crazyflie_t; 11 | typedef void (*ble_crazyflie_data_handler_t)(ble_crazyflie_t *p_crazyflie, uint8_t *p_data, uint16_t length); 12 | 13 | struct ble_crazyflie_s { 14 | uint8_t uuid_type; 15 | uint16_t service_handle; 16 | uint16_t conn_handle; 17 | ble_gatts_char_handles_t crtp_char_handles; 18 | ble_gatts_char_handles_t crtpup_char_handles; 19 | ble_gatts_char_handles_t crtpdown_char_handles; 20 | bool crtpdown_notification_enabled; 21 | uint8_t packet_buffer[32]; 22 | uint8_t packet_length; 23 | uint8_t packet_index; 24 | ble_crazyflie_data_handler_t data_handler; 25 | 26 | uint8_t tx_pk_free; 27 | }; 28 | 29 | typedef struct { 30 | ble_crazyflie_data_handler_t data_handler; 31 | } ble_crazyflie_init_t; 32 | 33 | uint32_t ble_crazyflie_init(ble_crazyflie_t *p_crazyflie, const ble_crazyflie_init_t *p_crazyflie_init); 34 | 35 | void ble_crazyflie_on_ble_evt(ble_crazyflie_t *p_crazyflie, ble_evt_t const *p_ble_evt); 36 | 37 | uint32_t ble_crazyflie_send_packet(ble_crazyflie_t *p_crazyflie, uint8_t *p_data, uint16_t length); -------------------------------------------------------------------------------- /src/bootloader.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * Implementation of nRF51 CRTP Bootloader 25 | */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "crtp.h" 32 | #include "bootloader.h" 33 | #include "crc.h" 34 | #include "systick.h" 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include "version.h" 41 | 42 | 43 | static char buffer[PAGE_SIZE*BUFFER_PAGES] = {0x42}; 44 | 45 | static enum {bootloaderIdle, 46 | bootloaderErasing, 47 | bootloaderFlashing, 48 | bootloaderFlashOk, 49 | bootloaderFlashFail} bootloaderState = bootloaderIdle; 50 | static int currentFlashPage; 51 | static int currentBufferPage; 52 | static int flashError; 53 | static WriteFlashParameters_t flashParams = {0}; 54 | 55 | 56 | static int verifyCopyFlashFlags() { 57 | CopyFlashFlags_t *flashFlags = (void*)FLASH_BASE+((FLASH_PAGES-1)*PAGE_SIZE); 58 | int error = 0; 59 | uint32_t crc = crcSlow(flashFlags, sizeof(CopyFlashFlags_t)-4); 60 | 61 | // Check that the structure has a good checksum 62 | if ( (flashFlags->header != 0xcf) || (crc != flashFlags->crc32) ) { 63 | error = 1; 64 | goto end; 65 | } 66 | 67 | // Check memory boundaries 68 | if (flashFlags->sdLength != 0) { 69 | if ( (((flashFlags->sdDestPage*PAGE_SIZE)+flashFlags->sdLength) > (FLASH_SIZE-MBS_SIZE)) || 70 | ((flashFlags->sdDestPage*PAGE_SIZE) < MBR_SIZE) ) { 71 | error = 2; 72 | goto end; 73 | } 74 | } 75 | if (flashFlags->blLength != 0) { 76 | if ( (((flashFlags->blDestPage*PAGE_SIZE)+flashFlags->blLength) > (FLASH_SIZE-MBS_SIZE)) || 77 | ((flashFlags->blDestPage*PAGE_SIZE) < MBR_SIZE) ) { 78 | error = 3; 79 | goto end; 80 | } 81 | } 82 | 83 | // Check images checksum 84 | if (flashFlags->sdLength != 0) { 85 | crc = crcSlow((void*)(FLASH_BASE+(flashFlags->sdSrcPage*PAGE_SIZE)), flashFlags->sdLength); 86 | if (crc != flashFlags->sdCrc32) { 87 | error = 4; 88 | goto end; 89 | } 90 | } 91 | if (flashFlags->blLength != 0) { 92 | crc = crcSlow((void*)(FLASH_BASE+(flashFlags->blSrcPage*PAGE_SIZE)), flashFlags->blLength); 93 | if (crc != flashFlags->blCrc32) { 94 | error = 5; 95 | goto end; 96 | } 97 | } 98 | 99 | end: 100 | return error; 101 | } 102 | 103 | 104 | // Pass a packet. 105 | // Return true and replaces the packet content if has data to communicate back 106 | bool bootloaderProcess(CrtpPacket *packet) { 107 | bool tx = false; 108 | 109 | if ((packet->datalen != 0xFFU) && 110 | (packet->datalen >= 2) && 111 | (packet->header == 0xFF) && 112 | (packet->data[0] == 0xFE)) { 113 | 114 | if (packet->data[1] == CMD_GET_INFO) { 115 | GetInfoReturns_t * info = (GetInfoReturns_t *)&packet->data[2]; 116 | 117 | info->pageSize = PAGE_SIZE; 118 | info->nBuffPages = BUFFER_PAGES; 119 | info->nFlashPages = FLASH_PAGES; 120 | info->flashStart = FLASH_START; 121 | //memcpy(info->cpuId, cpuidGetId(), CPUID_LEN); 122 | bzero(info->cpuId, CPUID_LEN); 123 | info->version = PROTOCOL_VERSION; 124 | info->version_major = VERSION_MAJOR | ((VERSION_DIRTY)?0x8000U:0x000); 125 | info->version_minor = VERSION_MINOR; 126 | info->version_patch = VERSION_PATCH; 127 | 128 | packet->datalen = 2+sizeof(GetInfoReturns_t); 129 | 130 | tx = true; 131 | } 132 | /* else if (packet->data[1] == CMD_SET_ADDRESS) 133 | { 134 | SetAddressParameters_t * addressPk; 135 | addressPk = (SetAddressParameters_t *)&packet.data[1]; 136 | 137 | esbSetAddress(addressPk->address); 138 | }*/ 139 | else if (packet->data[1] == CMD_LOAD_BUFFER) { 140 | int i = 0; 141 | LoadBufferParameters_t *params = (LoadBufferParameters_t *)&packet->data[2]; 142 | char *data = (char*)&packet->data[2 + sizeof(LoadBufferParameters_t)]; 143 | 144 | //Fill the buffer with the given datas 145 | for (i = 0; i < (packet->datalen - (2 + sizeof(LoadBufferParameters_t))) 146 | && (i + (params->page * PAGE_SIZE) + params->address) < (BUFFER_PAGES * PAGE_SIZE); i++) 147 | buffer[(i+(params->page*PAGE_SIZE)+params->address)] = data[i]; 148 | 149 | } 150 | else if (packet->data[1] == CMD_READ_BUFFER) { 151 | int i = 0; 152 | ReadBufferParameters_t *params = (ReadBufferParameters_t *)&packet->data[2]; 153 | char *data = (char*)&packet->data[2 + sizeof(ReadBufferParameters_t)]; 154 | 155 | //Return the datas required 156 | for (i = 0; i < 25 && (i + (params->page * PAGE_SIZE) + params->address) < (BUFFER_PAGES*PAGE_SIZE); i++) 157 | data[i] = buffer[(i + (params->page * PAGE_SIZE) + params->address)]; 158 | 159 | packet->datalen += i; 160 | 161 | tx = true; 162 | } else if (packet->data[1] == CMD_READ_FLASH) { 163 | int i = 0; 164 | ReadFlashParameters_t *params = (ReadFlashParameters_t *)&packet->data[2]; 165 | char *data = (char*)&packet->data[2 + sizeof(ReadFlashParameters_t)]; 166 | char *flash = (char*)FLASH_BASE; 167 | 168 | //Return the datas required 169 | for (i = 0; i < 25 && (i + (params->page * PAGE_SIZE) + params->address) < (FLASH_PAGES * PAGE_SIZE); i++) { 170 | //data[i] = flash[(i+(params->page*PAGE_SIZE)+params->address)]; 171 | //data[i] = *((char*)(FLASH_BASE+i+(params->page*PAGE_SIZE)+params->address)); 172 | data[i] = flash[(i + (params->page * PAGE_SIZE) + params->address)]; 173 | } 174 | 175 | packet->datalen += i; 176 | 177 | tx = true; 178 | } else if (packet->data[1] == CMD_WRITE_FLASH) { 179 | //int i; 180 | unsigned int error = 0xFF; 181 | //int flashAddress; 182 | //uint32_t *bufferToFlash; 183 | WriteFlashParameters_t *params = (WriteFlashParameters_t *)&packet->data[2]; 184 | WriteFlashReturns_t *returns = (WriteFlashReturns_t *)&packet->data[2]; 185 | 186 | if (bootloaderState != bootloaderIdle) 187 | goto finally; 188 | 189 | //Test if it is an acceptable write request 190 | if ((params->flashPageflashPage >= FLASH_PAGES) || 191 | ((params->flashPage + params->nPages) > FLASH_PAGES) || (params->bufferPage >= BUFFER_PAGES) 192 | ) { 193 | //Return a failure answer 194 | returns->done = 0; 195 | returns->error = 1; 196 | packet->datalen = 2+sizeof(WriteFlashReturns_t); 197 | tx = 1; 198 | } 199 | // Else, if everything is OK, flash the page(s) 200 | else { 201 | 202 | flashParams = *params; 203 | currentFlashPage = flashParams.flashPage; 204 | currentBufferPage = flashParams.bufferPage; 205 | bootloaderState = bootloaderErasing; 206 | 207 | // Start the flashing process. The rest is handled by the event handler state machine 208 | if (sd_flash_page_erase(currentFlashPage) != NRF_SUCCESS) { 209 | error = 1; 210 | goto failure; 211 | } 212 | 213 | goto finally; 214 | 215 | failure: 216 | //If the write procedure failed, send the error packet 217 | //TODO: see if it is necessary or wanted to send the reason as well 218 | returns->done = 0; 219 | returns->error = error; 220 | packet->datalen = 2+sizeof(WriteFlashReturns_t); 221 | tx = true; 222 | 223 | finally: 224 | ; //None... 225 | } 226 | } else if (packet->data[1] == CMD_RESET_INIT) { 227 | packet->raw[0] = 0xff; 228 | packet->raw[1] = 0xfe; 229 | packet->raw[2] = CMD_RESET_INIT; 230 | 231 | memcpy(&(packet->raw[3]), (uint32_t*)NRF_FICR->DEVICEADDR, 6); 232 | 233 | packet->datalen = 8; 234 | 235 | tx = true; 236 | } else if (packet->data[1] == CMD_RESET) { 237 | int start = systickGetTick(); 238 | while ((systickGetTick()-start) < 100); 239 | if ((packet->datalen >= 3) && (packet->data[2] == 0)) { 240 | //Set bit 0x40 forces boot to bootloader 241 | NRF_POWER->GPREGRET |= 0x40U; 242 | } else { 243 | //Set bit 0x20 forces boot to firmware 244 | NRF_POWER->GPREGRET |= 0x20U; 245 | } 246 | NVIC_SystemReset(); 247 | } else if (packet->data[1] == CMD_COPY_FLASH_INIT) { 248 | CopyFlashReturns_t *returns = (void*)&packet->data[2]; 249 | 250 | returns->error = verifyCopyFlashFlags(); 251 | returns->willdo = (returns->error) ? 0 : 1; 252 | packet->datalen = 2 + sizeof(CopyFlashReturns_t); 253 | tx = true; 254 | } 255 | } 256 | 257 | /* Flashing asynchronous work, make sure to run them when they can return 258 | * data to send back 259 | */ 260 | if ((tx == false) && (packet->datalen != 0xFFU)) { 261 | WriteFlashReturns_t *returns = (WriteFlashReturns_t *)&packet->data[2]; 262 | switch (bootloaderState) { 263 | case bootloaderFlashOk: 264 | packet->data[1] = CMD_WRITE_FLASH; 265 | returns->done = 1; 266 | returns->error = 0; 267 | packet->datalen = 2+sizeof(WriteFlashReturns_t); 268 | tx = true; 269 | 270 | bootloaderState = bootloaderIdle; 271 | break; 272 | case bootloaderFlashFail: 273 | packet->data[1] = CMD_WRITE_FLASH; 274 | returns->done = 0; 275 | returns->error = flashError; 276 | packet->datalen = 2 + sizeof(WriteFlashReturns_t); 277 | tx = true; 278 | 279 | bootloaderState = bootloaderIdle; 280 | break; 281 | default: 282 | break; 283 | } 284 | } 285 | 286 | return tx; 287 | } 288 | 289 | void bootloaderOnSdEvt(uint32_t evt) { 290 | int err; 291 | 292 | if (evt == NRF_EVT_FLASH_OPERATION_SUCCESS) { 293 | switch (bootloaderState) { 294 | case bootloaderErasing: 295 | currentFlashPage += 1; 296 | if (currentFlashPage < (flashParams.flashPage + flashParams.nPages)) { 297 | // Erase next page 298 | if (sd_flash_page_erase(currentFlashPage) != NRF_SUCCESS) { 299 | flashError = 2; 300 | bootloaderState = bootloaderFlashFail; 301 | } 302 | } else { 303 | // Start flashing 304 | currentFlashPage = flashParams.flashPage; 305 | currentBufferPage = flashParams.bufferPage; 306 | bootloaderState = bootloaderFlashing; 307 | 308 | err = sd_flash_write((uint32_t *)(FLASH_BASE + (currentFlashPage * PAGE_SIZE)), 309 | (uint32_t const *)((uint32_t)buffer) + (currentBufferPage * PAGE_SIZE), 310 | 256); 311 | if (err != NRF_SUCCESS) { 312 | flashError = 3; 313 | bootloaderState = bootloaderFlashFail; 314 | } 315 | } 316 | break; 317 | case bootloaderFlashing: 318 | currentFlashPage += 1; 319 | currentBufferPage += 1; 320 | 321 | if (currentFlashPage < (flashParams.flashPage + flashParams.nPages)) { 322 | err = sd_flash_write((uint32_t *)(FLASH_BASE + (currentFlashPage * PAGE_SIZE)), 323 | (uint32_t const *)((uint32_t)buffer) + (currentBufferPage * PAGE_SIZE), 324 | 256); 325 | if (err != NRF_SUCCESS) { 326 | flashError = 3; 327 | bootloaderState = bootloaderFlashFail; 328 | } 329 | } else { 330 | bootloaderState = bootloaderFlashOk; 331 | } 332 | break; 333 | default: 334 | break; 335 | } 336 | } else if (evt == NRF_EVT_FLASH_OPERATION_ERROR) { 337 | switch (bootloaderState) { 338 | case bootloaderErasing: 339 | // Start the flashing process. The rest is handled by the event handler state machine 340 | if (sd_flash_page_erase(currentFlashPage) != NRF_SUCCESS) { 341 | flashError = 2; 342 | bootloaderState = bootloaderFlashFail; 343 | } 344 | break; 345 | case bootloaderFlashing: 346 | err = sd_flash_write((uint32_t *)(FLASH_BASE + (currentFlashPage * PAGE_SIZE)), 347 | (uint32_t const *)((uint32_t)buffer) + (currentBufferPage * PAGE_SIZE), 348 | 256); 349 | if (err != NRF_SUCCESS) { 350 | flashError = 3; 351 | bootloaderState = bootloaderFlashFail; 352 | } 353 | break; 354 | default: 355 | break; 356 | } 357 | } 358 | } 359 | 360 | -------------------------------------------------------------------------------- /src/bootloader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __BOOTLOADER_H__ 25 | #define __BOOTLOADER_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "crtp.h" 31 | #include 32 | 33 | #define BUFFER_PAGES 1 34 | #define FLASH_PAGES 232 35 | #define FLASH_START 108 36 | 37 | #define PAGE_SIZE 1024 38 | 39 | #define FLASH_BASE 0x00000000 40 | #define FLASH_SIZE (256*1024) 41 | 42 | #define MBS_SIZE (4*1024) 43 | 44 | //Public functions 45 | bool bootloaderProcess(CrtpPacket *packet); 46 | void bootloaderOnSdEvt(uint32_t evt); 47 | 48 | /* XXX: Protocol version has to be increased each time a command is 49 | * added or modified! 50 | */ 51 | #define PROTOCOL_VERSION 0x10 52 | 53 | #define CPUID_LEN 12 54 | 55 | /******* Reset (to fw) ******/ 56 | #define CMD_RESET_INIT 0xFF 57 | #define CMD_RESET 0xF0 58 | 59 | /******* GetInfo ******/ 60 | #define CMD_GET_INFO 0x10 61 | //Parameters ... void 62 | //Returns: 63 | typedef struct { 64 | short pageSize; 65 | short nBuffPages; 66 | short nFlashPages; 67 | short flashStart; 68 | char cpuId[CPUID_LEN]; 69 | char version; 70 | uint16_t version_major; 71 | uint8_t version_minor; 72 | uint8_t version_patch; 73 | } __attribute__((__packed__)) GetInfoReturns_t; 74 | 75 | /****** SetAddress ****/ 76 | #define CMD_SET_ADDRESS 0x11 77 | //Parameters: 78 | typedef struct { 79 | char address[5]; 80 | } __attribute__((__packed__)) SetAddressParameters_t; 81 | //Returns ... void 82 | 83 | /****** LoadBuffer ****/ 84 | #define CMD_LOAD_BUFFER 0x14 85 | //Parameters: 86 | typedef struct { 87 | unsigned short page; 88 | unsigned short address; 89 | } __attribute__((__packed__)) LoadBufferParameters_t; 90 | //Returns ... void 91 | 92 | /****** ReadBuffer ****/ 93 | #define CMD_READ_BUFFER 0x15 94 | //Parameters: 95 | typedef struct { 96 | unsigned short page; 97 | unsigned short address; 98 | } __attribute__((__packed__)) ReadBufferParameters_t; 99 | //Returns ... Same as parameters but with data 100 | 101 | /****** CopyFlash init ****/ 102 | #define CMD_COPY_FLASH_INIT 0x16 103 | //Parameters ... void 104 | //Returns: 105 | typedef struct { 106 | char willdo; 107 | unsigned char error; 108 | } __attribute__((__packed__)) CopyFlashReturns_t; 109 | 110 | /****** CopyFlash ****/ 111 | #define CMD_COPY_FLASH 0x17 112 | //Parameters ... void 113 | //Returns ... Resets just after the command 114 | 115 | /****** WriteFlash ****/ 116 | #define CMD_WRITE_FLASH 0x18 117 | //Parameters: 118 | typedef struct { 119 | unsigned short bufferPage; 120 | unsigned short flashPage; 121 | unsigned short nPages; 122 | } __attribute__((__packed__)) WriteFlashParameters_t; 123 | //Returns ... Same as parameters but with data 124 | typedef struct { 125 | char done; 126 | unsigned char error; 127 | } __attribute__((__packed__)) WriteFlashReturns_t; 128 | 129 | #define CMD_FLASH_STATUS 0x19 130 | //Parameters ... void 131 | //Returns: 132 | typedef struct { 133 | unsigned char done; 134 | unsigned char error; 135 | } __attribute__((__packed__)) FlashStatusReturns_t; 136 | 137 | /****** ReadBuffer ****/ 138 | #define CMD_READ_FLASH 0x1C 139 | //Parameters: 140 | typedef struct { 141 | unsigned short page; 142 | unsigned short address; 143 | } __attribute__((__packed__)) ReadFlashParameters_t; 144 | //Returns ... Same as parameters but with data 145 | 146 | 147 | /************** Flag page for copy-flash operation *********/ 148 | //This structure shall be written in the flash page just before the bootloader 149 | //It will be erased by the MBS when the flash operation is completed 150 | typedef struct { 151 | uint8_t header; //Should be 0xCF 152 | 153 | uint16_t sdSrcPage; 154 | uint16_t sdDestPage; 155 | uint32_t sdLength; 156 | uint32_t sdCrc32; 157 | 158 | uint16_t blSrcPage; 159 | uint16_t blDestPage; 160 | uint32_t blLength; 161 | uint32_t blCrc32; 162 | 163 | uint32_t crc32; //CRC32 of the complete structure except crc32 164 | } __attribute__((__packed__)) CopyFlashFlags_t; 165 | 166 | 167 | #endif //__BOOTLOADER_H__ 168 | -------------------------------------------------------------------------------- /src/button.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | 30 | #include 31 | #include "sdk_common.h" 32 | #include "nrf_nvic.h" 33 | #include "boards.h" 34 | #include "button.h" 35 | #include "systick.h" 36 | 37 | #include "custom_board.h" 38 | 39 | #define BUTTON_READ() ((NRF_GPIO->IN >> BUTTON_1) & 1UL) 40 | #define BUTTON_PRESSED 0UL 41 | #define BUTTON_RELEASED 1UL 42 | #define BUTTON_DEBOUNCE_TICK 1 43 | #define BUTTON_LONGPRESS_TICK 300 44 | 45 | static ButtonEvent state; 46 | 47 | void buttonInit(ButtonEvent initialEvent) { 48 | nrf_gpio_cfg_input(BUTTON_1, NRF_GPIO_PIN_PULLUP); 49 | NRF_GPIO->PIN_CNF[BUTTON_1] |= (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos); 50 | 51 | state = initialEvent; 52 | } 53 | 54 | void buttonProcess() { 55 | static unsigned int lastTick; 56 | static unsigned int pressedTick; 57 | static bool pressed; 58 | 59 | if (lastTick != systickGetTick()) { 60 | lastTick = systickGetTick(); 61 | 62 | if (pressed==false && BUTTON_READ() == BUTTON_PRESSED) { 63 | pressed = true; 64 | pressedTick = systickGetTick(); 65 | } else if (pressed==true && BUTTON_READ() == BUTTON_RELEASED) { 66 | pressed = false; 67 | if (((systickGetTick() - pressedTick) < BUTTON_LONGPRESS_TICK) && 68 | ((systickGetTick() - pressedTick) > BUTTON_DEBOUNCE_TICK) ) { 69 | state = buttonShortPress; 70 | } else { 71 | state = buttonLongPress; 72 | } 73 | } 74 | } 75 | } 76 | 77 | ButtonEvent buttonGetState() { 78 | ButtonEvent currentState = state; 79 | state = buttonIdle; 80 | 81 | return currentState; 82 | } 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/button.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __BUTTON_H__ 25 | #define __BUTTON_H__ 26 | 27 | //#include "pinout.h" 28 | #include "boards.h" 29 | #include 30 | 31 | typedef enum { 32 | buttonIdle = 0, 33 | buttonShortPress, 34 | buttonLongPress 35 | } ButtonEvent; 36 | 37 | void buttonInit(ButtonEvent initialEvent); 38 | 39 | void buttonProcess(); 40 | 41 | ButtonEvent buttonGetState(); 42 | 43 | #endif //__BUTTON_H__ 44 | -------------------------------------------------------------------------------- /src/crazyflie2_pm.c: -------------------------------------------------------------------------------- 1 | #include "crazyflie2_pm.h" 2 | 3 | #include "nrf.h" 4 | #include "nrf_gpio.h" 5 | #include "boards.h" 6 | #include "platform.h" 7 | 8 | static pm_state_t m_state = PM_STATE_OFF; 9 | 10 | void crazyflie2_pm_init(void) { 11 | // Initialize GPIO pins 12 | nrf_gpio_cfg(PM_CHG, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 13 | nrf_gpio_cfg(PM_VBAT, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 14 | nrf_gpio_cfg(PM_VBAT_SYNC, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 15 | nrf_gpio_cfg(PM_ISET, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 16 | nrf_gpio_cfg(PM_PGOOD, NRF_GPIO_PIN_DIR_INPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 17 | nrf_gpio_cfg(PM_EN1, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 18 | nrf_gpio_cfg(PM_EN2, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 19 | nrf_gpio_cfg(PM_CHG_EN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 20 | nrf_gpio_cfg(VEN_D, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE); 21 | 22 | // Set default charge state 23 | nrf_gpio_pin_clear(PM_EN1); 24 | nrf_gpio_pin_clear(PM_EN2); 25 | nrf_gpio_pin_clear(PM_CHG_EN); 26 | 27 | // Setup battery and charge current measurement 28 | nrf_gpio_pin_clear(PM_VBAT_SYNC); 29 | // todo: setup analog measurement 30 | 31 | // Setup radio PA 32 | if (platformHasRfx2411n()) { 33 | // Enable RF power amplifier 34 | nrf_gpio_cfg_output(RADIO_PA_RX_EN); 35 | nrf_gpio_cfg_output(RADIO_PA_MODE); 36 | nrf_gpio_cfg_output(RADIO_PA_ANT_SW); 37 | #ifdef USE_EXT_ANTENNA 38 | // Select u.FL antenna 39 | nrf_gpio_pin_clear(RADIO_PA_ANT_SW); 40 | #else 41 | // Select chip antenna 42 | nrf_gpio_pin_set(RADIO_PA_ANT_SW); 43 | #endif 44 | 45 | #ifdef RFX2411N_BYPASS_MODE 46 | nrf_gpio_pin_set(RADIO_PA_MODE); 47 | #else 48 | nrf_gpio_pin_set(RADIO_PA_RX_EN); 49 | nrf_gpio_pin_clear(RADIO_PA_MODE); 50 | #endif 51 | } else { 52 | // Enable RF power amplifier 53 | nrf_gpio_cfg_output(RADIO_PAEN_PIN); 54 | 55 | #ifdef DISABLE_PA 56 | nrf_gpio_pin_clear(RADIO_PAEN_PIN); 57 | nrf_gpio_cfg_output(RADIO_PATX_DIS_PIN); 58 | nrf_gpio_pin_clear(RADIO_PATX_DIS_PIN); 59 | #else 60 | nrf_gpio_pin_set(RADIO_PAEN_PIN); 61 | #endif 62 | } 63 | 64 | crazyflie2_pm_set_state(PM_STATE_SYSTEM_OFF); 65 | } 66 | 67 | pm_state_t crazyflie2_pm_get_state(void) { 68 | return m_state; 69 | } 70 | 71 | void crazyflie2_pm_set_state(pm_state_t state) { 72 | m_state = state; 73 | 74 | switch (state) { 75 | case PM_STATE_OFF: 76 | nrf_gpio_pin_clear(VEN_D); 77 | // Todo: switch OFF nRF51 enabling wakeup by button 78 | break; 79 | case PM_STATE_SYSTEM_OFF: 80 | nrf_gpio_pin_clear(VEN_D); 81 | break; 82 | case PM_STATE_SYSTEM_ON: 83 | nrf_gpio_pin_set(VEN_D); 84 | break; 85 | } 86 | // Todo: set GPIOs for requested state 87 | } -------------------------------------------------------------------------------- /src/crazyflie2_pm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum { 4 | PM_STATE_OFF, 5 | PM_STATE_SYSTEM_OFF, 6 | PM_STATE_SYSTEM_ON, 7 | } pm_state_t; 8 | 9 | /** 10 | * Initialize the power management module. 11 | */ 12 | void crazyflie2_pm_init(void); 13 | 14 | /** 15 | * Get the current power management state. 16 | */ 17 | pm_state_t crazyflie2_pm_get_state(void); 18 | 19 | /** 20 | * Set the current power management state. 21 | */ 22 | void crazyflie2_pm_set_state(pm_state_t state); 23 | -------------------------------------------------------------------------------- /src/crc.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * 3 | * Filename: crc.c 4 | * 5 | * Description: Slow and fast implementations of the CRC standards. 6 | * 7 | * Notes: The parameters for each supported CRC standard are 8 | * defined in the header file crc.h. The implementations 9 | * here should stand up to further additions to that list. 10 | * 11 | * Modified by Bitcraze: made static local variables and 12 | * used stdint.h types where relevant. 13 | * 14 | * Copyright (c) 2012 Bitcraze AB 15 | * Copyright (c) 2000 by Michael Barr. This software is placed into 16 | * the public domain and may be used for any purpose. However, this 17 | * notice must not be changed or removed and no warranty is either 18 | * expressed or implied by its publication or distribution. 19 | **********************************************************************/ 20 | 21 | #include "crc.h" 22 | 23 | 24 | /* 25 | * Derive parameters from the standard-specific parameters in crc.h. 26 | */ 27 | #define WIDTH (8 * sizeof(crc)) 28 | #define TOPBIT (1 << (WIDTH - 1)) 29 | 30 | #if (REFLECT_DATA == TRUE) 31 | #undef REFLECT_DATA 32 | #define REFLECT_DATA(X) ((unsigned char) reflect((X), 8)) 33 | #else 34 | #undef REFLECT_DATA 35 | #define REFLECT_DATA(X) (X) 36 | #endif 37 | 38 | #if (REFLECT_REMAINDER == TRUE) 39 | #undef REFLECT_REMAINDER 40 | #define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH)) 41 | #else 42 | #undef REFLECT_REMAINDER 43 | #define REFLECT_REMAINDER(X) (X) 44 | #endif 45 | 46 | 47 | /********************************************************************* 48 | * 49 | * Function: reflect() 50 | * 51 | * Description: Reorder the bits of a binary sequence, by reflecting 52 | * them about the middle position. 53 | * 54 | * Notes: No checking is done that nBits <= 32. 55 | * 56 | * Returns: The reflection of the original data. 57 | * 58 | *********************************************************************/ 59 | static unsigned long 60 | reflect(unsigned long data, unsigned char nBits) 61 | { 62 | unsigned long reflection = 0x00000000; 63 | unsigned char bit; 64 | 65 | /* 66 | * Reflect the data about the center bit. 67 | */ 68 | for (bit = 0; bit < nBits; ++bit) 69 | { 70 | /* 71 | * If the LSB bit is set, set the reflection of it. 72 | */ 73 | if (data & 0x01) 74 | { 75 | reflection |= (1 << ((nBits - 1) - bit)); 76 | } 77 | 78 | data = (data >> 1); 79 | } 80 | 81 | return (reflection); 82 | 83 | } /* reflect() */ 84 | 85 | 86 | /********************************************************************* 87 | * 88 | * Function: crcSlow() 89 | * 90 | * Description: Compute the CRC of a given message. 91 | * 92 | * Notes: 93 | * 94 | * Returns: The CRC of the message. 95 | * 96 | *********************************************************************/ 97 | crc 98 | crcSlow(void * datas, int nBytes) 99 | { 100 | crc remainder = INITIAL_REMAINDER; 101 | unsigned char * message = datas; 102 | int byte; 103 | unsigned char bit; 104 | 105 | 106 | /* 107 | * Perform modulo-2 division, a byte at a time. 108 | */ 109 | for (byte = 0; byte < nBytes; ++byte) 110 | { 111 | /* 112 | * Bring the next byte into the remainder. 113 | */ 114 | remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8)); 115 | 116 | /* 117 | * Perform modulo-2 division, a bit at a time. 118 | */ 119 | for (bit = 8; bit > 0; --bit) 120 | { 121 | /* 122 | * Try to divide the current data bit. 123 | */ 124 | if (remainder & TOPBIT) 125 | { 126 | remainder = (remainder << 1) ^ POLYNOMIAL; 127 | } 128 | else 129 | { 130 | remainder = (remainder << 1); 131 | } 132 | } 133 | } 134 | 135 | /* 136 | * The final remainder is the CRC result. 137 | */ 138 | return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); 139 | 140 | } /* crcSlow() */ 141 | 142 | 143 | #if 0 144 | 145 | static crc crcTable[256]; 146 | 147 | 148 | /********************************************************************* 149 | * 150 | * Function: crcInit() 151 | * 152 | * Description: Populate the partial CRC lookup table. 153 | * 154 | * Notes: This function must be rerun any time the CRC standard 155 | * is changed. If desired, it can be run "offline" and 156 | * the table results stored in an embedded system's ROM. 157 | * 158 | * Returns: None defined. 159 | * 160 | *********************************************************************/ 161 | void 162 | crcInit(void) 163 | { 164 | crc remainder; 165 | int dividend; 166 | unsigned char bit; 167 | 168 | 169 | /* 170 | * Compute the remainder of each possible dividend. 171 | */ 172 | for (dividend = 0; dividend < 256; ++dividend) 173 | { 174 | /* 175 | * Start with the dividend followed by zeros. 176 | */ 177 | remainder = dividend << (WIDTH - 8); 178 | 179 | /* 180 | * Perform modulo-2 division, a bit at a time. 181 | */ 182 | for (bit = 8; bit > 0; --bit) 183 | { 184 | /* 185 | * Try to divide the current data bit. 186 | */ 187 | if (remainder & TOPBIT) 188 | { 189 | remainder = (remainder << 1) ^ POLYNOMIAL; 190 | } 191 | else 192 | { 193 | remainder = (remainder << 1); 194 | } 195 | } 196 | 197 | /* 198 | * Store the result into the table. 199 | */ 200 | crcTable[dividend] = remainder; 201 | } 202 | 203 | } /* crcInit() */ 204 | 205 | 206 | /********************************************************************* 207 | * 208 | * Function: crcFast() 209 | * 210 | * Description: Compute the CRC of a given message. 211 | * 212 | * Notes: crcInit() must be called first. 213 | * 214 | * Returns: The CRC of the message. 215 | * 216 | *********************************************************************/ 217 | crc 218 | crcFast(void * datas, int nBytes) 219 | { 220 | crc remainder = INITIAL_REMAINDER; 221 | unsigned char * message = datas; 222 | unsigned char data; 223 | int byte; 224 | 225 | 226 | /* 227 | * Divide the message by the polynomial, a byte at a time. 228 | */ 229 | for (byte = 0; byte < nBytes; ++byte) 230 | { 231 | data = REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8)); 232 | remainder = crcTable[data] ^ (remainder << 8); 233 | } 234 | 235 | /* 236 | * The final remainder is the CRC. 237 | */ 238 | return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); 239 | 240 | } /* crcFast() */ 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /src/crc.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * 3 | * Filename: crc.h 4 | * 5 | * Description: A header file describing the various CRC standards. 6 | * 7 | * Notes: See crc.c 8 | * 9 | * 10 | * Copyright (c) 2012 Bitcraze AB 11 | * Copyright (c) 2000 by Michael Barr. This software is placed into 12 | * the public domain and may be used for any purpose. However, this 13 | * notice must not be changed or removed and no warranty is either 14 | * expressed or implied by its publication or distribution. 15 | **********************************************************************/ 16 | /** 17 | * @file 18 | * Efficient implementation of various CRC standards. 19 | * 20 | * Two CRC calculation function are implemented: flow and fast. The slow version 21 | * is espcially inefficient but virtually use no RAM at all. The fast function 22 | * is more efficient cpu-wise but require from 512 to 1KiB of RAM located lookup 23 | * table (might be possible to move the table into FLASH, but then it would take 24 | * 1K of flash ...). 25 | * 26 | * crcInit() shall be used *only* if the fast version of CRC is used. 27 | * 28 | * The CRC algorythm to use is choosen in crc.h. 29 | */ 30 | 31 | #ifndef _crc_h 32 | #define _crc_h 33 | 34 | #include 35 | 36 | #define FALSE 0 37 | #define TRUE !FALSE 38 | 39 | /** 40 | * Select the CRC standard from the list that follows. 41 | */ 42 | #define CRC32 43 | 44 | 45 | #if defined(CRC_CCITT) 46 | 47 | typedef uint16_t crc; 48 | 49 | #define CRC_NAME "CRC-CCITT" 50 | #define POLYNOMIAL 0x1021 51 | #define INITIAL_REMAINDER 0xFFFF 52 | #define FINAL_XOR_VALUE 0x0000 53 | #define REFLECT_DATA FALSE 54 | #define REFLECT_REMAINDER FALSE 55 | #define CHECK_VALUE 0x29B1 56 | 57 | #elif defined(CRC16) 58 | 59 | typedef uint16_t crc; 60 | 61 | #define CRC_NAME "CRC-16" 62 | #define POLYNOMIAL 0x8005 63 | #define INITIAL_REMAINDER 0x0000 64 | #define FINAL_XOR_VALUE 0x0000 65 | #define REFLECT_DATA TRUE 66 | #define REFLECT_REMAINDER TRUE 67 | #define CHECK_VALUE 0xBB3D 68 | 69 | #elif defined(CRC32) 70 | 71 | typedef uint32_t crc; 72 | 73 | #define CRC_NAME "CRC-32" 74 | #define POLYNOMIAL 0x04C11DB7 75 | #define INITIAL_REMAINDER 0xFFFFFFFF 76 | #define FINAL_XOR_VALUE 0xFFFFFFFF 77 | #define REFLECT_DATA TRUE 78 | #define REFLECT_REMAINDER TRUE 79 | #define CHECK_VALUE 0xCBF43926 80 | 81 | #else 82 | 83 | #error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd." 84 | 85 | #endif 86 | 87 | /** 88 | * Init function that must be called before using crcFast(). 89 | * This function is useless for crcSlow() and shall not be called if only 90 | * crcSlow() is used! 91 | * 92 | * @note Using this function will use 1KiB of BSS ram! 93 | */ 94 | void crcInit(void); 95 | 96 | /** 97 | * Slow implementation of CRC. 98 | * 99 | * This function trades speeds for memory usage as it does not require 100 | * pre-calculated tables but executes some code for each data bits. Good for one 101 | * time CRC calculation. Bad for data communication check. 102 | * 103 | * @param datas Pointer to the data buffer onto the CRC will be calculated. 104 | * @param nBytes Number of bytes to calculate the CRC from. 105 | * @return The CRC value. 106 | */ 107 | crc crcSlow(void * datas, int nBytes); 108 | 109 | /** 110 | * Fast implementation of CRC. 111 | * 112 | * This function trades memory usage for speed as it requires pre-calculated 113 | * table (calculated by crcInit()). The requirement is 512Bytes for 16bits CRC 114 | * and 1024Bytes for 32bits CRC. 115 | * 116 | * @param datas Pointer to the data buffer onto the CRC will be calculated. 117 | * @param nBytes Number of bytes to calculate the CRC from. 118 | * @return The CRC value. 119 | */ 120 | crc crcFast(void * datas, int nBytes); 121 | 122 | 123 | #endif /* _crc_h */ 124 | -------------------------------------------------------------------------------- /src/crtp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __CRTP_H__ 25 | #define __CRTP_H__ 26 | 27 | #include 28 | 29 | #define CRTP_MAX_DATA_SIZE 31 30 | 31 | typedef struct crtpPacket_s { 32 | union { 33 | struct { 34 | union { 35 | uint8_t header; 36 | struct { 37 | uint8_t channel:2; 38 | uint8_t reserved:2; 39 | uint8_t port:4; 40 | }; 41 | }; 42 | uint8_t data[CRTP_MAX_DATA_SIZE]; 43 | } __attribute__((packed)); 44 | char raw[CRTP_MAX_DATA_SIZE +1]; 45 | }; 46 | uint8_t datalen; 47 | } CrtpPacket; 48 | 49 | #endif //__CRTP_H__ 50 | -------------------------------------------------------------------------------- /src/esb.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * Implementation of the Nordic ESB protocol in PRX mode for nRF51822 25 | */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "esb.h" 32 | 33 | #include 34 | 35 | #undef RSSI_ACK_PACKET 36 | 37 | #define RXQ_LEN 4 38 | #define TXQ_LEN 4 39 | 40 | static char address[5] = {0xe7, 0xe7, 0xe7, 0xe7, 0xe7}; 41 | 42 | static enum {doTx, doRx} rs; //Radio state 43 | 44 | static EsbPacket rxPackets[TXQ_LEN]; 45 | static int rxq_head = 0; 46 | static int rxq_tail = 0; 47 | 48 | static EsbPacket txPackets[TXQ_LEN]; 49 | static int txq_head = 0; 50 | static int txq_tail = 0; 51 | 52 | static EsbPacket ackPacket; 53 | 54 | // Function that swaps the bits within each byte in a uint32. Used to convert from nRF24L type addressing to nRF51 type addressing 55 | static uint32_t bytewise_bit_swap(uint32_t inp) 56 | { 57 | inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4; 58 | inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2; 59 | return (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1; 60 | } 61 | 62 | /* Radio protocol implementation */ 63 | 64 | static bool isRetry(EsbPacket *pk) 65 | { 66 | static int prevPid; 67 | static int prevCrc; 68 | 69 | bool retry = false; 70 | 71 | if ((prevPid == pk->pid) && (prevCrc == pk->crc)) { 72 | retry = true; 73 | } 74 | 75 | prevPid = pk->pid; 76 | prevCrc = pk->crc; 77 | 78 | return retry; 79 | } 80 | 81 | // Handles the queue 82 | static void setupTx(bool retry) { 83 | static EsbPacket * lastSentPacket; 84 | 85 | if (retry) { 86 | NRF_RADIO->PACKETPTR = (uint32_t)lastSentPacket; 87 | } else { 88 | if (lastSentPacket != &ackPacket) { 89 | //No retry, TX payload has been sent! 90 | if (txq_head != txq_tail) { 91 | txq_tail = ((txq_tail+1)%TXQ_LEN); 92 | } 93 | } 94 | 95 | if (txq_tail != txq_head) { 96 | // Send next TX packet 97 | NRF_RADIO->PACKETPTR = (uint32_t)&txPackets[txq_tail]; 98 | lastSentPacket = &txPackets[txq_tail]; 99 | } else { 100 | // Send empty ACK 101 | #ifdef RSSI_ACK_PACKET 102 | ackPacket.size = 3; 103 | ackPacket.data[0] = 0xff; 104 | ackPacket.data[1] = 0x01; 105 | ackPacket.data[2] = NRF_RADIO->RSSISAMPLE; 106 | #endif 107 | NRF_RADIO->PACKETPTR = (uint32_t)&ackPacket; 108 | lastSentPacket = &ackPacket; 109 | } 110 | } 111 | 112 | //After being disabled the radio will automatically send the ACK 113 | NRF_RADIO->SHORTS &= ~RADIO_SHORTS_DISABLED_RXEN_Msk; 114 | NRF_RADIO->SHORTS |= RADIO_SHORTS_DISABLED_TXEN_Msk; 115 | rs = doTx; 116 | NRF_RADIO->TASKS_DISABLE = 1UL; 117 | } 118 | 119 | static void setupRx() { 120 | NRF_RADIO->PACKETPTR = (uint32_t)&rxPackets[rxq_head]; 121 | 122 | NRF_RADIO->SHORTS &= ~RADIO_SHORTS_DISABLED_TXEN_Msk; 123 | NRF_RADIO->SHORTS |= RADIO_SHORTS_DISABLED_RXEN_Msk; 124 | rs = doRx; 125 | NRF_RADIO->TASKS_DISABLE = 1UL; 126 | } 127 | 128 | void esbInterruptHandler() 129 | { 130 | EsbPacket *pk; 131 | 132 | if (NRF_RADIO->EVENTS_END) { 133 | NRF_RADIO->EVENTS_END = 0UL; 134 | 135 | switch (rs){ 136 | case doRx: 137 | //Wrong CRC packet are dropped 138 | if (!NRF_RADIO->CRCSTATUS) { 139 | NRF_RADIO->TASKS_START = 1UL; 140 | return; 141 | } 142 | 143 | pk = &rxPackets[rxq_head]; 144 | pk->rssi = NRF_RADIO->RSSISAMPLE; 145 | pk->crc = NRF_RADIO->RXCRC; 146 | 147 | // If no more space available on RX queue, drop packet! 148 | if (((rxq_head+1)%RXQ_LEN) == rxq_tail) { 149 | NRF_RADIO->TASKS_START = 1UL; 150 | return; 151 | } 152 | 153 | // If this packet is a retry, send the same ACK again 154 | if (isRetry(pk)) { 155 | setupTx(true); 156 | return; 157 | } 158 | 159 | // Good packet received, yea! 160 | rxq_head = ((rxq_head+1)%RXQ_LEN); 161 | setupTx(false); 162 | 163 | break; 164 | case doTx: 165 | //Setup RX for next packet 166 | setupRx(); 167 | break; 168 | } 169 | } 170 | } 171 | 172 | 173 | /* Public API */ 174 | 175 | // S1 is used for compatibility with NRF24L0+. These three bits are used 176 | // to store the PID and NO_ACK. 177 | #define PACKET0_S1_SIZE (3UL) 178 | // S0 is not used 179 | #define PACKET0_S0_SIZE (0UL) 180 | // The size of the packet length field is 6 bits 181 | #define PACKET0_PAYLOAD_SIZE (6UL) 182 | // The size of the base address field is 4 bytes 183 | #define PACKET1_BASE_ADDRESS_LENGTH (4UL) 184 | // Don't use any extra added length besides the length field when sending 185 | #define PACKET1_STATIC_LENGTH (0UL) 186 | // Max payload allowed in a packet 187 | #define PACKET1_PAYLOAD_SIZE (32UL) 188 | 189 | void esbInit() 190 | { 191 | NRF_RADIO->POWER = 1; 192 | 193 | // Enable Radio interrupts 194 | //NVIC_SetPriority(RADIO_IRQn, 1); 195 | NVIC_EnableIRQ(RADIO_IRQn); 196 | // Radio config 197 | NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos); 198 | esbSetChannel(0); 199 | esbSetDatarate(esbDatarate2M); 200 | 201 | // Radio address config 202 | // Using logical address 0 so only BASE0 and PREFIX0 & 0xFF are used 203 | NRF_RADIO->PREFIX0 = bytewise_bit_swap(0xC4C3C200UL | address[4]); // Prefix byte of addresses 3 to 0 204 | NRF_RADIO->PREFIX1 = bytewise_bit_swap(0xC5C6C7C8UL); // Prefix byte of addresses 7 to 4 205 | NRF_RADIO->BASE0 = bytewise_bit_swap(*(uint32_t*)address); //*(uint32_t*)&address[0]; // Base address for prefix 0 206 | NRF_RADIO->BASE1 = bytewise_bit_swap(0x00C2C2C2UL); // Base address for prefix 1-7 207 | NRF_RADIO->TXADDRESS = 0x00UL; // Set device address 0 to use when transmitting 208 | NRF_RADIO->RXADDRESSES = 0x01UL; // Enable device address 0 to use which receiving 209 | 210 | // Packet configuration 211 | NRF_RADIO->PCNF0 = (PACKET0_S1_SIZE << RADIO_PCNF0_S1LEN_Pos) | 212 | (PACKET0_S0_SIZE << RADIO_PCNF0_S0LEN_Pos) | 213 | (PACKET0_PAYLOAD_SIZE << RADIO_PCNF0_LFLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" 214 | 215 | // Packet configuration 216 | NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | 217 | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | 218 | (PACKET1_BASE_ADDRESS_LENGTH << RADIO_PCNF1_BALEN_Pos) | 219 | (PACKET1_STATIC_LENGTH << RADIO_PCNF1_STATLEN_Pos) | 220 | (PACKET1_PAYLOAD_SIZE << RADIO_PCNF1_MAXLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" 221 | 222 | // CRC Config 223 | NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos); // Number of checksum bits 224 | NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value 225 | NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1 226 | 227 | // Enable interrupt for end event 228 | NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; 229 | 230 | // Set all shorts so that RSSI is measured and only END is required interrupt 231 | NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; 232 | NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk; 233 | NRF_RADIO->SHORTS |= RADIO_SHORTS_DISABLED_TXEN_Msk; 234 | NRF_RADIO->SHORTS |= RADIO_SHORTS_DISABLED_RSSISTOP_Enabled; 235 | 236 | // Set RX buffer and start RX 237 | rs = doRx; 238 | NRF_RADIO->PACKETPTR = (uint32_t)&rxPackets[rxq_head]; 239 | NRF_RADIO->TASKS_RXEN = 1U; 240 | } 241 | 242 | void esbDeinit() 243 | { 244 | NVIC_DisableIRQ(RADIO_IRQn); 245 | 246 | NRF_RADIO->INTENCLR = RADIO_INTENSET_END_Msk; 247 | NRF_RADIO->SHORTS = 0; 248 | NRF_RADIO->TASKS_DISABLE = 1; 249 | NRF_RADIO->POWER = 0; 250 | } 251 | 252 | bool esbIsRxPacket() 253 | { 254 | return (rxq_head != rxq_tail); 255 | } 256 | 257 | EsbPacket * esbGetRxPacket() 258 | { 259 | EsbPacket *pk = NULL; 260 | 261 | if (esbIsRxPacket()) { 262 | pk = &rxPackets[rxq_tail]; 263 | } 264 | 265 | return pk; 266 | } 267 | 268 | void esbReleaseRxPacket() 269 | { 270 | rxq_tail = (rxq_tail+1)%RXQ_LEN; 271 | } 272 | 273 | bool esbCanTxPacket() 274 | { 275 | return ((txq_head+1)%TXQ_LEN)!=txq_tail; 276 | } 277 | 278 | EsbPacket * esbGetTxPacket() 279 | { 280 | EsbPacket *pk = NULL; 281 | 282 | if (esbCanTxPacket()) { 283 | pk = &txPackets[txq_head]; 284 | } 285 | 286 | return pk; 287 | } 288 | 289 | void esbSendTxPacket() 290 | { 291 | txq_head = (txq_head+1)%TXQ_LEN; 292 | } 293 | 294 | void esbSetDatarate(EsbDatarate datarate) 295 | { 296 | switch (datarate) { 297 | case esbDatarate250K: 298 | NRF_RADIO->MODE = (RADIO_MODE_MODE_Nrf_250Kbit << RADIO_MODE_MODE_Pos); 299 | break; 300 | case esbDatarate1M: 301 | NRF_RADIO->MODE = (RADIO_MODE_MODE_Nrf_1Mbit << RADIO_MODE_MODE_Pos); 302 | break; 303 | case esbDatarate2M: 304 | NRF_RADIO->MODE = (RADIO_MODE_MODE_Nrf_2Mbit << RADIO_MODE_MODE_Pos); 305 | break; 306 | } 307 | } 308 | 309 | void esbSetChannel(unsigned int channel) 310 | { 311 | if (channel < 126) { 312 | NRF_RADIO->FREQUENCY = channel; 313 | } 314 | } 315 | 316 | void esbSetAddress(char *addr) { 317 | memcpy(address, addr, 5); 318 | } 319 | 320 | -------------------------------------------------------------------------------- /src/esb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * Implementation of the Nordic ESB protocol in PRX mode for nRF51822 25 | */ 26 | #ifndef __ESB_H__ 27 | #define __ESB_H__ 28 | 29 | #include 30 | #include 31 | 32 | /* ESB Radio packet */ 33 | typedef struct esbPacket_s { 34 | /* Part that is written by the radio DMA */ 35 | struct { 36 | uint8_t size; 37 | union { 38 | uint8_t s1; 39 | struct { 40 | uint8_t noack :1; 41 | uint8_t pid :2; 42 | }; 43 | }; 44 | uint8_t data[32]; 45 | } __attribute__((packed)); 46 | /* Written by the radio interrupt routine */ 47 | int rssi; 48 | unsigned int crc; 49 | } EsbPacket; 50 | 51 | typedef enum esbDatarate_e { esbDatarate250K=0, 52 | esbDatarate1M=1, 53 | esbDatarate2M=2 } EsbDatarate; 54 | 55 | /*** For compatibility ***/ 56 | #define RADIO_RATE_250K esbDatarate250K 57 | #define RADIO_RATE_1M esbDatarate1M 58 | #define RADIO_RATE_2M esbDatarate2M 59 | 60 | /* Initialize the radio for ESB */ 61 | void esbInit(); 62 | 63 | /* Stop ESB and free the radio */ 64 | void esbDeinit(); 65 | 66 | /* Radio interrupt handler */ 67 | void esbInterruptHandler(); 68 | 69 | /* Return true is a packet has been received and is ready to read */ 70 | bool esbIsRxPacket(); 71 | 72 | /* Return the packet received of NULL if none*/ 73 | EsbPacket * esbGetRxPacket(); 74 | 75 | /* Release the RX packet so that it can be used again by the radio */ 76 | void esbReleaseRxPacket(); 77 | 78 | /* Return true if a packet can be pushed in the TX queue */ 79 | bool esbCanTxPacket(); 80 | 81 | /* Return the address of the next TX packet in the TX queue */ 82 | EsbPacket * esbGetTxPacket(); 83 | 84 | /* Release and set for sending the buffer returned by getTxPacket */ 85 | void esbSendTxPacket(); 86 | 87 | /* Set datarate */ 88 | void esbSetDatarate(EsbDatarate datarate); 89 | 90 | /* Set channel */ 91 | void esbSetChannel(unsigned int channel); 92 | 93 | /* Set TX and RX radio link address */ 94 | void esbSetAddress(char *address); 95 | 96 | 97 | #endif //__ESB_H__ 98 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA 3 | * Copyright (c) 2024, Bitcraze AB 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form, except as embedded into a Nordic 14 | * Semiconductor ASA integrated circuit in a product or a software update for 15 | * such product, must reproduce the above copyright notice, this list of 16 | * conditions and the following disclaimer in the documentation and/or other 17 | * materials provided with the distribution. 18 | * 19 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of its 20 | * contributors may be used to endorse or promote products derived from this 21 | * software without specific prior written permission. 22 | * 23 | * 4. This software, with or without modification, must only be used with a 24 | * Nordic Semiconductor ASA integrated circuit. 25 | * 26 | * 5. Any software provided in binary form under this license must not be reverse 27 | * engineered, decompiled, modified and/or disassembled. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS 30 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 31 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE 33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 35 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 38 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | */ 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include "nordic_common.h" 47 | #include "nrf.h" 48 | #include "app_error.h" 49 | #include "ble.h" 50 | #include "ble_hci.h" 51 | #include "ble_srv_common.h" 52 | #include "ble_advdata.h" 53 | #include "ble_advertising.h" 54 | #include "ble_conn_params.h" 55 | #include "boards.h" 56 | #include "softdevice_handler.h" 57 | #include "app_timer.h" 58 | #include "app_mailbox.h" 59 | #include "fstorage.h" 60 | #include "fds.h" 61 | #include 62 | 63 | #include "sensorsim.h" 64 | #include "nrf_gpio.h" 65 | #include "ble_hci.h" 66 | #include "ble_advdata.h" 67 | #include "ble_advertising.h" 68 | #include "ble_conn_state.h" 69 | #include "ble_dis.h" 70 | 71 | #include "ble_crazyflie.h" 72 | 73 | #include "syslink.h" 74 | #include "crazyflie2_pm.h" 75 | #include "esb.h" 76 | #include "timeslot.h" 77 | #include "button.h" 78 | #include "uart.h" 79 | #include "systick.h" 80 | #include "bootloader.h" 81 | #include "platform.h" 82 | 83 | #include "crtp.h" 84 | 85 | #define NRF_LOG_MODULE_NAME "APP" 86 | #include "nrf_log.h" 87 | #include "nrf_log_ctrl.h" 88 | 89 | #define IS_SRVC_CHANGED_CHARACT_PRESENT 1 /**< Include or not the service_changed characteristic. if not enabled, the server's database cannot be changed for the lifetime of the device*/ 90 | 91 | #if (NRF_SD_BLE_API_VERSION == 3) 92 | #define NRF_BLE_MAX_MTU_SIZE GATT_MTU_SIZE_DEFAULT /**< MTU size used in the softdevice enabling and to reply to a BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. */ 93 | #endif 94 | 95 | #define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */ 96 | 97 | #define CENTRAL_LINK_COUNT 0 /**< Number of central links used by the application. When changing this number remember to adjust the RAM settings*/ 98 | #define PERIPHERAL_LINK_COUNT 1 /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/ 99 | 100 | #define DEVICE_NAME "Crazyflie Loader" /**< Name of device. Will be included in the advertising data. */ 101 | #define MANUFACTURER_NAME "Bitcraze AB" /**< Manufacturer. Will be passed to Device Information Service. */ 102 | #define APP_ADV_INTERVAL 300 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 187.5 ms). */ 103 | 104 | #define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */ 105 | #define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */ 106 | 107 | #define MIN_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.1 seconds). */ 108 | #define MAX_CONN_INTERVAL MSEC_TO_UNITS(100, UNIT_1_25_MS) /**< Maximum acceptable connection interval (0.2 second). */ 109 | #define SLAVE_LATENCY 0 /**< Slave latency. */ 110 | #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory timeout (4 seconds). */ 111 | 112 | #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */ 113 | #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */ 114 | #define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */ 115 | 116 | #define SEC_PARAM_BOND 1 /**< Perform bonding. */ 117 | #define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ 118 | #define SEC_PARAM_LESC 0 /**< LE Secure Connections not enabled. */ 119 | #define SEC_PARAM_KEYPRESS 0 /**< Keypress notifications not enabled. */ 120 | #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ 121 | #define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ 122 | #define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ 123 | #define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */ 124 | 125 | #define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */ 126 | 127 | static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */ 128 | 129 | static ble_crazyflie_t m_crazyflie; 130 | 131 | /* Up to 4 full packets can be buffered there*/ 132 | APP_MAILBOX_DEF(m_uplink, 32*4, sizeof(uint8_t)); 133 | 134 | static ble_uuid_t m_adv_uuids[] = { 135 | {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}}; 136 | 137 | /**@brief Callback function for asserts in the SoftDevice. 138 | * 139 | * @details This function will be called in case of an assert in the SoftDevice. 140 | * 141 | * @warning This handler is an example only and does not fit a final product. You need to analyze 142 | * how your product is supposed to react in case of Assert. 143 | * @warning On assert from the SoftDevice, the system can only recover on reset. 144 | * 145 | * @param[in] line_num Line number of the failing ASSERT call. 146 | * @param[in] file_name File name of the failing ASSERT call. 147 | */ 148 | void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) 149 | { 150 | app_error_handler(DEAD_BEEF, line_num, p_file_name); 151 | } 152 | 153 | /**@brief Function for the Timer initialization. 154 | * 155 | * @details Initializes the timer module. This creates and starts application timers. 156 | */ 157 | static void timers_init(void) 158 | { 159 | 160 | // Initialize timer module. 161 | APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); 162 | } 163 | 164 | 165 | /**@brief Function for the GAP initialization. 166 | * 167 | * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the 168 | * device including the device name, appearance, and the preferred connection parameters. 169 | */ 170 | static void gap_params_init(void) 171 | { 172 | uint32_t err_code; 173 | ble_gap_conn_params_t gap_conn_params; 174 | ble_gap_conn_sec_mode_t sec_mode; 175 | 176 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); 177 | 178 | err_code = sd_ble_gap_device_name_set(&sec_mode, 179 | (const uint8_t *)DEVICE_NAME, 180 | strlen(DEVICE_NAME)); 181 | APP_ERROR_CHECK(err_code); 182 | 183 | err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN); 184 | APP_ERROR_CHECK(err_code); 185 | 186 | memset(&gap_conn_params, 0, sizeof(gap_conn_params)); 187 | 188 | gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; 189 | gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; 190 | gap_conn_params.slave_latency = SLAVE_LATENCY; 191 | gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; 192 | 193 | err_code = sd_ble_gap_ppcp_set(&gap_conn_params); 194 | APP_ERROR_CHECK(err_code); 195 | } 196 | 197 | static void handle_crazyflie_data(ble_crazyflie_t *p_crazyflie, uint8_t *p_data, uint16_t length) { 198 | NRF_LOG_INFO("CRTP packet received of length %d width first byte %02x\n", length, p_data[0]); 199 | uint32_t error_code; 200 | 201 | error_code = app_mailbox_sized_put(&m_uplink, p_data, length); 202 | if (error_code != NRF_SUCCESS) { 203 | NRF_LOG_INFO("Error putting packet in mailbox: %x\n", error_code); 204 | } 205 | } 206 | 207 | /**@brief Function for initializing services that will be used by the application. 208 | */ 209 | static void services_init(void) 210 | { 211 | uint32_t err_code; 212 | ble_crazyflie_init_t crazyflie_init = { 213 | .data_handler = handle_crazyflie_data, 214 | }; 215 | 216 | err_code = ble_crazyflie_init(&m_crazyflie, &crazyflie_init); 217 | APP_ERROR_CHECK(err_code); 218 | 219 | ble_dis_init_t dis_init; 220 | 221 | // Initialize Device Information Service 222 | memset(&dis_init, 0, sizeof(dis_init)); 223 | 224 | ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); 225 | 226 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); 227 | BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); 228 | 229 | err_code = ble_dis_init(&dis_init); 230 | APP_ERROR_CHECK(err_code); 231 | } 232 | 233 | 234 | /**@brief Function for handling the Connection Parameters Module. 235 | * 236 | * @details This function will be called for all events in the Connection Parameters Module which 237 | * are passed to the application. 238 | * @note All this function does is to disconnect. This could have been done by simply 239 | * setting the disconnect_on_fail config parameter, but instead we use the event 240 | * handler mechanism to demonstrate its use. 241 | * 242 | * @param[in] p_evt Event received from the Connection Parameters Module. 243 | */ 244 | static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) 245 | { 246 | uint32_t err_code; 247 | 248 | if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) 249 | { 250 | err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE); 251 | APP_ERROR_CHECK(err_code); 252 | } 253 | } 254 | 255 | 256 | /**@brief Function for handling a Connection Parameters error. 257 | * 258 | * @param[in] nrf_error Error code containing information about what went wrong. 259 | */ 260 | static void conn_params_error_handler(uint32_t nrf_error) 261 | { 262 | APP_ERROR_HANDLER(nrf_error); 263 | } 264 | 265 | 266 | /**@brief Function for initializing the Connection Parameters module. 267 | */ 268 | static void conn_params_init(void) 269 | { 270 | uint32_t err_code; 271 | ble_conn_params_init_t cp_init; 272 | 273 | memset(&cp_init, 0, sizeof(cp_init)); 274 | 275 | cp_init.p_conn_params = NULL; 276 | cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; 277 | cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; 278 | cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; 279 | cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; 280 | cp_init.disconnect_on_fail = false; 281 | cp_init.evt_handler = on_conn_params_evt; 282 | cp_init.error_handler = conn_params_error_handler; 283 | 284 | err_code = ble_conn_params_init(&cp_init); 285 | APP_ERROR_CHECK(err_code); 286 | } 287 | 288 | APP_TIMER_DEF(m_led_timer); 289 | 290 | static void blink_led(void* data) { 291 | UNUSED_PARAMETER(data); 292 | static bool led_state = true; 293 | nrf_gpio_pin_write(LED_1, led_state); 294 | 295 | led_state = !led_state; 296 | } 297 | 298 | /**@brief Function for starting timers. 299 | */ 300 | static void application_timers_start(void) 301 | { 302 | uint32_t err_code; 303 | err_code = app_timer_create(&m_led_timer, APP_TIMER_MODE_REPEATED, blink_led); 304 | APP_ERROR_CHECK(err_code); 305 | err_code = app_timer_start(m_led_timer, APP_TIMER_TICKS(500, APP_TIMER_PRESCALER), NULL); 306 | APP_ERROR_CHECK(err_code); 307 | 308 | } 309 | 310 | 311 | /**@brief Function for handling advertising events. 312 | * 313 | * @details This function will be called for advertising events which are passed to the application. 314 | * 315 | * @param[in] ble_adv_evt Advertising event. 316 | */ 317 | static void on_adv_evt(ble_adv_evt_t ble_adv_evt) 318 | { 319 | switch (ble_adv_evt) 320 | { 321 | case BLE_ADV_EVT_FAST: 322 | NRF_LOG_INFO("Fast advertising\r\n"); 323 | break; 324 | 325 | case BLE_ADV_EVT_IDLE: 326 | break; 327 | 328 | default: 329 | break; 330 | } 331 | } 332 | 333 | 334 | /**@brief Function for handling the Application's BLE Stack events. 335 | * 336 | * @param[in] p_ble_evt Bluetooth stack event. 337 | */ 338 | static void on_ble_evt(ble_evt_t * p_ble_evt) 339 | { 340 | uint32_t err_code = NRF_SUCCESS; 341 | 342 | switch (p_ble_evt->header.evt_id) 343 | { 344 | case BLE_GAP_EVT_DISCONNECTED: 345 | NRF_LOG_INFO("Disconnected.\r\n"); 346 | APP_ERROR_CHECK(err_code); 347 | break; // BLE_GAP_EVT_DISCONNECTED 348 | 349 | case BLE_GAP_EVT_CONNECTED: 350 | NRF_LOG_INFO("Connected.\r\n"); 351 | APP_ERROR_CHECK(err_code); 352 | m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; 353 | break; // BLE_GAP_EVT_CONNECTED 354 | 355 | case BLE_GATTC_EVT_TIMEOUT: 356 | // Disconnect on GATT Client timeout event. 357 | NRF_LOG_DEBUG("GATT Client Timeout.\r\n"); 358 | err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, 359 | BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); 360 | APP_ERROR_CHECK(err_code); 361 | break; // BLE_GATTC_EVT_TIMEOUT 362 | 363 | case BLE_GATTS_EVT_TIMEOUT: 364 | // Disconnect on GATT Server timeout event. 365 | NRF_LOG_DEBUG("GATT Server Timeout.\r\n"); 366 | err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, 367 | BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); 368 | APP_ERROR_CHECK(err_code); 369 | break; // BLE_GATTS_EVT_TIMEOUT 370 | 371 | case BLE_EVT_USER_MEM_REQUEST: 372 | err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gattc_evt.conn_handle, NULL); 373 | APP_ERROR_CHECK(err_code); 374 | break; // BLE_EVT_USER_MEM_REQUEST 375 | 376 | case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: 377 | { 378 | ble_gatts_evt_rw_authorize_request_t req; 379 | ble_gatts_rw_authorize_reply_params_t auth_reply; 380 | 381 | req = p_ble_evt->evt.gatts_evt.params.authorize_request; 382 | 383 | if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID) 384 | { 385 | if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ) || 386 | (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) || 387 | (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) 388 | { 389 | if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) 390 | { 391 | auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; 392 | } 393 | else 394 | { 395 | auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ; 396 | } 397 | auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED; 398 | err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle, 399 | &auth_reply); 400 | APP_ERROR_CHECK(err_code); 401 | } 402 | } 403 | } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST 404 | 405 | #if (NRF_SD_BLE_API_VERSION == 3) 406 | case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: 407 | err_code = sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 408 | NRF_BLE_MAX_MTU_SIZE); 409 | APP_ERROR_CHECK(err_code); 410 | break; // BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST 411 | #endif 412 | 413 | default: 414 | // No implementation needed. 415 | break; 416 | } 417 | } 418 | 419 | 420 | /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler. 421 | * 422 | * @details This function is called from the BLE Stack event interrupt handler after a BLE stack 423 | * event has been received. 424 | * 425 | * @param[in] p_ble_evt Bluetooth stack event. 426 | */ 427 | static void ble_evt_dispatch(ble_evt_t * p_ble_evt) 428 | { 429 | /** The Connection state module has to be fed BLE events in order to function correctly 430 | * Remember to call ble_conn_state_on_ble_evt before calling any ble_conns_state_* functions. */ 431 | ble_conn_state_on_ble_evt(p_ble_evt); 432 | ble_conn_params_on_ble_evt(p_ble_evt); 433 | on_ble_evt(p_ble_evt); 434 | ble_advertising_on_ble_evt(p_ble_evt); 435 | ble_crazyflie_on_ble_evt(&m_crazyflie, p_ble_evt); 436 | } 437 | 438 | 439 | /**@brief Function for dispatching a system event to interested modules. 440 | * 441 | * @details This function is called from the System event interrupt handler after a system 442 | * event has been received. 443 | * 444 | * @param[in] sys_evt System stack event. 445 | */ 446 | static void sys_evt_dispatch(uint32_t sys_evt) 447 | { 448 | // Dispatch the system event to the fstorage module, where it will be 449 | // dispatched to the Flash Data Storage (FDS) module. 450 | fs_sys_event_handler(sys_evt); 451 | 452 | // Dispatch to the Advertising module last, since it will check if there are any 453 | // pending flash operations in fstorage. Let fstorage process system events first, 454 | // so that it can report correctly to the Advertising module. 455 | ble_advertising_on_sys_evt(sys_evt); 456 | 457 | bootloaderOnSdEvt(sys_evt); 458 | } 459 | 460 | 461 | /**@brief Function for initializing the BLE stack. 462 | * 463 | * @details Initializes the SoftDevice and the BLE event interrupt. 464 | */ 465 | static void ble_stack_init(void) 466 | { 467 | uint32_t err_code; 468 | 469 | nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC; 470 | 471 | // Initialize the SoftDevice handler module. 472 | SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL); 473 | 474 | ble_enable_params_t ble_enable_params; 475 | err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, 476 | PERIPHERAL_LINK_COUNT, 477 | &ble_enable_params); 478 | APP_ERROR_CHECK(err_code); 479 | 480 | // Check the ram settings against the used number of links 481 | CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT); 482 | 483 | // Enable BLE stack. 484 | #if (NRF_SD_BLE_API_VERSION == 3) 485 | ble_enable_params.gatt_enable_params.att_mtu = NRF_BLE_MAX_MTU_SIZE; 486 | #endif 487 | err_code = softdevice_enable(&ble_enable_params); 488 | APP_ERROR_CHECK(err_code); 489 | 490 | // Register with the SoftDevice handler module for BLE events. 491 | err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); 492 | APP_ERROR_CHECK(err_code); 493 | 494 | // Register with the SoftDevice handler module for BLE events. 495 | err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch); 496 | APP_ERROR_CHECK(err_code); 497 | } 498 | 499 | /**@brief Function for initializing the Advertising functionality. 500 | */ 501 | static void advertising_init(void) 502 | { 503 | uint32_t err_code; 504 | ble_advdata_t advdata; 505 | ble_adv_modes_config_t options; 506 | 507 | // Build advertising data struct to pass into @ref ble_advertising_init. 508 | memset(&advdata, 0, sizeof(advdata)); 509 | 510 | advdata.name_type = BLE_ADVDATA_FULL_NAME; 511 | advdata.include_appearance = true; 512 | advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; 513 | advdata.uuids_more_available.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); 514 | advdata.uuids_more_available.p_uuids = m_adv_uuids; 515 | 516 | memset(&options, 0, sizeof(options)); 517 | options.ble_adv_fast_enabled = true; 518 | options.ble_adv_fast_interval = APP_ADV_INTERVAL; 519 | options.ble_adv_fast_timeout = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED; 520 | 521 | err_code = ble_advertising_init(&advdata, NULL, &options, on_adv_evt, NULL); 522 | APP_ERROR_CHECK(err_code); 523 | } 524 | 525 | #define BOOTLOADER_ADDRESS 0x0003A000 526 | #define FW_ADDRESS 0x0001B000 527 | 528 | void start_firmware() __attribute__ ((noreturn, naked)); 529 | void start_firmware() { 530 | void (*fw_start)(void) = *(void (**)(void))(FW_ADDRESS + 4); 531 | 532 | sd_softdevice_vector_table_base_set(FW_ADDRESS); 533 | __set_MSP(*(uint32_t*)FW_ADDRESS); 534 | fw_start(); 535 | 536 | while (1); 537 | } 538 | 539 | static sd_mbr_command_t startSdCmd = { 540 | .command = SD_MBR_COMMAND_INIT_SD, 541 | }; 542 | 543 | // static struct syslinkPacket m_syslink_packet; 544 | // static void handle_syslink_packet(struct syslinkPacket *packet); 545 | void mainLoop(void); 546 | /**@brief Function for application main entry. 547 | */ 548 | int main(void) 549 | { 550 | uint32_t err_code; 551 | static char address[5]; 552 | 553 | platformInitByDeviceType(); 554 | 555 | sd_mbr_command(&startSdCmd); 556 | sd_softdevice_vector_table_base_set(BOOTLOADER_ADDRESS); 557 | 558 | // If the master boot switch has detected short or no click: boot the firmware 559 | if (((NRF_POWER->GPREGRET & 0x86U) != 0x82U) && 560 | ((NRF_POWER->GPREGRET & 0x40U) != 0x40U) && 561 | (*(uint32_t *)FW_ADDRESS != 0xFFFFFFFFU) ) { 562 | start_firmware(); 563 | } 564 | 565 | if (NRF_POWER->GPREGRET & 0x40U) { 566 | address[4] = 0xb1; 567 | memcpy(&address[0], (char*)&NRF_FICR->DEVICEADDR[0], 4); 568 | esbSetAddress(address); 569 | } 570 | 571 | NRF_POWER->GPREGRET &= ~(0x60U); 572 | 573 | // Initialize. 574 | err_code = NRF_LOG_INIT(NULL); 575 | APP_ERROR_CHECK(err_code); 576 | 577 | // Light up LED 578 | nrf_gpio_cfg_output(LED_1); 579 | nrf_gpio_pin_write(LED_1, LEDS_ACTIVE_STATE); 580 | 581 | timers_init(); 582 | ble_stack_init(); 583 | gap_params_init(); 584 | services_init(); 585 | advertising_init(); 586 | conn_params_init(); 587 | 588 | // err_code = syslinkInit(); 589 | // APP_ERROR_CHECK(err_code); 590 | 591 | crazyflie2_pm_init(); 592 | crazyflie2_pm_set_state(PM_STATE_SYSTEM_ON); 593 | 594 | err_code = app_mailbox_create(&m_uplink); 595 | APP_ERROR_CHECK(err_code); 596 | 597 | // Start execution. 598 | application_timers_start(); 599 | err_code = ble_advertising_start(BLE_ADV_MODE_FAST); 600 | APP_ERROR_CHECK(err_code); 601 | 602 | err_code = timeslot_start(); 603 | APP_ERROR_CHECK(err_code); 604 | 605 | 606 | #ifdef HAS_TI_CHARGER 607 | // Enable 500mA USB input and enable battery charging 608 | nrf_gpio_cfg_output(PM_EN1); 609 | nrf_gpio_pin_set(PM_EN1); 610 | nrf_gpio_cfg_output(PM_EN2); 611 | nrf_gpio_pin_clear(PM_EN2); 612 | nrf_gpio_cfg_output(PM_CHG_EN); 613 | nrf_gpio_pin_clear(PM_CHG_EN); 614 | #endif 615 | 616 | // Power STM32, hold reset 617 | nrf_gpio_cfg_output(VEN_D); 618 | nrf_gpio_pin_set(VEN_D); 619 | nrf_gpio_cfg_output(STM_NRST_PIN); 620 | nrf_gpio_pin_clear(STM_NRST_PIN); 621 | 622 | // Set flow control and activate pull-down on RX data pin 623 | nrf_gpio_cfg_output(TX_PIN_NUMBER); 624 | nrf_gpio_pin_set(TX_PIN_NUMBER); 625 | nrf_gpio_cfg_output(RTS_PIN_NUMBER); 626 | nrf_gpio_pin_set(RTS_PIN_NUMBER); 627 | nrf_gpio_cfg_input(RX_PIN_NUMBER, NRF_GPIO_PIN_PULLDOWN); 628 | 629 | 630 | nrf_gpio_pin_set(STM_NRST_PIN); 631 | 632 | systickInit(); 633 | buttonInit(buttonIdle); 634 | 635 | mainLoop(); 636 | 637 | while (1); 638 | return 0; 639 | 640 | } 641 | 642 | static enum {connect_idle, connect_ble, connect_sb} cstate = connect_idle; 643 | 644 | void mainLoop(void) { 645 | bool resetToFw = false; 646 | static CrtpPacket crtpPacket; 647 | static bool stmStarted = false; 648 | 649 | while (!resetToFw) { 650 | EsbPacket *packet; 651 | buttonProcess(); 652 | 653 | if (buttonGetState() != buttonIdle) { 654 | resetToFw = true; 655 | } 656 | 657 | if ((stmStarted == false) && (nrf_gpio_pin_read(RX_PIN_NUMBER))) { 658 | nrf_gpio_cfg_input(RTS_PIN_NUMBER, NRF_GPIO_PIN_NOPULL); 659 | uartInit(); 660 | stmStarted = true; 661 | } 662 | 663 | 664 | if (cstate != connect_ble) { 665 | packet = esbGetRxPacket(); 666 | if (packet != NULL) { 667 | 668 | if ( ((packet->size >= 2) && 669 | (packet->data[0]==0xff) && 670 | (packet->data[1]==0xff)) || 671 | ((packet->size >= 2) && 672 | (packet->data[0]==0xff) && 673 | (packet->data[1]==0xfe)) 674 | ) { 675 | // Disable Bluetooth advertizing when receiving a bootloader SB packet 676 | if (cstate == connect_idle) { 677 | //sd_ble_gap_adv_stop(); 678 | cstate = connect_sb; 679 | } 680 | } 681 | 682 | // If we are connected SB, the packet is read and used 683 | if (cstate == connect_sb) { 684 | memcpy(crtpPacket.raw, packet->data, packet->size); 685 | crtpPacket.datalen = packet->size-1; 686 | } 687 | esbReleaseRxPacket(packet); 688 | } 689 | } 690 | if (cstate != connect_sb) { 691 | uint16_t full_size = 0; 692 | if (app_mailbox_sized_get(&m_uplink, crtpPacket.raw, &full_size) == NRF_SUCCESS) { 693 | crtpPacket.datalen = full_size - 1; 694 | cstate = connect_ble; 695 | } 696 | } 697 | 698 | if (crtpPacket.datalen != 0xffu) { 699 | struct syslinkPacket slPacket; 700 | slPacket.type = SYSLINK_RADIO_RAW; 701 | memcpy(slPacket.data, crtpPacket.raw, crtpPacket.datalen+1); 702 | slPacket.length = crtpPacket.datalen+1; 703 | 704 | if (bootloaderProcess(&crtpPacket) == false) { 705 | // Send packet to stm32 706 | syslinkSend(&slPacket); 707 | 708 | crtpPacket.datalen = 0xFFU; 709 | // If packet received from stm32, send it back 710 | if (syslinkReceive(&slPacket)) { 711 | if (slPacket.type == SYSLINK_RADIO_RAW) { 712 | memcpy(crtpPacket.raw, slPacket.data, slPacket.length); 713 | crtpPacket.datalen = slPacket.length-1; 714 | } 715 | } 716 | } 717 | } 718 | if (crtpPacket.datalen != 0xFFU) { 719 | if (cstate == connect_sb) { 720 | EsbPacket *pk = esbGetTxPacket(); 721 | if (pk) { 722 | memcpy(pk->data, crtpPacket.raw, crtpPacket.datalen+1); 723 | pk->size = crtpPacket.datalen+1; 724 | esbSendTxPacket(pk); 725 | } 726 | } else if (cstate == connect_ble) { 727 | ble_crazyflie_send_packet(&m_crazyflie, (uint8_t*) crtpPacket.raw, crtpPacket.datalen+1); 728 | } 729 | } 730 | 731 | crtpPacket.datalen = 0xFFU; 732 | 733 | // Blink the LED 734 | if (NRF_TIMER1->EVENTS_COMPARE[0]) { 735 | NRF_TIMER1->EVENTS_COMPARE[0] = 0; 736 | #ifndef DEBUG_TIMESLOT 737 | NRF_GPIOTE->TASKS_OUT[0] = 1; 738 | #endif 739 | } 740 | } 741 | 742 | //Set bit 0x20 forces boot to firmware 743 | NRF_POWER->GPREGRET |= 0x20U; 744 | sd_nvic_SystemReset(); 745 | 746 | while(1); 747 | } 748 | 749 | /** 750 | * @} 751 | */ 752 | -------------------------------------------------------------------------------- /src/platform.c: -------------------------------------------------------------------------------- 1 | #include "platform.h" 2 | 3 | #include 4 | #include 5 | 6 | static const char *defaultDeviceType = "0;CF20;R=D"; 7 | 8 | static char *deviceTypeStringLocation = (void*)PLATFORM_DEVICE_DATA_FLASH_POS; 9 | 10 | static bool has_rfx2411n = false; 11 | 12 | void platformGetDeviceTypeString(char *deviceTypeString) 13 | { 14 | if (deviceTypeStringLocation[0] == 0xffu) { 15 | strncpy(deviceTypeString, defaultDeviceType, 32); 16 | deviceTypeString[32] = 0; 17 | } else { 18 | strncpy(deviceTypeString, deviceTypeStringLocation, 32); 19 | deviceTypeString[32] = 0; 20 | } 21 | } 22 | 23 | /** 24 | * Parse deviceType string to extract the deviceType 25 | * 26 | * Ignores the key=value sections. 27 | * 28 | * \param [in] deviceTypeString deviceTypeString extracted from the hardware 29 | * \param [out] deviceType Buffer of at least PLATFORM_DEVICE_TYPE_MAX_LEN 30 | * bytes where the device type will be stored 31 | * \return 0 in case of success, 1 in case of failure. 32 | */ 33 | static int platformParseDeviceTypeString(char* deviceTypeString, char* deviceType) { 34 | // char *state; 35 | 36 | memcpy(deviceType, deviceTypeString+2, 4); 37 | deviceType[4] = '\0'; 38 | 39 | return 0; 40 | } 41 | 42 | // This function configures the platform in runtime based on the device type. 43 | // The main reason to not move it into the platform files is that if a user 44 | // flashes the wrong binary in the NRF we still want it to start up. 45 | int platformInitByDeviceType() { 46 | static char deviceTypeString[PLATFORM_DEVICE_TYPE_STRING_MAX_LEN]; 47 | static char deviceType[PLATFORM_DEVICE_TYPE_MAX_LEN]; 48 | 49 | platformGetDeviceTypeString(deviceTypeString); 50 | if (platformParseDeviceTypeString(deviceTypeString, deviceType) != 0) { 51 | return 1; 52 | } 53 | 54 | if (0 == strcmp(deviceType, "CF20")) { 55 | has_rfx2411n = false; 56 | 57 | } else if ((0 == strcmp(deviceType, "CF21")) || 58 | (0 == strcmp(deviceType, "C21B"))) { 59 | has_rfx2411n = true; 60 | 61 | } else if (0 == strcmp(deviceType, "RR10")) { 62 | has_rfx2411n = true; 63 | 64 | } else if ((0 == strcmp(deviceType, "RZ10")) || 65 | (0 == strcmp(deviceType, "CB10")) || 66 | (0 == strcmp(deviceType, "CB11"))) { 67 | has_rfx2411n = true; 68 | 69 | } else { 70 | has_rfx2411n = false; 71 | } 72 | 73 | return 0; 74 | } 75 | 76 | bool platformHasRfx2411n() { 77 | return has_rfx2411n; 78 | } 79 | -------------------------------------------------------------------------------- /src/platform.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 NRF Firmware 9 | * Copyright (c) 2024, Bitcraze AB, All rights reserved. 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #pragma once 25 | 26 | #include 27 | #include 28 | 29 | #define PLATFORM_DEVICE_DATA_FLASH_POS 0x3FFE0 30 | #define PLATFORM_DEVICE_TYPE_STRING_MAX_LEN 33 31 | #define PLATFORM_DEVICE_TYPE_MAX_LEN 31 32 | 33 | /** 34 | * Fetch deviceType string from flash 35 | * 36 | * This function defaults to "0;CF20;R=D" if no string is present in the 37 | * hardware 38 | * 39 | * \param [out] deviceTypeString Buffer of at least 40 | * PLATFORM_DEVICE_TYPE_STRING_MAX_LEN bytes 41 | * where the platform string will be stored 42 | */ 43 | void platformGetDeviceTypeString(char *deviceTypeString); 44 | 45 | /** 46 | * Initialize the platform 47 | * 48 | * Initialize the platform discovering capabilities and returns if it has been successful 49 | * 50 | * \return 0 in case of success, 1 in case of failure. 51 | */ 52 | int platformInit(); 53 | 54 | /** 55 | * Initialize the platform based on device type 56 | * 57 | * Generic initialization based on device type 58 | * 59 | * \return 0 in case of success, 1 in case of failure. 60 | */ 61 | int platformInitByDeviceType(); 62 | 63 | // ************** Capabilities functions ************** 64 | // The following functions can be implemented by different platform to give 65 | // access to the current device capabilities. Not all platform has to implement 66 | // all functions 67 | bool platformHasRfx2411n(); 68 | -------------------------------------------------------------------------------- /src/syslink.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #include "syslink.h" 25 | #include "uart.h" 26 | 27 | #include 28 | #include "boards.h" 29 | 30 | #include 31 | #include 32 | 33 | /* Frame format: 34 | * +----+-----+------+-----+=============+-----+-----+ 35 | * | START | TYPE | LEN | DATA | CKSUM | 36 | * +----+-----+------+-----+=============+-----+-----+ 37 | * 38 | * - Start is 2 bytes constant, defined bellow 39 | * - Length and type are uint8_t 40 | * - Length define the data length 41 | * - CKSUM is 2 bytes Fletcher 8 bit checksum. See rfc1146. 42 | * Checksum is calculated with TYPE, LEN and DATA 43 | */ 44 | 45 | 46 | #define START "\xbc\xcf" 47 | #define START_BYTE1 0xBC 48 | #define START_BYTE2 0xCF 49 | 50 | bool syslinkReceive(struct syslinkPacket *packet) 51 | { 52 | static enum {state_first_start, state_second_start, state_length, state_type, state_data, state_cksum1, state_cksum2, state_done} state = state_first_start; 53 | static int step=0; 54 | static int length=0; 55 | static uint8_t cksum_a=0, cksum_b=0; 56 | char c; 57 | 58 | packet->length = 0; 59 | 60 | if (state == state_done) 61 | { 62 | state = state_first_start; 63 | step = 0; 64 | } 65 | 66 | while (uartIsDataReceived() && (state != state_done)) 67 | { 68 | c = uartGetc(); 69 | 70 | switch(state) 71 | { 72 | case state_first_start: 73 | state = (c == START_BYTE1) ? state_second_start : state_first_start; 74 | break; 75 | case state_second_start: 76 | state = (c == START_BYTE2) ? state_type : state_first_start; 77 | break; 78 | case state_type: 79 | packet->type = c; 80 | cksum_a = c; 81 | cksum_b = cksum_a; 82 | state = state_length; 83 | break; 84 | case state_length: 85 | length = c; 86 | cksum_a += c; 87 | cksum_b += cksum_a; 88 | step = 0; 89 | if (length > 0) 90 | state = state_data; 91 | else if (length > SYSLINK_MTU) 92 | state = state_first_start; 93 | else 94 | state = state_cksum1; 95 | break; 96 | case state_data: 97 | if (step < SYSLINK_MTU) 98 | { 99 | packet->data[step] = c; 100 | cksum_a += c; 101 | cksum_b += cksum_a; 102 | } 103 | step++; 104 | if(step >= length) { 105 | state = state_cksum1; 106 | } 107 | break; 108 | case state_cksum1: 109 | if (c == cksum_a) 110 | { 111 | state = state_cksum2; 112 | } 113 | else 114 | { // Wrong checksum 115 | state = state_first_start; 116 | } 117 | break; 118 | case state_cksum2: 119 | if (c == cksum_b) 120 | { 121 | packet->length = length; 122 | state = state_done; 123 | } 124 | else 125 | { // Wrong checksum 126 | state = state_first_start; 127 | step = 0; 128 | } 129 | break; 130 | case state_done: 131 | break; 132 | } 133 | } 134 | 135 | return (state == state_done); 136 | } 137 | 138 | bool syslinkSend(struct syslinkPacket *packet) 139 | { 140 | uint8_t cksum_a=0; 141 | uint8_t cksum_b=0; 142 | int i; 143 | 144 | uartPuts(START); 145 | 146 | uartPutc((unsigned char)packet->type); 147 | cksum_a += packet->type; 148 | cksum_b += cksum_a; 149 | 150 | uartPutc((unsigned char)packet->length); 151 | cksum_a += packet->length; 152 | cksum_b += cksum_a; 153 | 154 | for (i=0; i < packet->length; i++) 155 | { 156 | uartPutc(packet->data[i]); 157 | cksum_a += packet->data[i]; 158 | cksum_b += cksum_a; 159 | } 160 | 161 | uartPutc(cksum_a); 162 | uartPutc(cksum_b); 163 | 164 | return true; 165 | } 166 | -------------------------------------------------------------------------------- /src/syslink.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __PACKET_H__ 25 | #define __PACKET_H__ 26 | 27 | #include 28 | #include 29 | 30 | #define SYSLINK_MTU 32 31 | 32 | struct syslinkPacket { 33 | uint8_t type; 34 | uint8_t length; 35 | char data[SYSLINK_MTU]; 36 | }; 37 | 38 | bool syslinkReceive(struct syslinkPacket *packet); 39 | 40 | bool syslinkSend(struct syslinkPacket *packet); 41 | 42 | 43 | // Defined packet types 44 | #define SYSLINK_RADIO_RAW 0x00 45 | #define SYSLINK_RADIO_CHANNEL 0x01 46 | #define SYSLINK_RADIO_DATARATE 0x02 47 | 48 | 49 | #define SYSLINK_PM_SOURCE 0x10 50 | 51 | #define SYSLINK_PM_ONOFF_SWITCHOFF 0x11 52 | 53 | #define SYSLINK_PM_BATTERY_VOLTAGE 0x12 54 | #define SYSLINK_PM_BATTERY_STATE 0x13 55 | #define SYSLINK_PM_BATTERY_AUTOUPDATE 0x14 56 | 57 | #define SYSLINK_OW_SCAN 0x20 58 | #define SYSLINK_OW_READ 0x21 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/systick.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * 1ms systick timer 25 | */ 26 | #include 27 | 28 | static unsigned int tick = 0; 29 | 30 | //void RTC1_IRQHandler() 31 | void TIMER2_IRQHandler() 32 | { 33 | tick++; 34 | //NRF_RTC1->EVENTS_TICK = 0; 35 | NRF_TIMER2->EVENTS_COMPARE[0] = 0; 36 | } 37 | 38 | void systickInit() 39 | { 40 | // NRF_RTC1->PRESCALER = 327; //100Hz systick 41 | // NRF_RTC1->EVTENSET = RTC_EVTENSET_TICK_Msk; 42 | // NRF_RTC1->INTENSET = RTC_INTENSET_TICK_Msk; 43 | // NVIC_EnableIRQ(RTC1_IRQn); 44 | 45 | // NRF_RTC1->TASKS_START = 1UL; 46 | 47 | NRF_TIMER2->TASKS_CLEAR = 1; 48 | 49 | NRF_TIMER2->PRESCALER = 4; 50 | NRF_TIMER2->CC[0] = 1000; 51 | NRF_TIMER2->SHORTS = 1UL<INTENSET = (1UL << TIMER_INTENSET_COMPARE0_Pos); 53 | NVIC_EnableIRQ(TIMER2_IRQn); 54 | 55 | NRF_TIMER2->TASKS_START = 1; 56 | } 57 | 58 | unsigned int systickGetTick() 59 | { 60 | return tick; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/systick.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __SYSTICK_H__ 25 | #define __SYSTICK_H__ 26 | 27 | void systickInit(); 28 | 29 | unsigned int systickGetTick(); 30 | 31 | #endif //__SYSTICK_H__ 32 | -------------------------------------------------------------------------------- /src/timeslot.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 NRF Firmware 9 | * Copyright (c) 2014, Bitcraze AB, All rights reserved. 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * Nordic BLE stack timeslot management code 25 | */ 26 | #include 27 | #include 28 | #include "timeslot.h" 29 | 30 | #include "sdk_common.h" 31 | #include "nrf.h" 32 | #include "nrf_soc.h" 33 | 34 | #include "esb.h" 35 | 36 | #define NRF_LOG_MODULE_NAME "APP" 37 | #include "nrf_log.h" 38 | 39 | #define TIMESLOT_LEN_US 1000 40 | 41 | static nrf_radio_request_t timeslot_request = { 42 | .request_type = NRF_RADIO_REQ_TYPE_EARLIEST, 43 | .params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, 44 | .params.earliest.priority = NRF_RADIO_PRIORITY_NORMAL, 45 | .params.earliest.length_us = TIMESLOT_LEN_US, 46 | .params.earliest.timeout_us = 1000000, 47 | }; 48 | 49 | static nrf_radio_signal_callback_return_param_t * timeslot_callback(uint8_t signal_type) 50 | { 51 | static nrf_radio_signal_callback_return_param_t return_param; 52 | 53 | return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; 54 | 55 | switch (signal_type) 56 | { 57 | case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START: 58 | // Set up rescheduling 59 | NRF_TIMER0->INTENSET = (1UL << TIMER_INTENSET_COMPARE0_Pos); 60 | NRF_TIMER0->CC[0] = TIMESLOT_LEN_US - 800; 61 | NVIC_EnableIRQ(TIMER0_IRQn); 62 | 63 | esbInit(); 64 | 65 | #ifdef DEBUG_TIMESLOT 66 | NRF_GPIOTE->TASKS_OUT[0] = 1; 67 | #endif 68 | 69 | return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; 70 | break; 71 | case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: 72 | esbInterruptHandler(); 73 | 74 | //NRF_GPIOTE->TASKS_OUT[0] = 1; 75 | 76 | return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; 77 | break; 78 | case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0: 79 | if (NRF_TIMER0->EVENTS_COMPARE[0] == 1) 80 | { 81 | NRF_TIMER0->EVENTS_COMPARE[0] = 0; 82 | 83 | return_param.params.extend.length_us = TIMESLOT_LEN_US; 84 | return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND; 85 | } 86 | 87 | break; 88 | case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: 89 | 90 | esbDeinit(); 91 | 92 | #ifdef DEBUG_TIMESLOT 93 | NRF_GPIOTE->TASKS_OUT[0] = 1; 94 | #endif 95 | 96 | return_param.params.request.p_next = ×lot_request; 97 | return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END; 98 | break; 99 | case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: 100 | NRF_TIMER0->CC[0] += TIMESLOT_LEN_US; 101 | break; 102 | default: 103 | break; 104 | } 105 | 106 | return &return_param; 107 | } 108 | 109 | void timeslot_sd_evt_signal(uint32_t sys_evt) 110 | { 111 | switch (sys_evt) { 112 | case NRF_EVT_RADIO_BLOCKED: 113 | case NRF_EVT_RADIO_CANCELED: 114 | sd_radio_request(×lot_request); 115 | NRF_LOG_WARNING("Radio timeslot request blocked or canceled, asking again\n"); 116 | break; 117 | default: 118 | break; 119 | } 120 | } 121 | 122 | uint32_t timeslot_start(void) 123 | { 124 | uint32_t err_code; 125 | err_code = sd_radio_session_open(timeslot_callback); 126 | VERIFY_SUCCESS(err_code); 127 | 128 | err_code = sd_radio_request(×lot_request); 129 | VERIFY_SUCCESS(err_code); 130 | 131 | return NRF_SUCCESS; 132 | } 133 | -------------------------------------------------------------------------------- /src/timeslot.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 NRF Firmware 9 | * Copyright (c) 2014, Bitcraze AB, All rights reserved. 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | * 24 | * Nordic BLE stack timeslot management code 25 | */ 26 | #pragma once 27 | 28 | void timeslot_sd_evt_signal(uint32_t sys_evt); 29 | uint32_t timeslot_start(void); 30 | -------------------------------------------------------------------------------- /src/uart.c: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #include 25 | 26 | #include 27 | 28 | #include "boards.h" 29 | 30 | #include "uart.h" 31 | 32 | static bool isInit = false; 33 | 34 | #define Q_LENGTH 128 35 | 36 | static char rxq[Q_LENGTH]; 37 | static int head = 0; 38 | static int tail = 0; 39 | 40 | static int dropped = 0; 41 | static char dummy; 42 | 43 | int error = 0; 44 | 45 | void UART0_IRQHandler() { 46 | int nhead = head + 1; 47 | 48 | //if (NRF_UART0->ERRORSRC) { 49 | // error = NRF_UART0->ERRORSRC; 50 | // NRF_UART0->ERRORSRC = 0xFF; 51 | // __BKPT(0); 52 | // } 53 | 54 | NRF_UART0->EVENTS_RXDRDY = 0; 55 | 56 | // Check if the queue is not full 57 | if (nhead >= Q_LENGTH) nhead = 0; 58 | if (nhead == tail) { 59 | dummy = NRF_UART0->RXD; //Read anyway to avoid hw overflow 60 | dropped++; 61 | return; 62 | } 63 | 64 | // Push data in queue 65 | rxq[head++] = NRF_UART0->RXD; 66 | if (head >= Q_LENGTH) head = 0; 67 | } 68 | 69 | void uartInit() { 70 | NRF_GPIO->PIN_CNF[TX_PIN_NUMBER] = (NRF_GPIO->PIN_CNF[TX_PIN_NUMBER] & (~GPIO_PIN_CNF_DRIVE_Msk)) | (GPIO_PIN_CNF_DRIVE_S0S1<DIRSET = 1 << TX_PIN_NUMBER; 73 | NRF_GPIO->OUTSET = 1 << TX_PIN_NUMBER; 74 | NRF_UART0->PSELTXD = TX_PIN_NUMBER; 75 | 76 | NRF_GPIO->DIRCLR = 1 << RX_PIN_NUMBER; 77 | NRF_UART0->PSELRXD = RX_PIN_NUMBER; 78 | 79 | NRF_GPIO->DIRSET = 1 << RTS_PIN_NUMBER; 80 | NRF_GPIO->OUTSET = 1 << RTS_PIN_NUMBER; 81 | NRF_UART0->PSELRTS = RTS_PIN_NUMBER; 82 | 83 | NRF_UART0->CONFIG = UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos; 84 | 85 | NRF_UART0->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1M; 86 | 87 | NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; 88 | 89 | NRF_UART0->TASKS_STARTTX = 1; 90 | 91 | // Enable interrupt on receive 92 | NVIC_EnableIRQ(UART0_IRQn); 93 | NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk; 94 | 95 | NRF_UART0->TASKS_STARTRX = 1; 96 | 97 | isInit = true; 98 | } 99 | 100 | void uartPuts(char* string) { 101 | if (!isInit) 102 | return; 103 | 104 | while (*string) 105 | uartPutc(*string++); 106 | } 107 | 108 | void uartSend(char* data, int len) { 109 | if (!isInit) 110 | return; 111 | 112 | while (len--) 113 | uartPutc(*data++); 114 | 115 | } 116 | 117 | void uartPutc(char c) { 118 | if (!isInit) 119 | return; 120 | 121 | NRF_UART0->TXD = c; 122 | while (!NRF_UART0->EVENTS_TXDRDY); 123 | NRF_UART0->EVENTS_TXDRDY = 0; 124 | } 125 | 126 | bool uartIsDataReceived() { 127 | if (!isInit) 128 | return false; 129 | 130 | return head!=tail; 131 | } 132 | 133 | char uartGetc() { 134 | char c = 0; 135 | 136 | if (!isInit) 137 | return c; 138 | 139 | if (head != tail) { 140 | c = rxq[tail++]; 141 | if (tail >= Q_LENGTH) tail = 0; 142 | } 143 | 144 | return c; 145 | } 146 | -------------------------------------------------------------------------------- /src/uart.h: -------------------------------------------------------------------------------- 1 | /** 2 | * || ____ _ __ 3 | * +------+ / __ )(_) /_______________ _____ ___ 4 | * | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ 5 | * +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ 6 | * || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ 7 | * 8 | * Crazyflie 2.0 nRF51 Bootloader 9 | * Copyright (c) 2014, Bitcraze AB 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 3.0 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library. 23 | */ 24 | #ifndef __UART_H__ 25 | #define __UART_H__ 26 | 27 | #include 28 | 29 | void uartInit(); 30 | 31 | void uartPuts(char* string); 32 | 33 | void uartSend(char* data, int len); 34 | 35 | void uartPutc(char c); 36 | 37 | bool uartIsDataReceived(); 38 | 39 | char uartGetc(); 40 | 41 | #endif //__UART_H__ 42 | -------------------------------------------------------------------------------- /tools/build/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | tools/build/fetch-dependencies 4 | 5 | make -------------------------------------------------------------------------------- /tools/build/build-update-binary: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | tools/build/build 4 | 5 | python3 tools/generate_update_binary.py -------------------------------------------------------------------------------- /tools/build/fetch-dependencies: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env bash 3 | 4 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | ROOT_DIR=$SCRIPT_DIR/../.. 6 | pushd $ROOT_DIR 7 | 8 | mkdir -p vendor 9 | cd vendor 10 | 11 | echo "9eb8b18c140135ab05066ad7394260f95413cb6cb403c623d389d131ceb5e381 nrf5sdk1230.zip" | sha256sum -c - 12 | 13 | # Download if file not correct 14 | if [ $? -ne 0 ]; then 15 | echo "Downloading nrf5sdk1230.zip" 16 | rm -f nrf5sdk1230.zip 17 | wget https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/sdks/nrf5/binaries/nrf5sdk1230.zip 18 | fi 19 | 20 | # Unzip the SDK making sure we have a clean copy 21 | rm -rf nrf5sdk 22 | mkdir -p nrf5sdk 23 | unzip -o nrf5sdk1230.zip -d nrf5sdk 24 | mv nrf5sdk/nRF5_SDK_12.3.0_d7731ad/* nrf5sdk 25 | rmdir nrf5sdk/nRF5_SDK_12.3.0_d7731ad 26 | 27 | # convert line endings to unix 28 | mv nrf5sdk/components/toolchain/gcc/Makefile.posix nrf5sdk/components/toolchain/gcc/Makefile.posix.orig 29 | tr -d '\r' < nrf5sdk/components/toolchain/gcc/Makefile.posix.orig > nrf5sdk/components/toolchain/gcc/Makefile.posix 30 | mv nrf5sdk/components/libraries/mailbox/app_mailbox.c nrf5sdk/components/libraries/mailbox/app_mailbox.c.orig 31 | tr -d '\r' < nrf5sdk/components/libraries/mailbox/app_mailbox.c.orig > nrf5sdk/components/libraries/mailbox/app_mailbox.c 32 | mv nrf5sdk/components/toolchain/cmsis/include/cmsis_gcc.h nrf5sdk/components/toolchain/cmsis/include/cmsis_gcc.h.orig 33 | tr -d '\r' < nrf5sdk/components/toolchain/cmsis/include/cmsis_gcc.h.orig > nrf5sdk/components/toolchain/cmsis/include/cmsis_gcc.h 34 | # Patch SDK compiler configuration 35 | patch -p0 < $ROOT_DIR/tools/nrf5sdk.patch 36 | 37 | popd 38 | -------------------------------------------------------------------------------- /tools/build/generateVersionHeader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | #!/usr/bin/env python 4 | 5 | import argparse 6 | import os 7 | import subprocess 8 | 9 | version = {} 10 | 11 | 12 | def extract_information_from_git(base): 13 | revision = ( 14 | subprocess.check_output(["git", "-C", base, "rev-parse", "HEAD"]) 15 | .decode("utf-8") 16 | .strip() 17 | ) 18 | 19 | version["revision"] = revision[0:12] 20 | version["irevision0"] = "0x" + revision[0:8] 21 | version["irevision1"] = "0x" + revision[8:12] 22 | version["productionRelease"] = "false" 23 | 24 | try: 25 | identify = subprocess.check_output( 26 | ["git", "-C", base, "describe", "--abbrev=12", "--tags", "HEAD"] 27 | ).decode("utf-8") 28 | identify = identify.split("-") 29 | 30 | if len(identify) > 2: 31 | version["local_revision"] = identify[len(identify) - 2] 32 | else: 33 | version["local_revision"] = "0" 34 | 35 | version["tag"] = identify[0] 36 | for x in range(1, len(identify) - 2): 37 | version["tag"] += "-" 38 | version["tag"] += identify[x] 39 | except subprocess.CalledProcessError: 40 | # We are maybe running from a shallow tree 41 | version["local_revision"] = "0" 42 | version["tag"] = "NA" 43 | 44 | version["tag"] = version["tag"].strip() 45 | 46 | if version["local_revision"] != "0": 47 | version["tag"] = version["tag"] + " +" + version["local_revision"] 48 | 49 | branch = ( 50 | subprocess.check_output( 51 | ["git", "-C", base, "rev-parse", "--abbrev-ref", "HEAD"] 52 | ) 53 | .decode("utf-8") 54 | .strip() 55 | ) 56 | version["branch"] = branch 57 | 58 | subprocess.call(["git", "-C", base, "update-index", "-q", "--refresh"]) 59 | changes = ( 60 | subprocess.check_output( 61 | ["git", "-C", base, "diff-index", "--name-only", "HEAD", "--"] 62 | ) 63 | .decode("utf-8") 64 | .strip() 65 | ) 66 | if len(changes): 67 | version["modified"] = "true" 68 | else: 69 | version["modified"] = "false" 70 | 71 | 72 | def generate_numeral_version(): 73 | vnum = version["tag"].split('+')[0].split('RC')[0].split('.') 74 | 75 | version["major"] = int(vnum[0]) if len(vnum) > 0 and vnum[0] != "NA" else 0 76 | version["minor"] = int(vnum[1]) if len(vnum) > 1 else 0 77 | version["patch"] = int(vnum[2]) if len(vnum) > 2 else 0 78 | 79 | version["dirty"] = "true" if version["modified"] == "true" or '+' in version["tag"] or 'RC' in version["tag"] else "false" 80 | 81 | 82 | if __name__ == "__main__": 83 | parser = argparse.ArgumentParser() 84 | parser.add_argument( 85 | "--crazyflie-base", 86 | help="base folder of the crazyflie firmware", 87 | action="store", 88 | default="./", 89 | ) 90 | parser.add_argument( 91 | "--output", help="name of output header", action="store", default="Include/version.h" 92 | ) 93 | args = parser.parse_args() 94 | 95 | extract_information_from_git(args.crazyflie_base) 96 | 97 | generate_numeral_version() 98 | 99 | dirtymark = '+' if version["dirty"] else '' 100 | print(f'Version {version["major"]}.{version["minor"]}.{version["patch"]}{dirtymark}') 101 | 102 | with open(os.path.join(args.crazyflie_base, args.output), 'w') as fd: 103 | fd.writelines( 104 | ['#include \n', 105 | '\n', 106 | f'#define VERSION_MAJOR {version["major"]}\n', 107 | f'#define VERSION_MINOR {version["minor"]}\n', 108 | f'#define VERSION_PATCH {version["patch"]}\n', 109 | f'#define VERSION_DIRTY {version["dirty"]}\n',] 110 | ) 111 | -------------------------------------------------------------------------------- /tools/debug/send_syslink.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Small script to stress the syslink RX state machine to see if it works well 4 | 5 | import serial 6 | import struct 7 | 8 | nrf = serial.Serial("/dev/ttyACM0", 1000000, rtscts=True) 9 | 10 | def send_packet(header: int, data: bytes): 11 | packet = bytearray() 12 | 13 | packet.extend(b"\xbc\xcf") 14 | packet.extend(struct.pack("