diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..2cd0e1554 --- /dev/null +++ b/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: false +AlignEscapedNewlines: LeftWithLastLine +AlignOperands: true +AlignTrailingComments: + Kind: Always + OverEmptyLines: 2 +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: true + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BracedInitializerIndentWidth: 2 +BreakBeforeBinaryOperators: None +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ContinuationIndentWidth: 2 +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentPPDirectives: BeforeHash +InsertBraces: true +IndentCaseLabels: true +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +PenaltyBreakBeforeFirstCallParameter: 1000000 +PenaltyBreakOpenParenthesis: 1000000 +PPIndentWidth: 2 +QualifierAlignment: Custom +QualifierOrder: ['static', 'const', 'volatile', 'restrict', 'type'] +SpaceAfterTemplateKeyword: false +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SortIncludes: false +TabWidth: 2 +... diff --git a/.gitignore b/.gitignore index b38e865b5..bc5ad7f61 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,7 @@ dkms.conf segger/Output _build/ -_bin/ +cmake-build-*/ bin/ *.emSession *.jlink @@ -67,7 +67,9 @@ TAGS .DS_Store Makefile.user -# Python virtual environments +# Exclude all SoftDevice S340 files +lib/softdevice/s340* +_bin/ venv/ .python-version lib/python3.13/ diff --git a/.gitmodules b/.gitmodules index bd80adc1b..f8d402389 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ path = lib/uf2 url = https://github.com/microsoft/uf2.git +[submodule "lib/tinycrypt"] + path = lib/tinycrypt + url = https://github.com/intel/tinycrypt diff --git a/CMakeLists.txt b/CMakeLists.txt index 567a815af..58238bf28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,11 @@ cmake_minimum_required(VERSION 3.17) +include(CMakePrintHelpers) find_package(Python COMPONENTS Interpreter) if (NOT DEFINED BOARD) message(FATAL_ERROR "BOARD is not defined") endif () -if (NOT DEFINED TOOLCHAIN) - set(TOOLCHAIN gcc) -endif () - # include board specific include(${CMAKE_CURRENT_LIST_DIR}/src/boards/${BOARD}/board.cmake) @@ -21,15 +18,22 @@ else () set(JLINK_DEVICE ${MCU_VARIANT}_xxaa) endif () -set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/arm_${TOOLCHAIN}.cmake) - -project(Adafruit_nRF52_Bootloader C ASM) +include(${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/arm_gcc.cmake) set(NRFX_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/nrfx) set(SDK11_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/sdk11/components) set(SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/sdk/components) set(SOFTDEVICE_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/softdevice) +set(MBR_HEX ${SOFTDEVICE_DIR}/mbr/hex/mbr_nrf52_2.4.1_mbr.hex) set(TINYUSB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinyusb/src) +set(TCRYPT_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinycrypt/lib) + +option(DEFAULT_TO_OTA_DFU "Default to OTA DFU instead of Serial DFU" OFF) +option(SIGNED_FW "Enable signed firmware verification" OFF) +option(DUALBANK_FW "Enable dual bank DFU support" OFF) +option(FORCE_UF2 "Force UF2 support even with SIGNED_FW" OFF) +set(SIGNED_FW_QX "" CACHE STRING "Public key Qx (comma-separated bytes)") +set(SIGNED_FW_QY "" CACHE STRING "Public key Qy (comma-separated bytes)") set(UF2CONV_PY ${CMAKE_CURRENT_LIST_DIR}/lib/uf2/utils/uf2conv.py) set(UF2_FAMILY_ID_BOOTLOADER 0xd663823c) @@ -37,21 +41,13 @@ set(UF2_FAMILY_ID_BOOTLOADER 0xd663823c) #------------------- # Bootloader #------------------- -set(CMAKE_EXECUTABLE_SUFFIX .elf) -add_executable(bootloader) - -# SD_VERSION can be overwritten by board.cmake -if(NOT DEFINED SD_VERSION) - if(MCU_VARIANT STREQUAL "nrf52833") - set(SD_VERSION 7.3.0) - else() - set(SD_VERSION 6.1.1) - endif() +if (NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Build type" FORCE) endif () -set(MBR_HEX ${SOFTDEVICE_DIR}/mbr/hex/mbr_nrf52_2.4.1_mbr.hex) - -target_sources(bootloader PUBLIC +project(Adafruit_nRF52_Bootloader C ASM) +set(CMAKE_EXECUTABLE_SUFFIX .elf) +add_executable(bootloader # src src/dfu_ble_svc.c src/dfu_init.c @@ -70,7 +66,6 @@ target_sources(bootloader PUBLIC ${SDK11_DIR}/libraries/bootloader_dfu/bootloader_util.c ${SDK11_DIR}/libraries/bootloader_dfu/dfu_transport_serial.c ${SDK11_DIR}/libraries/bootloader_dfu/dfu_transport_ble.c - ${SDK11_DIR}/libraries/bootloader_dfu/dfu_single_bank.c ${SDK11_DIR}/ble/ble_services/ble_dfu/ble_dfu.c ${SDK11_DIR}/ble/ble_services/ble_dis/ble_dis.c ${SDK11_DIR}/drivers_nrf/pstorage/pstorage_raw.c @@ -84,9 +79,33 @@ target_sources(bootloader PUBLIC ${SDK_DIR}/libraries/hci/hci_slip.c ${SDK_DIR}/libraries/hci/hci_transport.c ${SDK_DIR}/libraries/util/nrf_assert.c - # ASM + # startup ${NRFX_DIR}/mdk/gcc_startup_${MCU_VARIANT}.S ) + +if (DUALBANK_FW) + target_sources(bootloader PUBLIC + ${SDK11_DIR}/libraries/bootloader_dfu/dfu_dual_bank.c + ) +else () + target_sources(bootloader PUBLIC + ${SDK11_DIR}/libraries/bootloader_dfu/dfu_single_bank.c + ) +endif () + +if (SIGNED_FW) + target_sources(bootloader PUBLIC + ${TCRYPT_DIR}/source/sha256.c + ${TCRYPT_DIR}/source/ecc.c + ${TCRYPT_DIR}/source/ecc_dsa.c + ${TCRYPT_DIR}/source/utils.c + ) + + target_include_directories(bootloader PUBLIC + ${TCRYPT_DIR}/include + ) +endif () + target_include_directories(bootloader PUBLIC src src/boards @@ -120,29 +139,9 @@ target_include_directories(bootloader PUBLIC ${SOFTDEVICE_DIR}/mbr/headers ) -# Debug option +# Debug linker file if (CMAKE_BUILD_TYPE STREQUAL "Debug") - # TODO not work yet, also need to add segger rtt, DFU_APP_DATA_RESERVED=0, BOOTLOADER_REGION_START=0xED000 set(LD_FILE ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}_debug.ld) - - target_sources(bootloader PUBLIC - lib/SEGGER_RTT/RTT/SEGGER_RTT.c - ) - target_include_directories(bootloader PUBLIC - lib/SEGGER_RTT/RTT - ) - - target_compile_definitions(bootloader PUBLIC - CFG_DEBUG - SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL - DFU_APP_DATA_RESERVED=0 - ) - - if (MCU_VARIANT STREQUAL "nrf52840") - target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0xEA000) - else () - target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0x6D000) - endif () else () set(LD_FILE ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}.ld) endif () @@ -150,6 +149,7 @@ endif () target_link_options(bootloader PUBLIC "LINKER:--script=${LD_FILE}" -L${NRFX_DIR}/mdk + -nostartfiles --specs=nosys.specs --specs=nano.specs ) target_compile_options(bootloader PUBLIC @@ -175,8 +175,32 @@ target_compile_options(bootloader PUBLIC ) target_compile_definitions(bootloader PUBLIC SOFTDEVICE_PRESENT + CONFIG_GPIO_AS_PINRESET + __START=main + __STARTUP_CLEAR_BSS ) +if (SIGNED_FW) + if (SIGNED_FW_QX STREQUAL "" OR SIGNED_FW_QY STREQUAL "") + message(FATAL_ERROR "SIGNED_FW requires SIGNED_FW_QX and SIGNED_FW_QY to be set") + endif () + string(REPLACE " " "" SIGNED_FW_QX_STR "${SIGNED_FW_QX}") + string(REPLACE " " "" SIGNED_FW_QY_STR "${SIGNED_FW_QY}") + target_compile_definitions(bootloader PUBLIC + SIGNED_FW + "SIGNED_FW_QX=${SIGNED_FW_QX_STR}" + "SIGNED_FW_QY=${SIGNED_FW_QY_STR}" + ) +endif () + +if (FORCE_UF2) + target_compile_definitions(bootloader PUBLIC FORCE_UF2) +endif () + +if (DEFAULT_TO_OTA_DFU) + target_compile_definitions(bootloader PUBLIC DEFAULT_TO_OTA_DFU) +endif () + if (TRACE_ETM STREQUAL "1") # ENABLE_TRACE will cause system_nrf5x.c to set up ETM trace target_compile_definitions(bootloader PUBLIC ENABLE_TRACE) @@ -217,32 +241,36 @@ endif () # MCU Variant differences # Supported are: nrf52 (nrf52832), nrf52833, nrf52840 #---------------------------------------------------- + +# SD_VERSION can be overwritten by board.cmake +if(NOT DEFINED SD_VERSION) + if(MCU_VARIANT STREQUAL "nrf52833") + set(SD_VERSION 7.3.0) + else() + set(SD_VERSION 6.1.1) + endif() +endif () + if (MCU_VARIANT STREQUAL "nrf52") set(SD_NAME s132) set(DFU_DEV_REV 0xADAF) set(DFU_APP_DATA_RESERVED 7*4096) - target_compile_definitions(bootloader PUBLIC - NRF52 - NRF52832_XXAA - S132 - ) + target_compile_definitions(bootloader PUBLIC NRF52 NRF52832_XXAA) elseif (MCU_VARIANT STREQUAL "nrf52833") - set(SD_NAME s140) set(DFU_DEV_REV 52833) set(DFU_APP_DATA_RESERVED 7*4096) - target_compile_definitions(bootloader PUBLIC - NRF52833_XXAA - S140 - ) + target_compile_definitions(bootloader PUBLIC NRF52833_XXAA) + if (NOT DEFINED SD_NAME) + set(SD_NAME s140) + endif () elseif (MCU_VARIANT STREQUAL "nrf52840") - set(SD_NAME s140) set(DFU_DEV_REV 52840) # App reserved 40KB (8+32) to match circuitpython for 840 set(DFU_APP_DATA_RESERVED 10*4096) - target_compile_definitions(bootloader PUBLIC - NRF52840_XXAA - S140 - ) + target_compile_definitions(bootloader PUBLIC NRF52840_XXAA) + if (NOT DEFINED SD_NAME) + set(SD_NAME s140) + endif () else () message(FATAL_ERROR "MCU_VARIANT ${MCU_VARIANT} is unknown") endif () @@ -250,53 +278,69 @@ endif () set(SD_FILENAME ${SD_NAME}_nrf52_${SD_VERSION}) set(SD_HEX ${SOFTDEVICE_DIR}/${SD_FILENAME}/${SD_FILENAME}_softdevice.hex) +string(TOUPPER ${SD_NAME} SD_NAME_UPPER) +target_compile_definitions(bootloader PUBLIC ${SD_NAME_UPPER}) target_include_directories(bootloader PUBLIC ${SOFTDEVICE_DIR}/${SD_FILENAME}/${SD_FILENAME}_API/include ) -if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") +# debug build +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + # TODO not work yet, also need to add segger rtt, DFU_APP_DATA_RESERVED=0, BOOTLOADER_REGION_START=0xED000 + target_sources(bootloader PUBLIC lib/SEGGER_RTT/RTT/SEGGER_RTT.c) + target_include_directories(bootloader PUBLIC lib/SEGGER_RTT/RTT) + target_compile_definitions(bootloader PUBLIC + CFG_DEBUG + SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL + DFU_APP_DATA_RESERVED=0 + ) + if (MCU_VARIANT STREQUAL "nrf52840") + target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0xEA000) + else () + target_compile_definitions(bootloader PUBLIC BOOTLOADER_REGION_START=0x6D000) + endif () +else () target_compile_definitions(bootloader PUBLIC DFU_APP_DATA_RESERVED=${DFU_APP_DATA_RESERVED}) endif () +#---------------------------------- +# ANT_LICENSE_KEY handling +#---------------------------------- +if (DEFINED ANT_LICENSE_KEY) + target_compile_definitions(bootloader PUBLIC ANT_LICENSE_KEY=${ANT_LICENSE_KEY}) +endif() + #---------------------------------- # Get UF2 version from git #---------------------------------- execute_process(COMMAND git describe --dirty --always --tags OUTPUT_VARIABLE GIT_VERSION) string(STRIP ${GIT_VERSION} GIT_VERSION) -execute_process(COMMAND bash "-c" "git submodule status | cut -d\" \" -f3,4 | paste -s -d\" \" -" - OUTPUT_VARIABLE GIT_SUBMODULE_VERSIONS - ) -string(STRIP ${GIT_SUBMODULE_VERSIONS} GIT_SUBMODULE_VERSIONS) -string(REPLACE ../ "" GIT_SUBMODULE_VERSIONS ${GIT_SUBMODULE_VERSIONS}) -string(REPLACE lib/ "" GIT_SUBMODULE_VERSIONS ${GIT_SUBMODULE_VERSIONS}) - -string(REPLACE "-" ";" RELEASE_VERSION ${GIT_VERSION}) -list(GET RELEASE_VERSION 0 RELEASE_VERSION) -string(REPLACE "." ";" RELEASE_VERSION ${RELEASE_VERSION}) -list(GET RELEASE_VERSION 0 RELEASE_VERSION_MAJOR) -list(GET RELEASE_VERSION 1 RELEASE_VERSION_MINOR) -list(GET RELEASE_VERSION 2 RELEASE_VERSION_PATCH) -math(EXPR MK_BOOTLOADER_VERSION "(${RELEASE_VERSION_MAJOR} << 16) + (${RELEASE_VERSION_MINOR} << 8) + ${RELEASE_VERSION_PATCH}") +# Extract semantic version numbers (MAJOR.MINOR.PATCH) from GIT_VERSION. +# Supports tags like: +# v1.2.3 +# 1.2.3 +# 1.2.3-147-gd71abcd +# If the version string does not match MAJOR.MINOR.PATCH, defaults to 0.0.0. +if(GIT_VERSION MATCHES "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(RELEASE_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(RELEASE_VERSION_MINOR ${CMAKE_MATCH_2}) + set(RELEASE_VERSION_PATCH ${CMAKE_MATCH_3}) +else() + set(RELEASE_VERSION_MAJOR 0) + set(RELEASE_VERSION_MINOR 0) + set(RELEASE_VERSION_PATCH 0) +endif() +math(EXPR MK_BOOTLOADER_VERSION "((${RELEASE_VERSION_MAJOR} << 16) | (${RELEASE_VERSION_MINOR} << 8) | ${RELEASE_VERSION_PATCH})") -cmake_print_variables(GIT_VERSION GIT_SUBMODULE_VERSIONS MK_BOOTLOADER_VERSION) +cmake_print_variables(GIT_VERSION MK_BOOTLOADER_VERSION) target_compile_definitions(bootloader PUBLIC - UF2_VERSION_BASE="${GIT_VERSION}" - UF2_VERSION="${GIT_VERSION} - ${GIT_SUBMODULE_VERSIONS}" + UF2_VERSION="${GIT_VERSION}" BLEDIS_FW_VERSION="${GIT_VERSION} ${SD_NAME} ${SD_VERSION}" MK_BOOTLOADER_VERSION=${MK_BOOTLOADER_VERSION} ) -#---------------------------------- -# Post build -#---------------------------------- - -# run size after build -add_custom_command(TARGET bootloader POST_BUILD - COMMAND ${CMAKE_SIZE} $ - ) - # Add bin/hex output add_custom_command(TARGET bootloader POST_BUILD COMMAND ${CMAKE_OBJCOPY} -Obinary $ $/bootloader.bin @@ -308,12 +352,11 @@ add_custom_command(TARGET bootloader POST_BUILD #---------------------------------- # Flashing target #---------------------------------- - if (NOT DEFINED NRFJPROG) set(NRFJPROG nrfjprog) endif() -add_custom_target(flash-jlink +add_custom_target(flash-bootloader DEPENDS bootloader COMMAND ${NRFJPROG} --program $ --verify --sectoranduicrerase -f nrf52 --reset ) @@ -324,13 +367,27 @@ add_custom_target(flash-uf2 ) add_custom_target(flash-sd - COMMAND ${NRFJPROG} --program ${SD_HEX} --verify --sectorerase -f nrf52 --reset + DEPENDS flash-mbr + COMMAND ${NRFJPROG} --program ${SD_HEX} --verify --sectorerase -f nrf52 ) add_custom_target(flash-mbr - COMMAND ${NRFJPROG} --program ${MBR_HEX} --verify --sectorerase -f nrf52 --reset + COMMAND ${NRFJPROG} --program ${MBR_HEX} --verify --sectorerase -f nrf52 ) add_custom_target(flash-erase COMMAND ${NRFJPROG} -f nrf52 --eraseall - ) \ No newline at end of file + ) + +add_custom_target(flash-all + DEPENDS bootloader flash-erase + COMMAND ${NRFJPROG} --program ${SD_HEX} --verify --sectorerase -f nrf52 + COMMAND ${NRFJPROG} --program $ --verify --sectoranduicrerase -f nrf52 --reset + ) + +# flash skip crc magic ( app valid = 0x0001, crc = 0x0000 ) +#add_custom_target(flash-skip-crc +# #COMMAND ${NRFJPROG} --memwr $(BOOT_SETTING_ADDR) --val 0x00000001 -f nrf52 +# COMMAND ${NRFJPROG} --memwr 0xFF000 --val 0x00000001 -f nrf52 +# #COMMAND ${NRFJPROG} --memwr 0x7F000 --val 0x00000001 -f nrf52 +# ) diff --git a/Makefile b/Makefile index 829eb511b..8f1bb721d 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,20 @@ #------------------------------------------------------------------------------ # CONFIGURE -# - SDK_PATH : path to SDK directory +# - SDK_PATH : path to SDK directory # -# - SD_NAME : e.g s132, s140 -# - SD_VERSION : SoftDevice version e.g 6.0.0 -# - SD_HEX : to bootloader hex binary +# - SD_NAME : e.g s132, s140 +# - SD_VERSION : SoftDevice version e.g 6.0.0 +# - SD_HEX : to bootloader hex binary +# - SIGNED_FW : if bootloader will ONLY accept signed firmware +# - SIGNED_FW_QX : Qx for signed firmware verification +# - SIGNED_FW_QY : Qy for signed firmware verification +# - DUALBANK_FW : If bootloader will implement a dual bank feature to allow autorecover from failed +# - FORCE_UF2 : if SIGNED_FW is 1, will force to include UF2 support (UNSECURE, UF2 does NOT validate signature!) +# - DEFAULT_TO_OTA_DFU : if entering DFU, by default enter OTA DFU instead of Serial DFU #------------------------------------------------------------------------------ +PYTHON = python + # local customization -include Makefile.user @@ -16,6 +24,7 @@ SDK_PATH = lib/sdk/components SDK11_PATH = lib/sdk11/components TUSB_PATH = lib/tinyusb/src +TCRYPT_PATH = lib/tinycrypt/lib NRFX_PATH = lib/nrfx SD_PATH = lib/softdevice/$(SD_FILENAME) @@ -33,6 +42,15 @@ SD_HEX = $(SD_PATH)/$(SD_FILENAME)_softdevice.hex MBR_HEX = lib/softdevice/mbr/hex/mbr_nrf52_2.4.1_mbr.hex +# Detect the operating system +# The "OS" environment variable on Windows is always "Windows_NT" +# when running under a modern shell like cmd.exe or powershell +ifeq ($(OS),Windows_NT) + NULL_DEVICE = NUL +else + NULL_DEVICE = /dev/null +endif + # linker by MCU eg. nrf52840.ld ifeq ($(DEBUG), 1) LD_FILE = linker/$(MCU_SUB_VARIANT)_debug.ld @@ -40,8 +58,8 @@ else LD_FILE = linker/$(MCU_SUB_VARIANT).ld endif -GIT_VERSION := $(shell git describe --dirty --always --tags) GIT_SUBMODULE_VERSIONS := $(shell git submodule status | cut -d" " -f3,4 | paste -s -d" " -) +GIT_VERSION := $(shell git describe --dirty --always --tags) # compiled file name OUT_NAME = $(BOARD)_bootloader-$(GIT_VERSION) @@ -104,25 +122,39 @@ BIN = _bin/$(BOARD) # MCU_SUB_VARIANT can be nrf52 (nrf52832), nrf52833, nrf52840 ifeq ($(MCU_SUB_VARIANT),nrf52) + CFLAGS += -DNRF52 -DNRF52832_XXAA SD_NAME = s132 DFU_DEV_REV = 0xADAF - CFLAGS += -DNRF52 -DNRF52832_XXAA -DS132 DFU_APP_DATA_RESERVED=7*4096 else ifeq ($(MCU_SUB_VARIANT),nrf52833) - SD_NAME = s140 + CFLAGS += -DNRF52833_XXAA DFU_DEV_REV = 52833 - CFLAGS += -DNRF52833_XXAA -DS140 DFU_APP_DATA_RESERVED=7*4096 + ifndef SD_NAME + SD_NAME = s140 + endif else ifeq ($(MCU_SUB_VARIANT),nrf52840) - SD_NAME = s140 + CFLAGS += -DNRF52840_XXAA DFU_DEV_REV = 52840 - CFLAGS += -DNRF52840_XXAA -DS140 # App reserved 40KB (8+32) to match circuitpython for 840 DFU_APP_DATA_RESERVED=10*4096 + ifndef SD_NAME + SD_NAME = s140 + endif else $(error Sub Variant $(MCU_SUB_VARIANT) is unknown) endif +SD_NAME_UPPER = $(subst s,S,${SD_NAME}) +CFLAGS += -D$(SD_NAME_UPPER) + +#---------------------------------- +# ANT_LICENSE_KEY handling +#---------------------------------- +ifdef ANT_LICENSE_KEY + CFLAGS += -DANT_LICENSE_KEY=\"$(ANT_LICENSE_KEY)\" +endif + #------------------------------------------------------------------------------ # SOURCE FILES #------------------------------------------------------------------------------ @@ -136,6 +168,15 @@ C_SRC += \ src/screen.c \ src/images.c \ +# if using a signed firmware +ifeq ($(SIGNED_FW), 1) +C_SRC += \ + $(TCRYPT_PATH)/source/sha256.c \ + $(TCRYPT_PATH)/source/ecc.c \ + $(TCRYPT_PATH)/source/ecc_dsa.c \ + $(TCRYPT_PATH)/source/utils.c +endif + # all files in boards C_SRC += src/boards/boards.c @@ -150,7 +191,11 @@ C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/bootloader_settings.c C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/bootloader_util.c C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/dfu_transport_serial.c C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/dfu_transport_ble.c +ifeq ($(DUALBANK_FW), 1) +C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/dfu_dual_bank.c +else C_SRC += $(SDK11_PATH)/libraries/bootloader_dfu/dfu_single_bank.c +endif C_SRC += $(SDK11_PATH)/ble/ble_services/ble_dfu/ble_dfu.c C_SRC += $(SDK11_PATH)/ble/ble_services/ble_dis/ble_dis.c C_SRC += $(SDK11_PATH)/drivers_nrf/pstorage/pstorage_raw.c @@ -184,22 +229,23 @@ C_SRC += src/boards/$(BOARD)/pinconfig.c # USB Application ( MSC + UF2 ) C_SRC += \ - src/usb/msc_uf2.c \ src/usb/usb_desc.c \ - src/usb/usb.c \ - src/usb/uf2/ghostfat.c + src/usb/msc_uf2.c \ + src/usb/uf2/ghostfat.c \ + src/usb/usb.c # TinyUSB stack C_SRC += \ $(TUSB_PATH)/portable/nordic/nrf5x/dcd_nrf5x.c \ $(TUSB_PATH)/common/tusb_fifo.c \ $(TUSB_PATH)/device/usbd.c \ + $(TUSB_PATH)/device/usbd_control.c \ $(TUSB_PATH)/class/cdc/cdc_device.c \ $(TUSB_PATH)/class/msc/msc_device.c \ $(TUSB_PATH)/tusb.c - endif + #------------------------------------------------------------------------------ # Assembly Files #------------------------------------------------------------------------------ @@ -218,6 +264,11 @@ IPATH += \ src/usb \ $(TUSB_PATH) +ifeq ($(SIGNED_FW), 1) +IPATH += \ + $(TCRYPT_PATH)/include +endif + # nrfx IPATH += \ $(NRFX_PATH) \ @@ -313,8 +364,39 @@ CFLAGS += -DUF2_VERSION_BASE='"$(GIT_VERSION)"' CFLAGS += -DUF2_VERSION='"$(GIT_VERSION) $(GIT_SUBMODULE_VERSIONS)"' CFLAGS += -DBLEDIS_FW_VERSION='"$(GIT_VERSION) $(SD_NAME) $(SD_VERSION)"' -_VER = $(subst ., ,$(word 1, $(subst -, ,$(GIT_VERSION)))) -CFLAGS += -DMK_BOOTLOADER_VERSION='($(word 1,$(_VER)) << 16) + ($(word 2,$(_VER)) << 8) + $(word 3,$(_VER))' +ifeq ($(SIGNED_FW), 1) +CFLAGS += -DSIGNED_FW +CFLAGS += -DSIGNED_FW_QX='$(SIGNED_FW_QX)' +CFLAGS += -DSIGNED_FW_QY='$(SIGNED_FW_QY)' +endif + +ifeq ($(FORCE_UF2), 1) +CFLAGS += -DFORCE_UF2 +endif + +ifeq ($(DEFAULT_TO_OTA_DFU), 1) +CFLAGS += -DDEFAULT_TO_OTA_DFU +endif + +# Extract semantic version numbers (MAJOR.MINOR.PATCH) from GIT_VERSION. +# Supports tags like: +# v1.2.3 +# 1.2.3 +# 1.2.3-147-gd71abcd +# If the version string does not match MAJOR.MINOR.PATCH, defaults to 0.0.0. +_VER3 := $(shell echo "$(GIT_VERSION)" | sed -E 's/^v?([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 \2 \3/; t; s/.*/0 0 0/') + +# Split extracted version into individual numeric components +_VER_MAJ := $(word 1,$(_VER3)) +_VER_MIN := $(word 2,$(_VER3)) +_VER_PAT := $(word 3,$(_VER3)) + +# Pack MAJOR.MINOR.PATCH into a single 32-bit integer: +# [31:16] MAJOR +# [15:8] MINOR +# [7:0] PATCH +# This value is stored in the bootloader version register and must be a valid C integer constant. +CFLAGS += -DMK_BOOTLOADER_VERSION='((($(_VER_MAJ)<<16)|($(_VER_MIN)<<8)|($(_VER_PAT))))' # Debug option use RTT for printf ifeq ($(DEBUG), 1) @@ -425,17 +507,17 @@ $(BUILD)/$(OUT_NAME).hex: $(BUILD)/$(OUT_NAME).out # Hex file with mbr (still no SD) $(BUILD)/$(OUT_NAME)_nosd.hex: $(BUILD)/$(OUT_NAME).hex @echo Create $(notdir $@) - @python3 tools/hexmerge.py --overlap=replace -o $@ $< $(MBR_HEX) + @$(PYTHON) tools/hexmerge.py --overlap=replace -o $@ $< $(MBR_HEX) # Bootolader self-update uf2 $(BUILD)/update-$(OUT_NAME)_nosd.uf2: $(BUILD)/$(OUT_NAME)_nosd.hex @echo Create $(notdir $@) - @python3 lib/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_BOOTLOADER) -c -o $@ $^ + $(PYTHON) lib/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_BOOTLOADER) -c -o $@ $^ # merge bootloader and sd hex together $(BUILD)/$(MERGED_FILE).hex: $(BUILD)/$(OUT_NAME).hex @echo Create $(notdir $@) - @python3 tools/hexmerge.py -o $@ $< $(SD_HEX) + @$(PYTHON) tools/hexmerge.py -o $@ $< $(SD_HEX) # Create pkg zip file for bootloader+SD combo to use with DFU CDC $(BUILD)/$(MERGED_FILE).zip: $(BUILD)/$(OUT_NAME).hex diff --git a/cmake/cpu/cortex-m4.cmake b/cmake/cpu/cortex-m4.cmake index 79f97e24a..91a615d4e 100644 --- a/cmake/cpu/cortex-m4.cmake +++ b/cmake/cpu/cortex-m4.cmake @@ -1,23 +1,6 @@ -if (TOOLCHAIN STREQUAL "gcc") - set(TOOLCHAIN_COMMON_FLAGS - -mthumb - -mcpu=cortex-m4 - -mfloat-abi=hard - -mfpu=fpv4-sp-d16 - ) - - if (NOT DEFINED FREERTOS_PORT) - set(FREERTOS_PORT GCC_ARM_CM4F CACHE INTERNAL "") - endif () - -elseif (TOOLCHAIN STREQUAL "iar") - set(TOOLCHAIN_COMMON_FLAGS - --cpu cortex-m4 - --fpu VFPv4 - ) - - if (NOT DEFINED FREERTOS_PORT) - set(FREERTOS_PORT IAR_ARM_CM4F CACHE INTERNAL "") - endif () - -endif () +set(TOOLCHAIN_COMMON_FLAGS + -mthumb + -mcpu=cortex-m4 + -mfloat-abi=hard + -mfpu=fpv4-sp-d16 +) \ No newline at end of file diff --git a/cmake/toolchain/arm_gcc.cmake b/cmake/toolchain/arm_gcc.cmake index 5203d1e4d..d11826c0d 100644 --- a/cmake/toolchain/arm_gcc.cmake +++ b/cmake/toolchain/arm_gcc.cmake @@ -3,10 +3,7 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_C_COMPILER "arm-none-eabi-gcc") set(CMAKE_CXX_COMPILER "arm-none-eabi-g++") set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc") - -set(CMAKE_SIZE "arm-none-eabi-size" CACHE FILEPATH "") -set(CMAKE_OBJCOPY "arm-none-eabi-objcopy" CACHE FILEPATH "") -set(CMAKE_OBJDUMP "arm-none-eabi-objdump" CACHE FILEPATH "") +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE) @@ -16,9 +13,6 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -# pass TOOLCHAIN_CPU to -set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_SYSTEM_PROCESSOR) - include(${CMAKE_CURRENT_LIST_DIR}/../cpu/${CMAKE_SYSTEM_PROCESSOR}.cmake) # enable all possible warnings for building examples @@ -27,6 +21,7 @@ list(APPEND TOOLCHAIN_COMMON_FLAGS -ffunction-sections -fsingle-precision-constant -fno-strict-aliasing + -g ) set(TOOLCHAIN_EXE_LINKER_FLAGS @@ -35,12 +30,9 @@ set(TOOLCHAIN_EXE_LINKER_FLAGS #-Wl,--cref ) -include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake) +# join the toolchain flags into a single string +list(JOIN TOOLCHAIN_COMMON_FLAGS " " TOOLCHAIN_COMMON_FLAGS) +list(JOIN TOOLCHAIN_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS_INIT) -# try_compile is cmake test compiling its own example, -# pass -nostdlib to skip stdlib linking -get_property(IS_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE) -if (IS_IN_TRY_COMPILE) - set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -nostdlib") - set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib") -endif () +set(CMAKE_C_FLAGS_INIT "${TOOLCHAIN_COMMON_FLAGS} ${TOOLCHAIN_C_FLAGS}") +set(CMAKE_ASM_FLAGS_INIT "${TOOLCHAIN_COMMON_FLAGS} ${TOOLCHAIN_ASM_FLAGS}") diff --git a/cmake/toolchain/set_flags.cmake b/cmake/toolchain/set_flags.cmake deleted file mode 100644 index bbbd21125..000000000 --- a/cmake/toolchain/set_flags.cmake +++ /dev/null @@ -1,17 +0,0 @@ -include(CMakePrintHelpers) - -# join the toolchain flags into a single string -list(JOIN TOOLCHAIN_COMMON_FLAGS " " TOOLCHAIN_COMMON_FLAGS) - -foreach (LANG IN ITEMS C CXX ASM) - set(CMAKE_${LANG}_FLAGS_INIT ${TOOLCHAIN_COMMON_FLAGS}) - - #cmake_print_variables(CMAKE_${LANG}_FLAGS_INIT) - - # optimization flags for LOG, LOGGER ? - #set(CMAKE_${LANG}_FLAGS_RELEASE_INIT "-Os") - #set(CMAKE_${LANG}_FLAGS_DEBUG_INIT "-O0") -endforeach () - -# Linker -list(JOIN TOOLCHAIN_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS_INIT) diff --git a/docs/oldsettings.md b/docs/oldsettings.md deleted file mode 100644 index 339349c5c..000000000 --- a/docs/oldsettings.md +++ /dev/null @@ -1,30 +0,0 @@ - -These are the recommended settings for OTAFIX-v1.2 and earlier.

- - - - - - -
- -**Packets Receipt Notification:** ON -**Number of packets:** 8 -**Reboot time:** 0ms -**Scan timeout:** 2000ms -**Request high MTU:** OFF -**Disable resume:** ON -**Prepare object delay:** 400ms -**Force Scanning:** ON -**Keep bond:** OFF -**External MCU DFU:** OFF - - - -Click the screenshot to view full. - - - - - -
\ No newline at end of file diff --git a/lib/nrfx b/lib/nrfx index 11f57e578..7a4c9d946 160000 --- a/lib/nrfx +++ b/lib/nrfx @@ -1 +1 @@ -Subproject commit 11f57e578c7feea13f21c79ea0efab2630ac68c7 +Subproject commit 7a4c9d946cf1801771fc180acdbf7b878f270093 diff --git a/lib/sdk11/components/ble/ble_services/ble_dfu/ble_dfu.c b/lib/sdk11/components/ble/ble_services/ble_dfu/ble_dfu.c index b36175d93..a79e4cb0b 100644 --- a/lib/sdk11/components/ble/ble_services/ble_dfu/ble_dfu.c +++ b/lib/sdk11/components/ble/ble_services/ble_dfu/ble_dfu.c @@ -17,13 +17,13 @@ #include #include "sdk_common.h" -#define MAX_DFU_PKT_LEN (247 - 3) // MTU - 3 bytes for ATT header /**< Maximum length (in bytes) of the DFU Packet characteristic. */ -#define PKT_START_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Start DFU Request. */ -#define PKT_INIT_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Init DFU Request. */ -#define PKT_RCPT_NOTIF_REQ_LEN 3 /**< Length (in bytes) of the Packet Receipt Notification Request. */ -#define MAX_PKTS_RCPT_NOTIF_LEN 6 /**< Maximum length (in bytes) of the Packets Receipt Notification. */ -#define MAX_RESPONSE_LEN 7 /**< Maximum length (in bytes) of the response to a Control Point command. */ -#define MAX_NOTIF_BUFFER_LEN MAX(MAX_PKTS_RCPT_NOTIF_LEN, MAX_RESPONSE_LEN) /**< Maximum length (in bytes) of the buffer needed by DFU Service while sending notifications to peer. */ +#define MAX_DFU_PKT_LEN (BLEGATT_ATT_MTU_MAX - 3) /**< Maximum length (in bytes) of the DFU Packet characteristic. */ +#define PKT_START_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Start DFU Request. */ +#define PKT_INIT_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Init DFU Request. */ +#define PKT_RCPT_NOTIF_REQ_LEN 3 /**< Length (in bytes) of the Packet Receipt Notification Request. */ +#define MAX_PKTS_RCPT_NOTIF_LEN 6 /**< Maximum length (in bytes) of the Packets Receipt Notification. */ +#define MAX_RESPONSE_LEN 7 /**< Maximum length (in bytes) of the response to a Control Point command. */ +#define MAX_NOTIF_BUFFER_LEN MAX(MAX_PKTS_RCPT_NOTIF_LEN, MAX_RESPONSE_LEN) /**< Maximum length (in bytes) of the buffer needed by DFU Service while sending notifications to peer. */ enum { @@ -57,7 +57,8 @@ static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu) memset(&char_md, 0, sizeof(char_md)); - char_md.char_props.write_wo_resp = 1; + char_md.char_props.write = 1; // For those improved apps that can take advantage of ACK + char_md.char_props.write_wo_resp = 1; // Nordic IOS DFU app REQUIRES Write Without Response */ char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; diff --git a/lib/sdk11/components/drivers_nrf/pstorage/pstorage.h b/lib/sdk11/components/drivers_nrf/pstorage/pstorage.h index dbd867159..f7d2f43d0 100644 --- a/lib/sdk11/components/drivers_nrf/pstorage/pstorage.h +++ b/lib/sdk11/components/drivers_nrf/pstorage/pstorage.h @@ -27,10 +27,6 @@ #include "pstorage_platform.h" -extern uint8_t* dfu_page_erased; -extern uint32_t dfu_image_page_count; -extern int32_t dfu_pending_erase_page; -extern uint32_t dfu_base_address; /**@defgroup ps_opcode Persistent Storage Access Operation Codes * @{ diff --git a/lib/sdk11/components/drivers_nrf/pstorage/pstorage_raw.c b/lib/sdk11/components/drivers_nrf/pstorage/pstorage_raw.c index 6e92bc26a..a6ac06761 100644 --- a/lib/sdk11/components/drivers_nrf/pstorage/pstorage_raw.c +++ b/lib/sdk11/components/drivers_nrf/pstorage/pstorage_raw.c @@ -47,15 +47,6 @@ #error No target defined #endif -#define PENDING_PACKET_SIZE 256 /**< Maximum size of a single pending packet data buffer. */ -#define PENDING_PACKET_COUNT 8 /**< Maximum number of packets that can be buffered during lazy erase. */ - -uint8_t * dfu_page_erased; /**< Pointer to page erased status array, set by DFU layer. */ -uint32_t dfu_image_page_count; /**< Number of pages in DFU image, set by DFU layer. */ -uint32_t dfu_base_address; /**< Base address for DFU image, set by DFU layer. */ - -static bool lazy_erase_check_and_trigger(pstorage_handle_t * p_dest, pstorage_size_t size, pstorage_size_t offset); -static void process_pending_packets(void); /** * @brief Application registration information. @@ -102,29 +93,10 @@ typedef struct cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details */ }cmd_queue_t; -/**@brief Structure for buffering packets during lazy page erase. */ -typedef struct -{ - bool valid; /**< Whether this slot contains valid data. */ - pstorage_handle_t handle; /**< Storage handle for destination. */ - uint32_t offset; /**< Offset within the storage block. */ - uint32_t size; /**< Size of data in bytes. */ - uint8_t * p_data_orig; /**< Original data pointer for callback. */ - uint8_t data[PENDING_PACKET_SIZE] __attribute__((aligned(4))); /**< Buffered packet data. */ -} pending_packet_t; - -static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */ -static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES]; /**< Registered application information table. */ -static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next */ -static pstorage_size_t m_round_val; /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */ - -static pending_packet_t m_pending_packets[PENDING_PACKET_COUNT]; /**< Ring buffer for pending packets. */ -static uint8_t m_pending_read_idx; /**< Read index for pending packet ring buffer. */ -static uint8_t m_pending_write_idx; /**< Write index for pending packet ring buffer. */ -static uint8_t m_pending_count; /**< Number of pending packets in buffer. */ -static bool m_lazy_erase_active; /**< True if a lazy erase is in progress. */ -static uint32_t m_lazy_erase_page; /**< Page index currently being erased. */ -static bool m_processing_pending; /**< True if processing a pending packet store. */ +static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */ +static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES]; /**< Registered application information table. */ +static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next */ +static pstorage_size_t m_round_val; /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */ /** * @brief Function for processing of commands and issuing flash access request to the SoftDevice. @@ -188,82 +160,6 @@ static void cmd_queue_init(void) } } -/** - * @brief Function for initializing the pending packets buffer. - */ -static void pending_packets_init(void) -{ - for (int i = 0; i < PENDING_PACKET_COUNT; i++) - { - m_pending_packets[i].valid = false; - } - m_pending_read_idx = 0; - m_pending_write_idx = 0; - m_pending_count = 0; - m_lazy_erase_active = false; - m_lazy_erase_page = 0; - m_processing_pending = false; -} - -/** - * @brief Function for adding a packet to the pending buffer. - * - * @param[in] p_handle Pointer to the storage handle. - * @param[in] p_data Pointer to the data to buffer. - * @param[in] size Size of data in bytes. - * @param[in] offset Offset within the storage block. - * - * @retval true If the packet was successfully added. - * @retval false If the buffer is full or size exceeds maximum. - */ -static bool pending_packet_add(pstorage_handle_t * p_handle, uint8_t * p_data, - uint32_t size, uint32_t offset) -{ - if (m_pending_count >= PENDING_PACKET_COUNT || size > PENDING_PACKET_SIZE) - { - return false; - } - - pending_packet_t * p = &m_pending_packets[m_pending_write_idx]; - p->handle = *p_handle; - p->offset = offset; - p->size = size; - p->p_data_orig = p_data; - memcpy(p->data, p_data, size); - p->valid = true; - - m_pending_write_idx = (m_pending_write_idx + 1) % PENDING_PACKET_COUNT; - m_pending_count++; - - return true; -} - -/** - * @brief Function for getting a pointer to the next pending packet without removing it. - * - * @return Pointer to the next pending packet, or NULL if buffer is empty. - */ -static pending_packet_t * pending_packet_peek(void) -{ - if (m_pending_count == 0) - { - return NULL; - } - return &m_pending_packets[m_pending_read_idx]; -} - -/** - * @brief Function for removing the next pending packet from the buffer. - */ -static void pending_packet_pop(void) -{ - if (m_pending_count > 0) - { - m_pending_packets[m_pending_read_idx].valid = false; - m_pending_read_idx = (m_pending_read_idx + 1) % PENDING_PACKET_COUNT; - m_pending_count--; - } -} /** * @brief Function for enqueueing a flash access operation. @@ -300,7 +196,6 @@ static uint32_t cmd_queue_enqueue(uint8_t opcode, m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr); m_cmd_queue.cmd[write_index].size = size; m_cmd_queue.cmd[write_index].offset = offset; - m_cmd_queue.count++; retval = NRF_SUCCESS; if (m_cmd_queue.flash_access == false) { @@ -311,6 +206,7 @@ static uint32_t cmd_queue_enqueue(uint8_t opcode, retval = NRF_SUCCESS; } } + m_cmd_queue.count++; } else { @@ -365,132 +261,15 @@ static void app_notify(uint32_t result, cmd_queue_element_t * p_elem) { pstorage_ntf_cb_t ntf_cb; uint8_t op_code = p_elem->op_code; - - if (p_elem->storage_addr.module_id < PSTORAGE_NUM_OF_PAGES) - { - ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb; - if (ntf_cb != NULL) - { - ntf_cb(&p_elem->storage_addr, - op_code, - result, - p_elem->p_data_addr, - p_elem->size); - } - } -} - -/** - * @brief Function for notifying application of buffered store completion. - * - * @param[in] result Result of event being notified. - * @param[in] p_handle Pointer to the storage handle. - * @param[in] p_data Pointer to the data buffer. - * @param[in] size Size of data in bytes. - */ -static void app_notify_buffered(uint32_t result, pstorage_handle_t * p_handle, - uint8_t * p_data, uint32_t size) -{ - if (p_handle->module_id < PSTORAGE_NUM_OF_PAGES) - { - pstorage_ntf_cb_t ntf_cb = m_app_table[p_handle->module_id].cb; - if (ntf_cb != NULL) - { - ntf_cb(p_handle, PSTORAGE_STORE_OP_CODE, result, p_data, size); - } - } -} - -/** - * @brief Function for processing packets from the pending buffer. - * - * @details Attempts to process the next pending packet. If the target page needs - * erasing, triggers a lazy erase. Otherwise enqueues the store operation. - */ -static void process_pending_packets(void) -{ - if (m_processing_pending || m_lazy_erase_active || m_cmd_queue.count > 0) - { - return; - } - - pending_packet_t * p = pending_packet_peek(); - if (p == NULL) - { - return; - } - - // Check if this packet needs an erase first - if (lazy_erase_check_and_trigger(&p->handle, p->size, p->offset)) - { - // Erase triggered, don't process this packet yet - return; - } - - // Page is ready, enqueue the store - m_processing_pending = true; - uint32_t ret = cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, &p->handle, p->data, p->size, p->offset); - - if (ret != NRF_SUCCESS) - { - m_processing_pending = false; - pending_packet_pop(); - } -} - - -/** - * @brief Function for checking and triggering lazy erase if needed. - * @param[in] p_dest Destination address where data is to be stored persistently. - * @param[in] size Size of data to be stored expressed in bytes. - * @param[in] offset Offset in bytes to be applied when writing to the block. - * @retval true Lazy erase was triggered. - * @retval false No lazy erase was needed. - */ -static bool lazy_erase_check_and_trigger(pstorage_handle_t * p_handle, pstorage_size_t size, pstorage_size_t offset) -{ - uint32_t target_addr = p_handle->block_id + offset; - - if (target_addr < dfu_base_address || dfu_page_erased == NULL) - { - return false; - } - - uint32_t rel_addr = target_addr - dfu_base_address; - uint32_t page_index = rel_addr / PSTORAGE_FLASH_PAGE_SIZE; - - // Also check end of packet - uint32_t end_addr = target_addr + size - 1; - uint32_t end_rel_addr = end_addr - dfu_base_address; - uint32_t end_page_index = end_rel_addr / PSTORAGE_FLASH_PAGE_SIZE; - - // Check if start page needs erase - bool start_needs_erase = (page_index < dfu_image_page_count && !dfu_page_erased[page_index]); - - // Check if end page needs erase (and is different from start page) - bool end_needs_erase = (end_page_index != page_index) && - (end_page_index < dfu_image_page_count && !dfu_page_erased[end_page_index]); - - if (!start_needs_erase && !end_needs_erase) - { - return false; - } - - // Determine which page to erase (start page takes priority) - uint32_t erase_page = start_needs_erase ? page_index : end_page_index; - - m_lazy_erase_active = true; - m_lazy_erase_page = erase_page; - - pstorage_handle_t erase_handle; - erase_handle.block_id = dfu_base_address + (erase_page * PSTORAGE_FLASH_PAGE_SIZE); - erase_handle.module_id = p_handle->module_id; - - cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, &erase_handle, NULL, - PSTORAGE_FLASH_PAGE_SIZE, 0); - - return true; + ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb; + + // Indicate result to client. + ntf_cb(&p_elem->storage_addr, + op_code, + result, + p_elem->p_data_addr, + p_elem->size); } @@ -500,7 +279,11 @@ static bool lazy_erase_check_and_trigger(pstorage_handle_t * p_handle, pstorage_ * @param[in] sys_evt System event received. */ void pstorage_sys_event_handler(uint32_t sys_evt) -{ +{ + // Do not bother processing events we are not interested in + if (sys_evt != NRF_EVT_FLASH_OPERATION_SUCCESS && + sys_evt != NRF_EVT_FLASH_OPERATION_ERROR) return; + uint32_t retval = NRF_SUCCESS; // The event shall only be processed if requested by this module. @@ -514,19 +297,13 @@ void pstorage_sys_event_handler(uint32_t sys_evt) { p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; m_round_val++; - + bool command_finished = ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size); - if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) - { - command_finished = true; - } - if (command_finished) { uint8_t queue_rp = m_cmd_queue.rp; - uint8_t completed_op = p_cmd->op_code; - + m_round_val = 0; m_cmd_queue.count--; m_cmd_queue.rp++; @@ -536,78 +313,24 @@ void pstorage_sys_event_handler(uint32_t sys_evt) m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE; } - if (m_lazy_erase_active && completed_op == PSTORAGE_CLEAR_OP_CODE) - { - // Lazy erase completed - if (dfu_page_erased != NULL && m_lazy_erase_page < dfu_image_page_count) - { - dfu_page_erased[m_lazy_erase_page] = 1; - } - - m_lazy_erase_active = false; - cmd_queue_element_init(queue_rp); - - process_pending_packets(); - } - else if (m_processing_pending && completed_op == PSTORAGE_STORE_OP_CODE) - { - // Store from pending buffer completed - pending_packet_t * p = pending_packet_peek(); - if (p != NULL) - { - pstorage_handle_t cb_handle = p->handle; - uint8_t* cb_data = p->p_data_orig; - uint32_t cb_size = p->size; - - pending_packet_pop(); - - cmd_queue_element_init(queue_rp); - - // Clear flag BEFORE callback - m_processing_pending = false; - - // Notify application that buffered this buffered store is done - app_notify_buffered(retval, &cb_handle, cb_data, cb_size); - } - else - { - m_processing_pending = false; - cmd_queue_element_init(queue_rp); - } - } - else - { - app_notify(retval, &m_cmd_queue.cmd[queue_rp]); - - // Initialize/free the element as it is now processed. - cmd_queue_element_init(queue_rp); - } - } + app_notify(retval, &m_cmd_queue.cmd[queue_rp]); - // Process next queued command OR next pending packet - if (m_cmd_queue.count > 0) - { - retval = cmd_queue_dequeue(); - } - else if (m_pending_count > 0 && !m_processing_pending && !m_lazy_erase_active) - { - // Queue is empty but we have pending packets - process one - process_pending_packets(); + // Initialize/free the element as it is now processed. + cmd_queue_element_init(queue_rp); } - + // Schedule any queued flash access operations. + retval = cmd_queue_dequeue(); if (retval != NRF_SUCCESS) { app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]); } } break; - + case NRF_EVT_FLASH_OPERATION_ERROR: - m_lazy_erase_active = false; - m_processing_pending = false; app_notify(NRF_ERROR_TIMEOUT, &m_cmd_queue.cmd[m_cmd_queue.rp]); break; - + default: // No implementation needed. break; @@ -620,6 +343,7 @@ void pstorage_sys_event_handler(uint32_t sys_evt) * @brief Function for processing of commands and issuing flash access request to the SoftDevice. * * @return The return value received from SoftDevice. + * @remark This function is only called when m_cmd_queue.flash_access == false */ static uint32_t cmd_process(void) { @@ -629,15 +353,13 @@ static uint32_t cmd_process(void) retval = NRF_ERROR_FORBIDDEN; - if (m_cmd_queue.count == 0) - { - return NRF_SUCCESS; - } - p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; storage_addr = p_cmd->storage_addr.block_id; + // Let's assume we will do a flash access + m_cmd_queue.flash_access = true; + switch (p_cmd->op_code) { case PSTORAGE_STORE_OP_CODE: @@ -665,7 +387,7 @@ static uint32_t cmd_process(void) } } break; - + case PSTORAGE_CLEAR_OP_CODE: { uint32_t page_number; @@ -676,15 +398,16 @@ static uint32_t cmd_process(void) retval = sd_flash_page_erase(page_number); } break; - + default: // Should never reach here. break; } - - if (retval == NRF_SUCCESS) + + // An error means we will not do it + if (retval != NRF_SUCCESS) { - m_cmd_queue.flash_access = true; + m_cmd_queue.flash_access = false; } return retval; @@ -695,8 +418,7 @@ static uint32_t cmd_process(void) uint32_t pstorage_init(void) { cmd_queue_init(); - pending_packets_init(); - + m_next_app_instance = 0; m_round_val = 0; @@ -738,22 +460,11 @@ uint32_t pstorage_store(pstorage_handle_t * p_dest, pstorage_size_t offset) { // Verify word alignment. - if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(p_dest->block_id + offset)))) + if ((!is_word_aligned(p_src)) || (!is_word_aligned(p_src+offset))) { return NRF_ERROR_INVALID_ADDR; } - if (m_lazy_erase_active || lazy_erase_check_and_trigger(p_dest, size, offset)) - { - // Buffer this packet - erase in progress or just triggered - if (!pending_packet_add(p_dest, p_src, size, offset)) - { - return NRF_ERROR_NO_MEM; - } - return NRF_SUCCESS; - } - - // Page already erased, proceed with store return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); } diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c index 5c574f75b..da193bdeb 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c @@ -44,15 +44,38 @@ typedef enum BOOTLOADER_SETTINGS_SAVING, /**< Bootloader status for indicating that saving of bootloader settings is in progress. */ BOOTLOADER_COMPLETE, /**< Bootloader status for indicating that all operations for the update procedure has completed and it is safe to reset the system. */ BOOTLOADER_TIMEOUT, /**< Bootloader status field for indicating that a timeout has occured and current update process should be aborted. */ - BOOTLOADER_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */ + BOOTLOADER_SYS_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */ + BOOTLOADER_RESET_TO_SELF, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted and the bootloader must be reentered. */ } bootloader_status_t; static pstorage_handle_t m_bootsettings_handle; /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */ static bootloader_status_t m_update_status; /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */ static bool m_cancel_timeout_on_usb; /**< If set the timeout is cancelled when USB is enumerated. Otherwise, the timeout is only cancelled when DFU update is started. */ +static bool m_usb_was_mounted; /**< Tracks whether the USB DFU session was ever enumerated so we can exit when cable is later removed. */ +static bool m_startup_dfu_has_activity; /**< Tracks whether any valid serial or UF2 update traffic has started. */ APP_TIMER_DEF( _dfu_startup_timer ); -volatile bool dfu_startup_packet_received = false; + +static void bootloader_timeout_startup_dfu(void) +{ + if (!m_startup_dfu_has_activity) + { + dfu_update_status_t update_status; + update_status.status_code = DFU_TIMEOUT; + + bootloader_dfu_update_process(update_status); + } +} + +void bootloader_dfu_activity_mark(void) +{ + m_startup_dfu_has_activity = true; +} + +void bootloader_mark_usb_mounted(void) +{ + m_usb_was_mounted = true; +} /**@brief Function for handling callbacks from pstorage module. * @@ -81,22 +104,17 @@ static void pstorage_callback_handler(pstorage_handle_t * p_handle, static void dfu_startup_timer_handler(void * p_context) { #ifdef NRF_USBD - if (m_cancel_timeout_on_usb && tud_mounted()) + // If host enumerated the device, keep waiting — m_usb_was_mounted was set + // by tud_mount_cb() and the unplug path in wait_for_events() will handle exit. + if (m_cancel_timeout_on_usb && m_usb_was_mounted) { return; } #endif // nRF52832 forced DFU on startup - // No packets are received within timeout, exit DFU mode - // dfu_startup_packet_received is set by process_dfu_packet() in dfu_transport_serial.c - if (!dfu_startup_packet_received) - { - dfu_update_status_t update_status; - update_status.status_code = DFU_TIMEOUT; - - bootloader_dfu_update_process(update_status); - } + // No update activity is received within timeout, exit DFU mode + bootloader_timeout_startup_dfu(); } /**@brief Function for waiting for events. @@ -117,7 +135,7 @@ static void wait_for_events(void) // Feed all Watchdog just in case application enable it // WDT cannot be disabled once started. It even last through NVIC soft reset - if ( nrf_wdt_started_check(NRF_WDT) ) + if ( nrf_wdt_started(NRF_WDT) ) { for (uint8_t i=0; i<8; i++) nrf_wdt_reload_request_set(NRF_WDT, i); } @@ -132,13 +150,22 @@ static void wait_for_events(void) tud_task(); tud_cdc_write_flush(); } + + // Exit startup DFU once USB was actually unplugged (VBUS gone), not on a + // host-side re-enumeration or temporary unmount. + if (m_cancel_timeout_on_usb && m_usb_was_mounted && + !(NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk)) + { + bootloader_timeout_startup_dfu(); + } #endif if ((m_update_status == BOOTLOADER_COMPLETE) || (m_update_status == BOOTLOADER_TIMEOUT) || - (m_update_status == BOOTLOADER_RESET) ) + (m_update_status == BOOTLOADER_SYS_RESET) || + (m_update_status == BOOTLOADER_RESET_TO_SELF)) { - // When update has completed or a timeout/reset occured we will return. + // When update has completed or a timeout/reset occurred we will return. return; } } @@ -147,23 +174,22 @@ static void wait_for_events(void) bool bootloader_app_is_valid(void) { - bool success = false; uint32_t const app_addr = DFU_BANK_0_REGION_START; - - bootloader_settings_t const *p_bootloader_settings; - bootloader_util_settings_get(&p_bootloader_settings); + uint32_t const sp_addr = *((uint32_t*)app_addr); + uint32_t const reset_addr = *((uint32_t*)(app_addr + 4)); enum { EMPTY_FLASH = 0xFFFFFFFFUL }; - // Application is invalid if first 2 words are all 0xFFFFFFF - if ( *((uint32_t *)app_addr ) == EMPTY_FLASH && - *((uint32_t *)(app_addr+4)) == EMPTY_FLASH ) + if (sp_addr == EMPTY_FLASH && reset_addr == EMPTY_FLASH) { return false; } - // The application in CODE region 1 is flagged as valid during update. - if ( p_bootloader_settings->bank_0 == BANK_VALID_APP ) + bootloader_settings_t const * p_bootloader_settings; + bootloader_util_settings_get(&p_bootloader_settings); + + // Primary path: a prior DFU flagged bank 0 as valid. + if (p_bootloader_settings->bank_0 == BANK_VALID_APP) { uint16_t image_crc = 0; @@ -175,10 +201,26 @@ bool bootloader_app_is_valid(void) NULL); } - success = (image_crc == p_bootloader_settings->bank_0_crc); + return (image_crc == p_bootloader_settings->bank_0_crc); + } + + // Fallback for debugger-flashed apps: settings page is erased (bank_0 = 0xFFFF) + // but an app may still have been written to bank 0 directly. Accept it if its + // Cortex-M vector table is plausible: initial SP within RAM, reset vector + // within app flash region with the Thumb bit set. The SP upper bound is + // inclusive because the empty-descending stack initializes one past RAM end. + if (p_bootloader_settings->bank_0 == 0xFFFF) + { + uint32_t const ram_start = 0x20000000UL; + uint32_t const ram_end = ram_start + (NRF_FICR->INFO.RAM << 10u); + bool const sp_valid = (sp_addr >= ram_start) && (sp_addr <= ram_end) && ((sp_addr & 3U) == 0); + bool const reset_in_app = (reset_addr & 1U) && + (reset_addr >= app_addr) && + (reset_addr < BOOTLOADER_REGION_START); + return sp_valid && reset_in_app; } - return success; + return false; } @@ -186,10 +228,36 @@ static void bootloader_settings_save(bootloader_settings_t * p_settings) { if ( is_ota() ) { - uint32_t err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t)); + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t)); + if (err_code != NRF_ERROR_NO_MEM) { + break; + } + // This means the write/erase queue of commands was completely full - Should not + // happen, but better safe than sorry, wait until space becomes available - + // the pstorage event handler is only run from the main loop, and we are also + // running from a BLE event on the main loop: This means if we wait here, the FLASH + // completion events will never be handled (will be queued by app_scheduler, but + // not handled, and that means this wait will never end... So, process SOC events + // from the SD (but NOT BLE events!) - This will free entries on the pstorage queue + // as soon as operations are complete, allowing this op to be queued + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); - err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0); + while(1) { + err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0); + if (err_code != NRF_ERROR_NO_MEM) { + break; + } + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); } else @@ -296,7 +364,8 @@ void bootloader_dfu_update_process(dfu_update_status_t update_status) } else if (update_status.status_code == DFU_RESET) { - m_update_status = BOOTLOADER_RESET; + m_update_status = + (update_status.restart_into_bootloader == false ? BOOTLOADER_SYS_RESET : BOOTLOADER_RESET_TO_SELF); } else { @@ -304,6 +373,10 @@ void bootloader_dfu_update_process(dfu_update_status_t update_status) } } +bool bootloader_must_reset_to_self(void) +{ + return m_update_status == BOOTLOADER_RESET_TO_SELF; +} uint32_t bootloader_init(void) { @@ -325,6 +398,8 @@ uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout uint32_t err_code; m_cancel_timeout_on_usb = cancel_timeout_on_usb && !ota; + m_usb_was_mounted = false; + m_startup_dfu_has_activity = false; // Clear swap if banked update is used. err_code = dfu_init(); @@ -340,8 +415,6 @@ uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout // - Makecode single tap reset but no enumerated (battery power) if ( timeout_ms ) { - dfu_startup_packet_received = false; - app_timer_create(&_dfu_startup_timer, APP_TIMER_MODE_SINGLE_SHOT, dfu_startup_timer_handler); app_timer_start(_dfu_startup_timer, APP_TIMER_TICKS(timeout_ms), NULL); } diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h index efd72e753..952a95fe6 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h @@ -32,6 +32,13 @@ */ uint32_t bootloader_init(void); +/**@brief Function to check if bootloader must be reentered after a reset + * @details: This function can only be called after bootloader_dfu_start returns + * @retval true If device must reboot to the bootloader + * @retval false If device must reboot to the application, if possible + */ +bool bootloader_must_reset_to_self(void); + /**@brief Function for validating application region in flash. * @retval true If Application region is valid. * @retval false If Application region is not valid. @@ -67,6 +74,20 @@ void bootloader_settings_get(bootloader_settings_t * const p_settings); */ void bootloader_dfu_update_process(dfu_update_status_t update_status); +/**@brief Mark that startup DFU has received valid update activity. + * + * @details This suppresses the startup timeout or USB unplug fallback that is only + * meant for the "entered bootloader, but never started an update" case. + */ +void bootloader_dfu_activity_mark(void); + +/**@brief Mark that the USB DFU session was enumerated by a host. + * + * @details Called from tud_mount_cb(). Enables the USB-unplug exit path in + * wait_for_events(), which exits startup DFU once VBUS is removed. + */ +void bootloader_mark_usb_mounted(void); + /**@brief Function getting state of SoftDevice update in progress. * After a successfull SoftDevice transfer the system restarts in orderto disable SoftDevice * and complete the update. @@ -92,6 +113,8 @@ uint32_t bootloader_dfu_sd_update_finalize(void); void bootloader_mbr_addrs_populate(void); +extern uint32_t proc_soc(void); + #endif // BOOTLOADER_H__ /**@} */ diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c b/lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c index 62cb2856e..a1fb9be34 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c @@ -11,10 +11,13 @@ */ #include "bootloader_util.h" +#include "dfu_types.h" +#include "nrf_peripherals.h" + #include +#include #include - /** * @brief Function for aborting current application/bootloader jump to to other app/bootloader. * @@ -164,8 +167,76 @@ static inline void bootloader_util_reset(uint32_t start_addr) #error Compiler not supported. #endif +// protect flash region from write access +static uint32_t bootloader_util_flash_protect(uint32_t address, uint32_t size) { + if ((size & (CODE_PAGE_SIZE - 1)) || (address & (CODE_PAGE_SIZE - 1)) || (address > BOOTLOADER_SETTINGS_ADDRESS)) { + return NRF_ERROR_INVALID_PARAM; + } + +#if defined(ACL_PRESENT) + // Protect using ACL. + static uint32_t acl_instance = 0; + + volatile ACL_ACL_Type *p_acl; + const uint32_t mask = (ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos); + + do { + if (acl_instance >= ACL_REGIONS_COUNT) { + return NRF_ERROR_NO_MEM; + } + + p_acl = &NRF_ACL->ACL[acl_instance]; + p_acl->ADDR = address; + p_acl->SIZE = size; + p_acl->PERM = mask; + + acl_instance++; + + } while (p_acl->ADDR != address || p_acl->SIZE != size || + p_acl->PERM != mask); // Check whether the acl_instance has been used before. + +#elif defined(BPROT_PRESENT) + // Protect using BPROT. BPROT does not support read protection. + uint32_t pagenum_start = address / CODE_PAGE_SIZE; + uint32_t pagenum_end = pagenum_start + ((size - 1) / CODE_PAGE_SIZE); + + for (uint32_t i = pagenum_start; i <= pagenum_end; i++) { + uint32_t config_index = i / 32; + uint32_t mask = (1 << (i - config_index * 32)); + + switch (config_index) { + case 0: + NRF_BPROT->CONFIG0 = mask; + break; + case 1: + NRF_BPROT->CONFIG1 = mask; + break; + #if BPROT_REGIONS_NUM > 64 + case 2: + NRF_BPROT->CONFIG2 = mask; + break; + case 3: + NRF_BPROT->CONFIG3 = mask; + break; + #endif + } + } -void bootloader_util_app_start(uint32_t start_addr) -{ - bootloader_util_reset(start_addr); +#endif + + return NRF_SUCCESS; +} + +void bootloader_util_app_start(uint32_t start_addr) { + // Protect MBR against user writes + bootloader_util_flash_protect(0, MBR_SIZE); + + // Size of the bootloader flash area to protect (Bootloader + MBR params + Bootloader settings) + const uint32_t area_size = BOOTLOADER_SETTINGS_ADDRESS + CODE_PAGE_SIZE - BOOTLOADER_REGION_START; + + // Protect bootloader code and params pages against user writes + bootloader_util_flash_protect(BOOTLOADER_REGION_START, area_size); + + // Jump to user application + bootloader_util_reset(start_addr); } diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_bank_internal.h b/lib/sdk11/components/libraries/bootloader_dfu/dfu_bank_internal.h index 03d20f614..f84d1115b 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_bank_internal.h +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_bank_internal.h @@ -40,6 +40,8 @@ typedef enum DFU_STATE_WAIT_4_ACTIVATE /**< State for: waiting for dfu_image_activate(). */ } dfu_state_t; +#define DFU_TIMEOUT_INTERVAL APP_TIMER_TICKS(360000) /**< DFU timeout interval in milliseconds. */ + #define IS_UPDATING_SD(START_PKT) ((START_PKT).dfu_update_mode & DFU_UPDATE_SD) /**< Macro for determining if a SoftDevice update is ongoing. */ #define IS_UPDATING_BL(START_PKT) ((START_PKT).dfu_update_mode & DFU_UPDATE_BL) /**< Macro for determining if a Bootloader update is ongoing. */ #define IS_UPDATING_APP(START_PKT) ((START_PKT).dfu_update_mode & DFU_UPDATE_APP) /**< Macro for determining if a Application update is ongoing. */ diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c new file mode 100644 index 000000000..32cc71a5c --- /dev/null +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c @@ -0,0 +1,947 @@ +/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#include +#include "dfu.h" +#include +#include "dfu_bank_internal.h" +#include "nrf.h" +#include "nrf_sdm.h" +#include "app_error.h" +#include "app_timer.h" +#include "bootloader.h" +#include "bootloader_types.h" +#include "pstorage.h" +#include "nrf_mbr.h" +#include "dfu_init.h" +#include "sdk_common.h" + +static dfu_state_t m_dfu_state; /**< Current DFU state. */ +static uint32_t m_image_size; /**< Size of the image that will be transmitted. */ + +static dfu_start_packet_t m_start_packet; /**< Start packet received for this update procedure. Contains update mode and image sizes information to be used for image transfer. */ +static uint8_t m_init_packet[128]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrity check and authorization checking. */ +static uint8_t m_init_packet_length; /**< Length of init packet received. */ +static uint16_t m_image_crc; /**< Calculated CRC of the image received. */ + +APP_TIMER_DEF(m_dfu_timer_id); /**< Application timer id. */ +static bool m_dfu_timed_out = false; /**< Boolean flag value for tracking DFU timer timeout state. */ + +static pstorage_handle_t m_storage_handle_swap; /**< Pstorage handle for the swap area (bank 1). Bank used when updating an application or bootloader without SoftDevice. */ +static pstorage_handle_t m_storage_handle_app; /**< Pstorage handle for the application area (bank 0). Bank used when updating a SoftDevice w/wo bootloader. Handle also used when swapping received application from bank 1 to bank 0. */ +static pstorage_handle_t * mp_storage_handle_active; /**< Pointer to the pstorage handle for the active bank for receiving of data packets. */ + +static dfu_callback_t m_data_pkt_cb; /**< Callback from DFU Bank module for notification of asynchronous operation such as flash prepare. */ +static dfu_bank_func_t m_functions; /**< Structure holding operations for the selected update process. */ + + +/**@brief Function for handling callbacks from pstorage module. + * + * @details Handles pstorage results for clear and storage operation. For detailed description of + * the parameters provided with the callback, please refer to \ref pstorage_ntf_cb_t. + */ +static void pstorage_callback_handler(pstorage_handle_t * p_handle, + uint8_t op_code, + uint32_t result, + uint8_t * p_data, + uint32_t data_len) +{ + switch (op_code) + { + case PSTORAGE_STORE_OP_CODE: + if ((m_dfu_state == DFU_STATE_RX_DATA_PKT) && (m_data_pkt_cb != NULL)) + { + m_data_pkt_cb(DATA_PACKET, result, p_data); + } + break; + + case PSTORAGE_CLEAR_OP_CODE: + if (m_dfu_state == DFU_STATE_PREPARING) + { + m_functions.cleared(); + m_dfu_state = DFU_STATE_RDY; + if (m_data_pkt_cb != NULL) + { + m_data_pkt_cb(START_PACKET, result, p_data); + } + } + break; + + default: + break; + } + APP_ERROR_CHECK(result); +} + + +/**@brief Function for handling the DFU timeout. + * + * @param[in] p_context The timeout context. + */ +static void dfu_timeout_handler(void * p_context) +{ + UNUSED_PARAMETER(p_context); + dfu_update_status_t update_status = {0}; + + m_dfu_timed_out = true; + update_status.status_code = DFU_TIMEOUT; + + bootloader_dfu_update_process(update_status); +} + + +/**@brief Function for restarting the DFU Timer. + * + * @details This function will stop and restart the DFU timer. This function will be called by the + * functions handling any DFU packet received from the peer that is transferring a firmware + * image. + */ +static uint32_t dfu_timer_restart(void) +{ + if (m_dfu_timed_out) + { + // The DFU timer had already timed out. + return NRF_ERROR_INVALID_STATE; + } + + uint32_t err_code = app_timer_stop(m_dfu_timer_id); + APP_ERROR_CHECK(err_code); + + err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); + APP_ERROR_CHECK(err_code); + + return err_code; +} + + +/**@brief Function for preparing of flash before receiving SoftDevice image. + * + * @details This function will erase current application area to ensure sufficient amount of + * storage for the SoftDevice image. Upon erase complete a callback will be done. + * See \ref dfu_bank_prepare_t for further details. + */ +static void dfu_prepare_func_app_erase(uint32_t image_size) +{ + mp_storage_handle_active = &m_storage_handle_app; + + // Doing a SoftDevice update thus current application must be cleared to ensure enough space + // for new SoftDevice. + m_dfu_state = DFU_STATE_PREPARING; + + if ( is_ota() ) + { + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + } + else + { + flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_image_size); + + // invoke complete callback + pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); + } +} + + +/**@brief Function for preparing swap before receiving application or bootloader image. + * + * @details This function will erase current swap area to ensure flash is ready for storage of the + * Application or Bootloader image. Upon erase complete a callback will be done. + * See \ref dfu_bank_prepare_t for further details. + */ +static void dfu_prepare_func_swap_erase(uint32_t image_size) +{ + mp_storage_handle_active = &m_storage_handle_swap; + + m_dfu_state = DFU_STATE_PREPARING; + + if ( is_ota() ) + { + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_swap, image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + } + else + { + flash_nrf5x_erase(DFU_BANK_1_REGION_START, image_size); + + // invoke complete callback + pstorage_callback_handler(&m_storage_handle_swap, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); + } +} + + +/**@brief Function for handling behaviour when clear operation has completed. + */ +static void dfu_cleared_func_swap(void) +{ + // Do nothing. +} + + +/**@brief Function for handling behaviour when clear operation has completed. + */ +static void dfu_cleared_func_app(void) +{ + dfu_update_status_t update_status = { 0 }; + update_status.status_code = DFU_BANK_0_ERASED; + bootloader_dfu_update_process(update_status); +} + + +/**@brief Function for calculating storage offset for receiving SoftDevice image. + * + * @details When a new SoftDevice is received it will be temporary stored in flash before moved to + * address 0x0. In order to successfully validate transfer and relocation it is important + * that temporary image and final installed image does not overlap hence an offset must + * be calculated in case new image is larger than currently installed SoftDevice. + */ +uint32_t offset_calculate(uint32_t sd_image_size) +{ + uint32_t offset = 0; + + if (m_start_packet.sd_image_size > DFU_BANK_0_REGION_START) + { + uint32_t page_mask = (CODE_PAGE_SIZE - 1); + uint32_t diff = m_start_packet.sd_image_size - DFU_BANK_0_REGION_START; + + offset = diff & ~page_mask; + + // Align offset to next page if image size is not page sized. + if ((diff & page_mask) > 0) + { + offset += CODE_PAGE_SIZE; + } + } + + return offset; +} + + +/**@brief Function for activating received SoftDevice image. + * + * @note This function will not move the SoftDevice image. + * The bootloader settings will be marked as SoftDevice update complete and the swapping of + * current SoftDevice will occur after system reset. + * + * @return NRF_SUCCESS on success. + */ +static uint32_t dfu_activate_sd(void) +{ + dfu_update_status_t update_status = {0}; + + update_status.status_code = DFU_UPDATE_SD_COMPLETE; + update_status.app_crc = m_image_crc; + update_status.sd_image_start = DFU_BANK_0_REGION_START; + update_status.sd_size = m_start_packet.sd_image_size; + update_status.bl_size = m_start_packet.bl_image_size; + update_status.app_size = m_start_packet.app_image_size; + + bootloader_dfu_update_process(update_status); + + return NRF_SUCCESS; +} + + +/**@brief Function for activating received Application image. + * + * @details This function will move the received application image from swap (bank 1) to + * application area (bank 0). + * + * @return NRF_SUCCESS on success. Error code otherwise. + */ +static uint32_t dfu_activate_app(void) +{ + uint32_t err_code = NRF_SUCCESS; + + // Erase BANK 0. + if ( is_ota() ) + { + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_start_packet.app_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + + while(1) { + err_code = pstorage_store(&m_storage_handle_app, + (uint8_t *)m_storage_handle_swap.block_id, + m_start_packet.app_image_size, + 0); + + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + VERIFY_SUCCESS(err_code); + + } + else + { + flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_start_packet.app_image_size); + pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); + + flash_nrf5x_write(DFU_BANK_0_REGION_START, (uint8_t *)DFU_BANK_1_REGION_START, m_start_packet.app_image_size, false); + flash_nrf5x_flush(false); + pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_STORE_OP_CODE, NRF_SUCCESS, (uint8_t *) DFU_BANK_1_REGION_START, m_start_packet.app_image_size); + } + + if (err_code == NRF_SUCCESS) + { + dfu_update_status_t update_status = { 0 }; + + memset(&update_status, 0, sizeof(dfu_update_status_t )); + update_status.status_code = DFU_UPDATE_APP_COMPLETE; + update_status.app_crc = m_image_crc; + update_status.app_size = m_start_packet.app_image_size; + + bootloader_dfu_update_process(update_status); + } + + return err_code; +} + + +/**@brief Function for activating received Bootloader image. + * + * @note This function will not move the bootloader image. + * The bootloader settings will be marked as Bootloader update complete and the swapping of + * current bootloader will occur after system reset. + * + * @return NRF_SUCCESS on success. + */ +static uint32_t dfu_activate_bl(void) +{ + dfu_update_status_t update_status = {0}; + + update_status.status_code = DFU_UPDATE_BOOT_COMPLETE; + update_status.app_crc = m_image_crc; + update_status.sd_size = m_start_packet.sd_image_size; + update_status.bl_size = m_start_packet.bl_image_size; + update_status.app_size = m_start_packet.app_image_size; + + bootloader_dfu_update_process(update_status); + + return NRF_SUCCESS; +} + + +uint32_t dfu_init(void) +{ + uint32_t err_code; + pstorage_module_param_t storage_module_param = {.cb = pstorage_callback_handler}; + + m_init_packet_length = 0; + m_image_crc = 0; + + err_code = pstorage_register(&storage_module_param, &m_storage_handle_app); + if (err_code != NRF_SUCCESS) + { + m_dfu_state = DFU_STATE_INIT_ERROR; + return err_code; + } + + m_storage_handle_app.block_id = DFU_BANK_0_REGION_START; + m_storage_handle_swap = m_storage_handle_app; + m_storage_handle_swap.block_id = DFU_BANK_1_REGION_START; + + // Create the timer to monitor the activity by the peer doing the firmware update. + err_code = app_timer_create(&m_dfu_timer_id, + APP_TIMER_MODE_SINGLE_SHOT, + dfu_timeout_handler); + APP_ERROR_CHECK(err_code); + + // Start the DFU timer. + err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); + APP_ERROR_CHECK(err_code); + + m_data_received = 0; + m_dfu_state = DFU_STATE_IDLE; + + return NRF_SUCCESS; +} + + +void dfu_register_callback(dfu_callback_t callback_handler) +{ + m_data_pkt_cb = callback_handler; +} + + +uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) +{ + uint32_t err_code; + + m_start_packet = *(p_packet->params.start_packet); + + // Check that the requested update procedure is supported. + // Currently the following combinations are allowed: + // - Application + // - SoftDevice + // - Bootloader + // - SoftDevice with Bootloader + if (IS_UPDATING_APP(m_start_packet) && + (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet))) + { + // App update is only supported independently. + return NRF_ERROR_NOT_SUPPORTED; + } + + if (!(IS_WORD_SIZED(m_start_packet.sd_image_size) && + IS_WORD_SIZED(m_start_packet.bl_image_size) && + IS_WORD_SIZED(m_start_packet.app_image_size))) + { + // Image_sizes are not a multiple of 4 (word size). + return NRF_ERROR_NOT_SUPPORTED; + } + + m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size + + m_start_packet.app_image_size; + + if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE) + { + return NRF_ERROR_DATA_SIZE; + } + + if (IS_UPDATING_SD(m_start_packet)) + { + if (m_image_size > (DFU_IMAGE_MAX_SIZE_FULL)) + { + return NRF_ERROR_DATA_SIZE; + } + m_functions.prepare = dfu_prepare_func_app_erase; + m_functions.cleared = dfu_cleared_func_app; + m_functions.activate = dfu_activate_sd; + } + else + { + if (m_image_size > DFU_IMAGE_MAX_SIZE_BANKED) + { + return NRF_ERROR_DATA_SIZE; + } + + m_functions.prepare = dfu_prepare_func_swap_erase; + m_functions.cleared = dfu_cleared_func_swap; + if (IS_UPDATING_BL(m_start_packet)) + { + m_functions.activate = dfu_activate_bl; + } + else + { + m_functions.activate = dfu_activate_app; + } + } + + if ( DFU_STATE_IDLE != m_dfu_state ) + return NRF_ERROR_INVALID_STATE; + + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + + m_functions.prepare(m_image_size); + + return NRF_SUCCESS; +} + + +uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) +{ + uint32_t data_length; + uint32_t err_code; + uint32_t * p_data; + + VERIFY_PARAM_NOT_NULL(p_packet); + + // Check pointer alignment. + if (!is_word_aligned(p_packet->params.data_packet.p_data_packet)) + { + // The p_data_packet is not word aligned address. + return NRF_ERROR_INVALID_ADDR; + } + + switch (m_dfu_state) + { + case DFU_STATE_RDY: + case DFU_STATE_RX_INIT_PKT: + return NRF_ERROR_INVALID_STATE; + + case DFU_STATE_RX_DATA_PKT: + data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); + + if ((m_data_received + data_length) > m_image_size) + { + // The caller is trying to write more bytes into the flash than the size provided to + // the dfu_image_size_set function. This is treated as a serious error condition and + // an unrecoverable one. Hence point the variable mp_app_write_address to the top of + // the flash area. This will ensure that all future application data packet writes + // will be blocked because of the above check. + m_data_received = 0xFFFFFFFF; + + return NRF_ERROR_DATA_SIZE; + } + + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + + p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet; + + if ( is_ota() ) + { + while(1) { + err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + VERIFY_SUCCESS(err_code); + } + else + { + flash_nrf5x_write( + (mp_storage_handle_active == &m_storage_handle_app + ? DFU_BANK_0_REGION_START + : DFU_BANK_1_REGION_START) + + m_data_received, p_data, data_length, false); + pstorage_callback_handler(mp_storage_handle_active, PSTORAGE_STORE_OP_CODE, NRF_SUCCESS, (uint8_t *) p_data, data_length); + } + + m_data_received += data_length; + + if (m_data_received != m_image_size) + { + // The entire image is not received yet. More data is expected. + err_code = NRF_ERROR_INVALID_LENGTH; + } + else + { + if ( !is_ota() ) flash_nrf5x_flush(false); + + // The entire image has been received. Return NRF_SUCCESS. + err_code = NRF_SUCCESS; + } + break; + + default: + err_code = NRF_ERROR_INVALID_STATE; + break; + } + + return err_code; +} + + +uint32_t dfu_init_pkt_complete(void) +{ + uint32_t err_code = NRF_ERROR_INVALID_STATE; + + // DFU initialization has been done and a start packet has been received. + if (IMAGE_WRITE_IN_PROGRESS()) + { + // Image write is already in progress. Cannot handle an init packet now. + return NRF_ERROR_INVALID_STATE; + } + + if (m_dfu_state == DFU_STATE_RX_INIT_PKT) + { + err_code = dfu_init_prevalidate(m_init_packet, m_init_packet_length, m_start_packet.dfu_update_mode); + if (err_code == NRF_SUCCESS) + { + m_dfu_state = DFU_STATE_RX_DATA_PKT; + } + else + { + m_init_packet_length = 0; + } + } + return err_code; +} + + +uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) +{ + uint32_t err_code = NRF_SUCCESS; + uint32_t length; + + switch (m_dfu_state) + { + case DFU_STATE_RDY: + m_dfu_state = DFU_STATE_RX_INIT_PKT; + // When receiving init packet in state ready just update and fall through this case. + /* FALLTHRU */ + + case DFU_STATE_RX_INIT_PKT: + // DFU initialization has been done and a start packet has been received. + if (IMAGE_WRITE_IN_PROGRESS()) + { + // Image write is already in progress. Cannot handle an init packet now. + return NRF_ERROR_INVALID_STATE; + } + + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + + length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); + if ((m_init_packet_length + length) > sizeof(m_init_packet)) + { + return NRF_ERROR_INVALID_LENGTH; + } + + memcpy(&m_init_packet[m_init_packet_length], + &p_packet->params.data_packet.p_data_packet[0], + length); + m_init_packet_length += length; + break; + + default: + // Either the start packet was not received or dfu_init function was not called before. + return NRF_ERROR_INVALID_STATE; + } + + return NRF_SUCCESS; +} + + +uint32_t dfu_image_validate() +{ + uint32_t err_code; + + switch (m_dfu_state) + { + case DFU_STATE_RX_DATA_PKT: + // Check if the application image write has finished. + if (m_data_received != m_image_size) + { + // Image not yet fully transferred by the peer or the peer has attempted to write + // too much data. Hence the validation should fail. + err_code = NRF_ERROR_INVALID_STATE; + } + else + { + m_dfu_state = DFU_STATE_VALIDATE; + + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + if (err_code == NRF_SUCCESS) + { + err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id, + m_image_size); + VERIFY_SUCCESS(err_code); + + m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; + } + } + break; + + default: + err_code = NRF_ERROR_INVALID_STATE; + break; + } + + return err_code; +} + + +uint32_t dfu_image_activate() +{ + uint32_t err_code; + + switch (m_dfu_state) + { + case DFU_STATE_WAIT_4_ACTIVATE: + + // Stop the DFU Timer because the peer activity need not be monitored any longer. + err_code = app_timer_stop(m_dfu_timer_id); + APP_ERROR_CHECK(err_code); + + err_code = m_functions.activate(); + break; + + default: + err_code = NRF_ERROR_INVALID_STATE; + break; + } + + return err_code; +} + + +void dfu_reset(void) +{ + dfu_update_status_t update_status = { 0 }; + + update_status.status_code = DFU_RESET; + + // If we are still receiving packets, and we are expecting more of them, + // and we receive the RESET command, this means the DFU app is trying + // to interrupt and recover a failed previous attempt of FLASHing a new + // application. Make sure to reboot into DFU mode instead of starting + // a previously stored application (specially valid for double bank + // bootloaders + update_status.restart_into_bootloader = (m_dfu_state == DFU_STATE_RX_DATA_PKT && m_data_received != m_image_size); + + bootloader_dfu_update_process(update_status); +} + + +static uint32_t dfu_compare_block(uint32_t * ptr1, uint32_t * ptr2, uint32_t len) +{ + sd_mbr_command_t sd_mbr_cmd; + + sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd.params.compare.ptr1 = ptr1; + sd_mbr_cmd.params.compare.ptr2 = ptr2; + sd_mbr_cmd.params.compare.len = len / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd); +} + + +static uint32_t dfu_copy_sd(uint32_t * src, uint32_t * dst, uint32_t len) +{ + sd_mbr_command_t sd_mbr_cmd; + + sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_SD; + sd_mbr_cmd.params.copy_sd.src = src; + sd_mbr_cmd.params.copy_sd.dst = dst; + sd_mbr_cmd.params.copy_sd.len = len / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd); +} + + +static uint32_t dfu_sd_img_block_swap(uint32_t * src, + uint32_t * dst, + uint32_t len, + uint32_t block_size) +{ + // It is necessary to swap the new SoftDevice in 3 rounds to ensure correct copy of data + // and verification of data in case power reset occurs during write to flash. + // To ensure the robustness of swapping the images are compared backwards till start of + // image swap. If the back is identical everything is swapped. + uint32_t err_code = dfu_compare_block(src, dst, len); + if (err_code == NRF_SUCCESS) + { + return err_code; + } + + if ((uint32_t)dst > SOFTDEVICE_REGION_START) + { + err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size), + (uint32_t *)((uint32_t)dst - block_size), + block_size, + block_size); + VERIFY_SUCCESS(err_code); + } + + err_code = dfu_copy_sd(src, dst, len); + VERIFY_SUCCESS(err_code); + + return dfu_compare_block(src, dst, len); +} + + +uint32_t dfu_sd_image_swap(void) +{ + bootloader_settings_t boot_settings; + + bootloader_settings_get(&boot_settings); + + if (boot_settings.sd_image_size == 0) + { + return NRF_SUCCESS; + } + + if ((SOFTDEVICE_REGION_START + boot_settings.sd_image_size) > boot_settings.sd_image_start) + { + uint32_t err_code; + uint32_t sd_start = SOFTDEVICE_REGION_START; + uint32_t block_size = (boot_settings.sd_image_start - sd_start) / 2; + + /* ##### FIX START ##### */ + block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); + /* ##### FIX END ##### */ + + uint32_t image_end = boot_settings.sd_image_start + boot_settings.sd_image_size; + + uint32_t img_block_start = boot_settings.sd_image_start + 2 * block_size; + uint32_t sd_block_start = sd_start + 2 * block_size; + + if (SD_SIZE_GET(MBR_SIZE) < boot_settings.sd_image_size) + { + // This will clear a page thus ensuring the old image is invalidated before swapping. + err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size), + (uint32_t *)(sd_start + block_size), + sizeof(uint32_t)); + VERIFY_SUCCESS(err_code); + + err_code = dfu_copy_sd((uint32_t *)sd_start, (uint32_t *)sd_start, sizeof(uint32_t)); + VERIFY_SUCCESS(err_code); + } + + return dfu_sd_img_block_swap((uint32_t *)img_block_start, + (uint32_t *)sd_block_start, + image_end - img_block_start, + block_size); + } + else + { + if (boot_settings.sd_image_size != 0) + { + return dfu_copy_sd((uint32_t *)boot_settings.sd_image_start, + (uint32_t *)SOFTDEVICE_REGION_START, + boot_settings.sd_image_size); + } + } + + return NRF_SUCCESS; +} + + +uint32_t dfu_bl_image_swap(void) +{ + bootloader_settings_t bootloader_settings; + sd_mbr_command_t sd_mbr_cmd; + + bootloader_settings_get(&bootloader_settings); + + if (bootloader_settings.bl_image_size != 0) + { + uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ? + DFU_BANK_1_REGION_START : + bootloader_settings.sd_image_start + + bootloader_settings.sd_image_size; + + sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_BL; + sd_mbr_cmd.params.copy_bl.bl_src = (uint32_t *)(bl_image_start); + sd_mbr_cmd.params.copy_bl.bl_len = bootloader_settings.bl_image_size / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd); + } + return NRF_SUCCESS; +} + + +uint32_t dfu_bl_image_validate(void) +{ + bootloader_settings_t bootloader_settings; + sd_mbr_command_t sd_mbr_cmd_1; + sd_mbr_command_t sd_mbr_cmd_2; + + bootloader_settings_get(&bootloader_settings); + + if (bootloader_settings.bl_image_size != 0) + { + uint32_t bl_image_start_1 = (bootloader_settings.sd_image_size == 0) ? + DFU_BANK_0_REGION_START : + bootloader_settings.sd_image_start + + bootloader_settings.sd_image_size; + + sd_mbr_cmd_1.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd_1.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; + sd_mbr_cmd_1.params.compare.ptr2 = (uint32_t *)(bl_image_start_1); + sd_mbr_cmd_1.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + + uint32_t err_code = sd_mbr_command(&sd_mbr_cmd_1); + if (err_code == NRF_SUCCESS) + return NRF_SUCCESS; + + uint32_t bl_image_start_2 = (bootloader_settings.sd_image_size == 0) ? + DFU_BANK_1_REGION_START : + bootloader_settings.sd_image_start + + bootloader_settings.sd_image_size; + + sd_mbr_cmd_2.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd_2.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; + sd_mbr_cmd_2.params.compare.ptr2 = (uint32_t *)(bl_image_start_2); + sd_mbr_cmd_2.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd_2); + } + return NRF_SUCCESS; +} + + +uint32_t dfu_sd_image_validate(void) +{ + bootloader_settings_t bootloader_settings; + sd_mbr_command_t sd_mbr_cmd; + + bootloader_settings_get(&bootloader_settings); + + if (bootloader_settings.sd_image_size == 0) + { + return NRF_SUCCESS; + } + + if ((SOFTDEVICE_REGION_START + bootloader_settings.sd_image_size) > bootloader_settings.sd_image_start) + { + uint32_t sd_start = SOFTDEVICE_REGION_START; + uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2; + uint32_t image_end = bootloader_settings.sd_image_start + + bootloader_settings.sd_image_size; + + /* ##### FIX START ##### */ + block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); + /* ##### FIX END ##### */ + + uint32_t img_block_start = bootloader_settings.sd_image_start + 2 * block_size; + uint32_t sd_block_start = sd_start + 2 * block_size; + + if (SD_SIZE_GET(MBR_SIZE) < bootloader_settings.sd_image_size) + { + return NRF_ERROR_NULL; + } + + return dfu_sd_img_block_swap((uint32_t *)img_block_start, + (uint32_t *)sd_block_start, + image_end - img_block_start, + block_size); + } + + sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)SOFTDEVICE_REGION_START; + sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)bootloader_settings.sd_image_start; + sd_mbr_cmd.params.compare.len = bootloader_settings.sd_image_size / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd); +} diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c index f8c90ef8f..114a57c9d 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c @@ -31,10 +31,13 @@ static dfu_state_t m_dfu_state; /**< Current DFU static uint32_t m_image_size; /**< Size of the image that will be transmitted. */ static dfu_start_packet_t m_start_packet; /**< Start packet received for this update procedure. Contains update mode and image sizes information to be used for image transfer. */ -static uint8_t m_init_packet[64]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrety check and authorization checking. */ +static uint8_t m_init_packet[128]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrety check and authorization checking. */ static uint8_t m_init_packet_length; /**< Length of init packet received. */ static uint16_t m_image_crc; /**< Calculated CRC of the image received. */ +APP_TIMER_DEF(m_dfu_timer_id); /**< Application timer id. */ +static bool m_dfu_timed_out = false; /**< Boolean flag value for tracking DFU timer timeout state. */ + static pstorage_handle_t m_storage_handle_app; /**< Pstorage handle for the application area (bank 0). Bank used when updating a SoftDevice w/wo bootloader. Handle also used when swapping received application from bank 1 to bank 0. */ static pstorage_handle_t * mp_storage_handle_active; /**< Pointer to the pstorage handle for the active bank for receiving of data packets. */ @@ -65,12 +68,6 @@ static void pstorage_callback_handler(pstorage_handle_t * p_handle, case PSTORAGE_CLEAR_OP_CODE: if (m_dfu_state == DFU_STATE_PREPARING) { - // Special case for lazy erase - mark first page as erased - if (dfu_page_erased != NULL && dfu_image_page_count > 0) - { - dfu_page_erased[0] = 1; - } - m_functions.cleared(); m_dfu_state = DFU_STATE_RDY; if (m_data_pkt_cb != NULL) @@ -86,44 +83,78 @@ static void pstorage_callback_handler(pstorage_handle_t * p_handle, APP_ERROR_CHECK(result); } -/**@brief Function for preparing flash before receiving image. + +/**@brief Function for handling the DFU timeout. * - * @details For lazy erase mode (OTA), this sets up the tracking array and erases - * only the first page to signal readiness. Subsequent pages are erased - * on-demand when stores target them. - * For non-OTA mode, all pages are erased upfront. + * @param[in] p_context The timeout context. + */ +static void dfu_timeout_handler(void * p_context) +{ + UNUSED_PARAMETER(p_context); + dfu_update_status_t update_status; + + m_dfu_timed_out = true; + update_status.status_code = DFU_TIMEOUT; + + bootloader_dfu_update_process(update_status); +} + + +/**@brief Function for restarting the DFU Timer. + * + * @details This function will stop and restart the DFU timer. This function will be called by the + * functions handling any DFU packet received from the peer that is transferring a firmware + * image. + */ +static uint32_t dfu_timer_restart(void) +{ + if (m_dfu_timed_out) + { + // The DFU timer had already timed out. + return NRF_ERROR_INVALID_STATE; + } + + uint32_t err_code = app_timer_stop(m_dfu_timer_id); + APP_ERROR_CHECK(err_code); + + err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); + APP_ERROR_CHECK(err_code); + + return err_code; +} + + +/**@brief Function for preparing of flash before receiving SoftDevice image. + * + * @details This function will erase current application area to ensure sufficient amount of + * storage for the SoftDevice image. Upon erase complete a callback will be done. + * See \ref dfu_bank_prepare_t for further details. */ static void dfu_prepare_func_app_erase(uint32_t image_size) { mp_storage_handle_active = &m_storage_handle_app; + // Doing a SoftDevice update thus current application must be cleared to ensure enough space + // for new SoftDevice. m_dfu_state = DFU_STATE_PREPARING; - dfu_base_address = m_storage_handle_app.block_id; if ( is_ota() ) { - // Setup for lazy erase - dfu_image_page_count = NRFX_CEIL_DIV(m_image_size, CODE_PAGE_SIZE); - - if (dfu_image_page_count < 1) dfu_image_page_count = 1; // This should not happen - - static uint8_t dfu_page_erased_static[256]; - dfu_page_erased = dfu_page_erased_static; - memset(dfu_page_erased, 0, dfu_image_page_count); - - uint32_t err_code = pstorage_clear(&m_storage_handle_app, CODE_PAGE_SIZE); + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); } else { - uint32_t const page_count = NRFX_CEIL_DIV(m_image_size, CODE_PAGE_SIZE); - - for ( uint32_t i = 0; i < page_count; i++ ) - { - uint32_t const addr = DFU_BANK_0_REGION_START + i * CODE_PAGE_SIZE; - PRINTF("Erase 0x%08lX\r\n", addr); - nrfx_nvmc_page_erase(addr); - } + flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_image_size); // invoke complete callback pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); @@ -151,14 +182,14 @@ static void dfu_cleared_func_app(void) uint32_t offset_calculate(uint32_t sd_image_size) { uint32_t offset = 0; - + if (m_start_packet.sd_image_size > DFU_BANK_0_REGION_START) { uint32_t page_mask = (CODE_PAGE_SIZE - 1); uint32_t diff = m_start_packet.sd_image_size - DFU_BANK_0_REGION_START; - + offset = diff & ~page_mask; - + // Align offset to next page if image size is not page sized. if ((diff & page_mask) > 0) { @@ -204,8 +235,7 @@ static uint32_t dfu_activate_sd(void) */ static uint32_t dfu_activate_app(void) { - uint32_t err_code = NRF_SUCCESS; - dfu_update_status_t update_status; + dfu_update_status_t update_status = { 0 }; memset(&update_status, 0, sizeof(dfu_update_status_t )); update_status.status_code = DFU_UPDATE_APP_COMPLETE; @@ -214,7 +244,7 @@ static uint32_t dfu_activate_app(void) bootloader_dfu_update_process(update_status); - return err_code; + return NRF_SUCCESS; } @@ -228,7 +258,7 @@ static uint32_t dfu_activate_app(void) */ static uint32_t dfu_activate_bl(void) { - dfu_update_status_t update_status; + dfu_update_status_t update_status = {0}; update_status.status_code = DFU_UPDATE_BOOT_COMPLETE; update_status.app_crc = m_image_crc; @@ -249,11 +279,6 @@ uint32_t dfu_init(void) m_init_packet_length = 0; m_image_crc = 0; - - // Reset lazy erase state - dfu_page_erased = NULL; - dfu_image_page_count = 0; - dfu_base_address = 0; err_code = pstorage_register(&storage_module_param, &m_storage_handle_app); if (err_code != NRF_SUCCESS) @@ -264,6 +289,16 @@ uint32_t dfu_init(void) m_storage_handle_app.block_id = DFU_BANK_0_REGION_START; + // Create the timer to monitor the activity by the peer doing the firmware update. + err_code = app_timer_create(&m_dfu_timer_id, + APP_TIMER_MODE_SINGLE_SHOT, + dfu_timeout_handler); + APP_ERROR_CHECK(err_code); + + // Start the DFU timer. + err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); + APP_ERROR_CHECK(err_code); + m_data_received = 0; m_dfu_state = DFU_STATE_IDLE; @@ -279,6 +314,8 @@ void dfu_register_callback(dfu_callback_t callback_handler) uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) { + uint32_t err_code; + m_start_packet = *(p_packet->params.start_packet); // Check that the requested update procedure is supported. @@ -287,7 +324,7 @@ uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) // - SoftDevice // - Bootloader // - SoftDevice with Bootloader - if (IS_UPDATING_APP(m_start_packet) && + if (IS_UPDATING_APP(m_start_packet) && (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet))) { // App update is only supported independently. @@ -304,7 +341,7 @@ uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size + m_start_packet.app_image_size; - + if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE) { return NRF_ERROR_DATA_SIZE; @@ -316,7 +353,7 @@ uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) } m_functions.prepare = dfu_prepare_func_app_erase; m_functions.cleared = dfu_cleared_func_app; - + if (IS_UPDATING_SD(m_start_packet)) { m_functions.activate = dfu_activate_sd; @@ -332,6 +369,10 @@ uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) if ( DFU_STATE_IDLE != m_dfu_state ) return NRF_ERROR_INVALID_STATE; + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + m_functions.prepare(m_image_size); return NRF_SUCCESS; @@ -374,12 +415,24 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) return NRF_ERROR_DATA_SIZE; } + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet; if ( is_ota() ) { - err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); - VERIFY_SUCCESS(err_code); + while(1) { + err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + VERIFY_SUCCESS(err_code); } else { @@ -396,7 +449,7 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) } else { - if ( !is_ota() ) flash_nrf5x_flush(false); + if ( !is_ota() ) flash_nrf5x_flush(false); // The entire image has been received. Return NRF_SUCCESS. err_code = NRF_SUCCESS; @@ -415,14 +468,14 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) uint32_t dfu_init_pkt_complete(void) { uint32_t err_code = NRF_ERROR_INVALID_STATE; - + // DFU initialization has been done and a start packet has been received. if (IMAGE_WRITE_IN_PROGRESS()) { // Image write is already in progress. Cannot handle an init packet now. return NRF_ERROR_INVALID_STATE; } - + if (m_dfu_state == DFU_STATE_RX_INIT_PKT) { err_code = dfu_init_prevalidate(m_init_packet, m_init_packet_length, m_start_packet.dfu_update_mode); @@ -441,6 +494,7 @@ uint32_t dfu_init_pkt_complete(void) uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) { + uint32_t err_code = NRF_SUCCESS; uint32_t length; switch (m_dfu_state) @@ -458,6 +512,10 @@ uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) return NRF_ERROR_INVALID_STATE; } + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); if ((m_init_packet_length + length) > sizeof(m_init_packet)) { @@ -497,9 +555,16 @@ uint32_t dfu_image_validate() { m_dfu_state = DFU_STATE_VALIDATE; - err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id, m_image_size); - VERIFY_SUCCESS(err_code); - m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + if (err_code == NRF_SUCCESS) + { + err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id, + m_image_size); + VERIFY_SUCCESS(err_code); + + m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; + } } break; @@ -519,6 +584,11 @@ uint32_t dfu_image_activate() switch (m_dfu_state) { case DFU_STATE_WAIT_4_ACTIVATE: + + // Stop the DFU Timer because the peer activity need not be monitored any longer. + err_code = app_timer_stop(m_dfu_timer_id); + APP_ERROR_CHECK(err_code); + err_code = m_functions.activate(); break; @@ -533,10 +603,18 @@ uint32_t dfu_image_activate() void dfu_reset(void) { - dfu_update_status_t update_status; + dfu_update_status_t update_status = { 0 }; update_status.status_code = DFU_RESET; + // If we are still receiving packets, and we are expecting more of them, + // and we receive the RESET command, this means the DFU app is trying + // to interrupt and recover a failed previous attempt of FLASHing a new + // application. Make sure to reboot into DFU mode instead of starting + // a previously stored application (specially valid for double bank + // bootloaders + update_status.restart_into_bootloader = (m_dfu_state == DFU_STATE_RX_DATA_PKT && m_data_received != m_image_size); + bootloader_dfu_update_process(update_status); } @@ -567,13 +645,13 @@ static uint32_t dfu_copy_sd(uint32_t * src, uint32_t * dst, uint32_t len) } -static uint32_t dfu_sd_img_block_swap(uint32_t * src, - uint32_t * dst, - uint32_t len, +static uint32_t dfu_sd_img_block_swap(uint32_t * src, + uint32_t * dst, + uint32_t len, uint32_t block_size) { // It is neccesarry to swap the new SoftDevice in 3 rounds to ensure correct copy of data - // and verifucation of data in case power reset occurs during write to flash. + // and verification of data in case power reset occurs during write to flash. // To ensure the robustness of swapping the images are compared backwards till start of // image swap. If the back is identical everything is swapped. uint32_t err_code = dfu_compare_block(src, dst, len); @@ -584,9 +662,9 @@ static uint32_t dfu_sd_img_block_swap(uint32_t * src, if ((uint32_t)dst > SOFTDEVICE_REGION_START) { - err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size), - (uint32_t *)((uint32_t)dst - block_size), - block_size, + err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size), + (uint32_t *)((uint32_t)dst - block_size), + block_size, block_size); VERIFY_SUCCESS(err_code); } @@ -608,37 +686,37 @@ uint32_t dfu_sd_image_swap(void) { return NRF_SUCCESS; } - + if ((SOFTDEVICE_REGION_START + boot_settings.sd_image_size) > boot_settings.sd_image_start) { uint32_t err_code; uint32_t sd_start = SOFTDEVICE_REGION_START; uint32_t block_size = (boot_settings.sd_image_start - sd_start) / 2; - + /* ##### FIX START ##### */ - block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); - /* ##### FIX END ##### */ - + block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); + /* ##### FIX END ##### */ + uint32_t image_end = boot_settings.sd_image_start + boot_settings.sd_image_size; uint32_t img_block_start = boot_settings.sd_image_start + 2 * block_size; uint32_t sd_block_start = sd_start + 2 * block_size; - + if (SD_SIZE_GET(MBR_SIZE) < boot_settings.sd_image_size) { // This will clear a page thus ensuring the old image is invalidated before swapping. - err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size), - (uint32_t *)(sd_start + block_size), + err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size), + (uint32_t *)(sd_start + block_size), sizeof(uint32_t)); VERIFY_SUCCESS(err_code); err_code = dfu_copy_sd((uint32_t *)sd_start, (uint32_t *)sd_start, sizeof(uint32_t)); VERIFY_SUCCESS(err_code); } - - return dfu_sd_img_block_swap((uint32_t *)img_block_start, - (uint32_t *)sd_block_start, - image_end - img_block_start, + + return dfu_sd_img_block_swap((uint32_t *)img_block_start, + (uint32_t *)sd_block_start, + image_end - img_block_start, block_size); } else @@ -646,7 +724,7 @@ uint32_t dfu_sd_image_swap(void) if (boot_settings.sd_image_size != 0) { return dfu_copy_sd((uint32_t *)boot_settings.sd_image_start, - (uint32_t *)SOFTDEVICE_REGION_START, + (uint32_t *)SOFTDEVICE_REGION_START, boot_settings.sd_image_size); } } @@ -666,7 +744,7 @@ uint32_t dfu_bl_image_swap(void) { uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ? DFU_BANK_0_REGION_START : - bootloader_settings.sd_image_start + + bootloader_settings.sd_image_start + bootloader_settings.sd_image_size; sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_BL; @@ -678,27 +756,54 @@ uint32_t dfu_bl_image_swap(void) return NRF_SUCCESS; } - uint32_t dfu_bl_image_validate(void) { bootloader_settings_t bootloader_settings; - sd_mbr_command_t sd_mbr_cmd; + + sd_mbr_command_t sd_mbr_cmd_1; + sd_mbr_command_t sd_mbr_cmd_2; bootloader_settings_get(&bootloader_settings); if (bootloader_settings.bl_image_size != 0) { - uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ? + /* + * The problem with updating the bootloader from a dual to single bank bootloader is that the new + * bootloader expects the firmware image to be at the start of BANK 0, while it's actually loaded + * to BANK1 by the old bootloader. After the update the new single bank bootloader verifies that + * the image was correctly written to flash by comparing itself with the firmware image that it + * expects to be located in BANK0. Since the actual firmware image is in BANK 1 this check will + * fail and the new bootloader updates itself with whatever data located in BANK0 using the MBR. + + * The fix is to modify the dfu_bl_image_validate() function in dfu_single_bank.c run verification + * on both addresses (BANK0 and BANK1) + */ + uint32_t bl_image_start_1 = (bootloader_settings.sd_image_size == 0) ? DFU_BANK_0_REGION_START : bootloader_settings.sd_image_start + bootloader_settings.sd_image_size; - sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; - sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; - sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)(bl_image_start); - sd_mbr_cmd.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + sd_mbr_cmd_1.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd_1.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; + sd_mbr_cmd_1.params.compare.ptr2 = (uint32_t *)(bl_image_start_1); + sd_mbr_cmd_1.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); - return sd_mbr_command(&sd_mbr_cmd); + uint32_t err_code = sd_mbr_command(&sd_mbr_cmd_1); + if (err_code == NRF_SUCCESS) { + return NRF_SUCCESS; + } + + uint32_t bl_image_start_2 = (bootloader_settings.sd_image_size == 0) ? + DFU_BANK_1_REGION_START : + bootloader_settings.sd_image_start + + bootloader_settings.sd_image_size; + + sd_mbr_cmd_2.command = SD_MBR_COMMAND_COMPARE; + sd_mbr_cmd_2.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; + sd_mbr_cmd_2.params.compare.ptr2 = (uint32_t *)(bl_image_start_2); + sd_mbr_cmd_2.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + + return sd_mbr_command(&sd_mbr_cmd_2); } return NRF_SUCCESS; } @@ -715,17 +820,18 @@ uint32_t dfu_sd_image_validate(void) { return NRF_SUCCESS; } - + if ((SOFTDEVICE_REGION_START + bootloader_settings.sd_image_size) > bootloader_settings.sd_image_start) { uint32_t sd_start = SOFTDEVICE_REGION_START; uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2; - uint32_t image_end = bootloader_settings.sd_image_start + + uint32_t image_end = bootloader_settings.sd_image_start + bootloader_settings.sd_image_size; /* ##### FIX START ##### */ - block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); - /* ##### FIX END ##### */ + block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); + /* ##### FIX END ##### */ + uint32_t img_block_start = bootloader_settings.sd_image_start + 2 * block_size; uint32_t sd_block_start = sd_start + 2 * block_size; @@ -734,12 +840,12 @@ uint32_t dfu_sd_image_validate(void) return NRF_ERROR_NULL; } - return dfu_sd_img_block_swap((uint32_t *)img_block_start, - (uint32_t *)sd_block_start, - image_end - img_block_start, + return dfu_sd_img_block_swap((uint32_t *)img_block_start, + (uint32_t *)sd_block_start, + image_end - img_block_start, block_size); } - + sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)SOFTDEVICE_REGION_START; sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)bootloader_settings.sd_image_start; diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_ble.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_ble.c index fd2e3dedc..98b8506de 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_ble.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_ble.c @@ -35,11 +35,6 @@ #include "nrf_delay.h" #include "sdk_common.h" - -#define BLEGAP_EVENT_LENGTH 6 -#define BLEGATT_ATT_MTU_MAX 247 -enum { BLE_CONN_CFG_HIGH_BANDWIDTH = 1 }; - #define DFU_REV_MAJOR 0x00 /** DFU Major revision number to be exposed. */ #define DFU_REV_MINOR 0x08 /** DFU Minor revision number to be exposed. */ #define DFU_REVISION ((DFU_REV_MAJOR << 8) | DFU_REV_MINOR) /** DFU Revision number to be exposed. Combined of major and minor versions. */ @@ -49,16 +44,17 @@ enum { BLE_CONN_CFG_HIGH_BANDWIDTH = 1 }; // limit of 8 chars #ifndef DEVICE_NAME #define DEVICE_NAME "AdaDFU" /**< Name of device. Will be included in the advertising data. */ -#endif //DEVICE_NAME +#endif -#define MIN_CONN_INTERVAL (uint16_t)(MSEC_TO_UNITS(10, UNIT_1_25_MS)) /**< Minimum acceptable connection interval (11.25 milliseconds). */ +#define MIN_CONN_INTERVAL (uint16_t)(MSEC_TO_UNITS(15, UNIT_1_25_MS)) /**< Minimum acceptable connection interval (11.25 milliseconds). */ #define MAX_CONN_INTERVAL (uint16_t)(MSEC_TO_UNITS(30, UNIT_1_25_MS)) /**< Maximum acceptable connection interval (15 milliseconds). */ -#define SLAVE_LATENCY 0 /**< Slave latency. */ -#define CONN_SUP_TIMEOUT (4 * 100) /**< Connection supervisory timeout (4 seconds). */ +#define SLAVE_LATENCY 4 /**< Slave latency. */ +#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(8000, UNIT_10_MS) /**< Connection supervisory timeout (4 seconds). */ +#define SPEEDUP_FLASH_WRITES 1 /**< Speedup FLASH writes by changing Softdevice local latency */ #define APP_ADV_INTERVAL MSEC_TO_UNITS(25, UNIT_0_625_MS) /**< The advertising interval (25 ms.). */ #define APP_ADV_TIMEOUT BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising timeout in units of seconds. This is set to @ref BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED so that the advertisement is done as long as there there is a call to @ref dfu_transport_close function.*/ -#define APP_DIRECTED_ADV_TIMEOUT 50 /**< number of direct advertisement (each lasting 1.28seconds). */ +#define APP_DIRECTED_ADV_TIMEOUT 50 /**< number of direct advertisement (each lasting 1.28seconds). */ #define PEER_ADDRESS_TYPE_INVALID 0xFF /**< Value indicating that no valid peer address exists. This will be the case when a private resolvable address is used in which case there is no address available but instead an IRK is present. */ #define PEER_ADDRESS_TYPE_INVALID 0xFF /**< Value indicating that no valid peer address exists. This will be the case when a private resolvable address is used in which case there is no address available but instead an IRK is present. */ @@ -77,8 +73,9 @@ enum { BLE_CONN_CFG_HIGH_BANDWIDTH = 1 }; #define IS_CONNECTED() (m_conn_handle != BLE_CONN_HANDLE_INVALID) /**< Macro to determine if the device is in connected state. */ -#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */ -#define SD_IMAGE_SIZE_OFFSET 0 /**< Offset in start packet for the size information for SoftDevice. */ +#define APP_FEATURE_NOT_SUPPORTED \ + (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2) /**< Reply when unsupported features are requested. */ +#define SD_IMAGE_SIZE_OFFSET 0 /**< Offset in start packet for the size information for SoftDevice. */ #define BL_IMAGE_SIZE_OFFSET 4 /**< Offset in start packet for the size information for bootloader. */ #define APP_IMAGE_SIZE_OFFSET 8 /**< Offset in start packet for the size information for application. */ @@ -123,13 +120,6 @@ static uint8_t * mp_final_packet; static ble_gap_addr_t const * m_whitelist[1]; /**< List of peers in whitelist (only one) */ static ble_gap_id_key_t const * m_gap_ids[1]; -static ble_gap_data_length_params_t m_dl_params = { - .max_tx_octets = 251, - .max_rx_octets = 251, - .max_tx_time_us = BLE_GAP_DATA_LENGTH_AUTO, - .max_rx_time_us = BLE_GAP_DATA_LENGTH_AUTO -}; - // Adafruit static uint8_t _adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; @@ -227,7 +217,35 @@ static ble_dfu_resp_val_t nrf_err_code_translate(uint32_t err_c } } +#ifdef SPEEDUP_FLASH_WRITES +static void prioritize_ble_over_flash_writes(void) { + // We set the local latency to 0: That will revert latency to the negotiated one with the host. + // That will increase throughput to the maximum possible + ble_opt_t opt; + varclr(&opt); + opt.gap_opt.local_conn_latency.conn_handle = m_conn_handle; /**< Connection Handle */ + opt.gap_opt.local_conn_latency.requested_latency = 0; /**< Requested local connection latency. */ + opt.gap_opt.local_conn_latency.p_actual_latency = + NULL; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return value). */ + sd_ble_opt_set(BLE_GAP_OPT_LOCAL_CONN_LATENCY, &opt); +} +static void prioritize_flash_writes_over_ble(void) { + // We set the local latency to the maximum possible: That will make FLASH writes faster, as BLE comms will + // be delayed (even losing RXd packets, but this is the same as a poor connection and will be handled by + // the protocol itself) + ble_opt_t opt; + varclr(&opt); + opt.gap_opt.local_conn_latency.conn_handle = m_conn_handle; /**< Connection Handle */ + opt.gap_opt.local_conn_latency.requested_latency = 50; /**< Requested local connection latency. */ + opt.gap_opt.local_conn_latency.p_actual_latency = + NULL; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return value). */ + sd_ble_opt_set(BLE_GAP_OPT_LOCAL_CONN_LATENCY, &opt); +} +#else + #define prioritize_ble_over_flash_writes() + #define prioritize_flash_writes_over_ble() +#endif /**@brief Function for handling the callback events from the dfu module. * Callbacks are expected when \ref dfu_data_pkt_handle has been executed. * @@ -245,6 +263,9 @@ static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data) case DATA_PACKET: if (result != NRF_SUCCESS) { + // Restore latency to the negotiated one + prioritize_ble_over_flash_writes(); + // Disconnect from peer. if (IS_CONNECTED()) { @@ -261,6 +282,9 @@ static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data) // If the callback matches final data packet received then the peer is notified. if (mp_final_packet == p_data) { + // Restore latency to the negotiated one + prioritize_ble_over_flash_writes(); + // Notify the DFU Controller about the success of the procedure. err_code = ble_dfu_response_send(&m_dfu, BLE_DFU_RECEIVE_APP_PROCEDURE, @@ -271,6 +295,10 @@ static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data) break; case START_PACKET: + + // Restore latency to the negotiated one + prioritize_ble_over_flash_writes(); + // Translate the err_code returned by the above function to DFU Response Value. resp_val = nrf_err_code_translate(result, BLE_DFU_START_PROCEDURE); @@ -343,6 +371,9 @@ static void start_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) start_packet.bl_image_size = uint32_decode(p_length_data + BL_IMAGE_SIZE_OFFSET); start_packet.app_image_size = uint32_decode(p_length_data + APP_IMAGE_SIZE_OFFSET); + // Prioritize FLASH writes over BLE comms + prioritize_flash_writes_over_ble(); + // Store the reported image size for use by the accumulator logic m_reported_image_size = start_packet.sd_image_size + start_packet.bl_image_size + @@ -351,6 +382,9 @@ static void start_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) err_code = dfu_start_pkt_handle(&update_packet); if (err_code != NRF_SUCCESS) { + // Prioritize BLE over flash writes + prioritize_ble_over_flash_writes(); + // Translate the err_code returned by the above function to DFU Response Value. ble_dfu_resp_val_t resp_val; @@ -910,13 +944,22 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: - m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; - m_is_advertising = false; + { + m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; + m_is_advertising = false; - // APP_ERROR_CHECK( sd_ble_gattc_exchange_mtu_request(m_conn_handle, BLEGATT_ATT_MTU_MAX) ); + // Force changing the slave latency to try to improve transfer throughput (bandwidth) + // But Android and IOS will override it with their minimum supported value + ble_gap_conn_params_t p_conn_params; + p_conn_params.min_conn_interval = p_ble_evt->evt.gap_evt.params.connected.conn_params.min_conn_interval; + p_conn_params.max_conn_interval = p_ble_evt->evt.gap_evt.params.connected.conn_params.max_conn_interval; + p_conn_params.slave_latency = SLAVE_LATENCY; + p_conn_params.conn_sup_timeout = p_ble_evt->evt.gap_evt.params.connected.conn_params.conn_sup_timeout; - sd_ble_gap_data_length_update(m_conn_handle, &m_dl_params, NULL); + err_code = sd_ble_gap_conn_param_update(m_conn_handle, &p_conn_params); + APP_ERROR_CHECK(err_code); + } break; case BLE_GAP_EVT_DISCONNECTED: @@ -946,6 +989,9 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) break; + case BLE_GAP_EVT_CONN_PARAM_UPDATE: + break; + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { ble_gap_sec_keyset_t keys; @@ -1058,7 +1104,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: // Let Softdevice decide the data length // ble_gap_data_length_params_t* param = &evt->evt.gap_evt.params.data_length_update_request.peer_params - APP_ERROR_CHECK( sd_ble_gap_data_length_update(m_conn_handle, &m_dl_params, NULL) ); + APP_ERROR_CHECK( sd_ble_gap_data_length_update(m_conn_handle, NULL, NULL) ); break; case BLE_GAP_EVT_PHY_UPDATE_REQUEST: @@ -1072,6 +1118,11 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { uint16_t att_mtu = MIN(p_ble_evt->evt.gatts_evt.params.exchange_mtu_request.client_rx_mtu, BLEGATT_ATT_MTU_MAX); + + // Round it to a multiple of 4 plus 3 bytes, as we need data packets to be multiple of 4 bytes + att_mtu &= 0xFFFCU; + att_mtu |= 3; + PRINTF("GAP ATT MTU is changed to %d\r\n", att_mtu); APP_ERROR_CHECK( sd_ble_gatts_exchange_mtu_reply(m_conn_handle, att_mtu) ); } diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c index 71f08526a..e27d600c9 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c @@ -12,6 +12,7 @@ #include "dfu_transport.h" #include +#include "bootloader.h" #include "dfu.h" #include #include "app_error.h" @@ -197,9 +198,8 @@ static void process_dfu_packet(void * p_event_data, uint16_t event_size) uint32_t index; dfu_update_packet_t * packet; - // Adafruit modification for startup dfu - extern bool dfu_startup_packet_received; - dfu_startup_packet_received = true; + // Mark that startup DFU has transitioned into a real update flow. + bootloader_dfu_activity_mark(); while (false == DATA_QUEUE_EMPTY()) { diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_types.h b/lib/sdk11/components/libraries/bootloader_dfu/dfu_types.h index 4148e1c9f..665f9c489 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_types.h +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_types.h @@ -20,10 +20,42 @@ * @brief Device Firmware Update module type and definitions. */ +/* + * Flash layout (nrf52840, see linker/nrf52840.ld): + * + * ------------------------- + * | Bootloader Settings | + * | 4 KB | + * |-------------------------| 0xFF000 BOOTLOADER_SETTINGS_ADDRESS + * | MBR Params Page | + * | 4 KB | + * |-------------------------| 0xFE000 + * | Bootloader Config | + * | 2 KB | + * |-------------------------| 0xFD800 + * | Bootloader | + * | 38 KB | + * |-------------------------| 0xF4000 BOOTLOADER_REGION_START + * | App Data Reserved | + * | 40 KB | + * |-------------------------| 0xEA000 + * | Application | + * | Single/ Dual Bank | + * | | + * |-------------------------| CODE_REGION_1_START + * | SoftDevice | + * | 0x26000 (optional) | + * |-------------------------| 0x01000 + * | MBR | + * | 4 KB | + * ------------------------- 0x00000 + */ + #ifndef DFU_TYPES_H__ #define DFU_TYPES_H__ #include +#include #include "nrf_sdm.h" #include "nrf_mbr.h" #include "nrf.h" @@ -74,8 +106,12 @@ static inline bool is_sd_existed(void) #endif #define DFU_IMAGE_MAX_SIZE_FULL (DFU_REGION_TOTAL_SIZE - DFU_APP_DATA_RESERVED) /**< Maximum size of an application, excluding save data from the application. */ +#define DFU_IMAGE_MAX_SIZE_BANKED (((DFU_IMAGE_MAX_SIZE_FULL) - \ + (DFU_IMAGE_MAX_SIZE_FULL % (2 * CODE_PAGE_SIZE)))/2) /**< Maximum size of an application, excluding save data from the application. */ + #define DFU_BL_IMAGE_MAX_SIZE (BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_REGION_START) /**< Maximum size of a bootloader, excluding save data from the current bootloader. */ #define DFU_BANK_0_REGION_START CODE_REGION_1_START /**< Bank 0 region start. */ +#define DFU_BANK_1_REGION_START (DFU_BANK_0_REGION_START + DFU_IMAGE_MAX_SIZE_BANKED) /**< Bank 1 region start. */ #define EMPTY_FLASH_MASK 0xFFFFFFFF /**< Bit mask that defines an empty address in flash. */ @@ -150,6 +186,7 @@ typedef struct uint32_t bl_size; /**< Size of the recieved BootLoader. */ uint32_t app_size; /**< Size of the recieved Application. */ uint32_t sd_image_start; /**< Location in flash where the received SoftDevice image is stored. */ + bool restart_into_bootloader; /**< If the chip must be reset and must reenter bootloader mode. */ } dfu_update_status_t; /**@brief Update complete handler type. */ diff --git a/lib/tinycrypt b/lib/tinycrypt new file mode 160000 index 000000000..cf24c907a --- /dev/null +++ b/lib/tinycrypt @@ -0,0 +1 @@ +Subproject commit cf24c907a61c01bc2c4e1ee0ae24457c27a840a2 diff --git a/lib/tinyusb b/lib/tinyusb index 7800876bf..9775e7691 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 7800876bf151a239046521232dc4603b156061be +Subproject commit 9775e76910d569ec73b8dd946f3fa5fe5414acdb diff --git a/lib/uf2 b/lib/uf2 index 90e9741f2..b19ac9ad6 160000 --- a/lib/uf2 +++ b/lib/uf2 @@ -1 +1 @@ -Subproject commit 90e9741f217f5a40c98ba74d663e408041037578 +Subproject commit b19ac9ad613e11a062e4d00845e2b80e6b0ad29f diff --git a/linker/nrf52.ld b/linker/nrf52.ld index 756e4905e..f5bd6ce80 100644 --- a/linker/nrf52.ld +++ b/linker/nrf52.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc -lnosys)*/ MEMORY { @@ -19,8 +19,6 @@ MEMORY /** Location of bootloader setting in flash. */ BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x7F000, LENGTH = 0x1000 - - /** RAM Region for bootloader. */ RAM (rwx) : ORIGIN = 0x20008000, LENGTH = 0x20010000-0x20008000 @@ -30,8 +28,6 @@ MEMORY /** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information * from application to bootloader when using buttonless DFU OTA. */ NOINIT (rwx) : ORIGIN = 0x20007F80, LENGTH = 0x80 - - /** Location in UICR where bootloader start address is stored. */ UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04 diff --git a/linker/nrf52833.ld b/linker/nrf52833.ld index 49d8350f4..72af5959e 100644 --- a/linker/nrf52833.ld +++ b/linker/nrf52833.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc -lnosys)*/ MEMORY { diff --git a/linker/nrf52833_debug.ld b/linker/nrf52833_debug.ld index ed8f35862..f11073899 100644 --- a/linker/nrf52833_debug.ld +++ b/linker/nrf52833_debug.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc)*/ MEMORY { diff --git a/linker/nrf52840.ld b/linker/nrf52840.ld index 5eec85ed3..6d426f894 100644 --- a/linker/nrf52840.ld +++ b/linker/nrf52840.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc -lnosys)*/ MEMORY { @@ -21,8 +21,6 @@ MEMORY /** Location of bootloader setting in flash. */ BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 - - /** RAM Region for bootloader. */ /* Avoid conflict with NOINIT for OTA bond sharing */ RAM (rwx) : ORIGIN = 0x20008000, LENGTH = 0x20040000-0x20008000 @@ -33,9 +31,7 @@ MEMORY /** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information * from application to bootloader when using buttonless DFU OTA. */ NOINIT (rwx) : ORIGIN = 0x20007F80, LENGTH = 0x80 - - - + /** Location in UICR where bootloader start address is stored. */ UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04 @@ -91,7 +87,6 @@ SECTIONS { } > NOINIT - /* other placements follow here... */ } diff --git a/linker/nrf52840_debug.ld b/linker/nrf52840_debug.ld index 7c68a8307..4c8e794a1 100644 --- a/linker/nrf52840_debug.ld +++ b/linker/nrf52840_debug.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc)*/ MEMORY { diff --git a/linker/nrf52_debug.ld b/linker/nrf52_debug.ld index b04b36a72..27ab4ce74 100644 --- a/linker/nrf52_debug.ld +++ b/linker/nrf52_debug.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc)*/ MEMORY { diff --git a/linker/nrf_common.ld b/linker/nrf_common.ld index 912250f92..1aba21736 100644 --- a/linker/nrf_common.ld +++ b/linker/nrf_common.ld @@ -123,19 +123,6 @@ SECTIONS } > RAM - /* nrfx's gcc_startup_*.S (since nrfx 3.x) copies .data via these - * non-double-underscore names, plus three more RAM-loaded regions - * (.sdata/.tdata/.fast) this board never places anything into. - * Aliased/zero-length here rather than pulled from nrfx's own - * nrf_common.ld, which also redefines .noinit/.bss placement that - * this bootloader deliberately overrides per-board (see linker/nrf52840.ld). */ - __data_start = __data_start__; - __data_end = __data_end__; - __data_load_start = __etext; - __sdata_start = .; __sdata_end = .; __sdata_load_start = .; - __tdata_start = .; __tdata_end = .; __tdata_load_start = .; - __fast_start = .; __fast_end = .; __fast_load_start = .; - .bss : { . = ALIGN(4); diff --git a/segger/Adafruit_nRF52_Bootloader.emProject b/segger/Adafruit_nRF52_Bootloader.emProject deleted file mode 100644 index 8084a4d7e..000000000 --- a/segger/Adafruit_nRF52_Bootloader.emProject +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/segger/SEGGER_RTT.c b/segger/SEGGER_RTT.c deleted file mode 100644 index aee5bd21e..000000000 --- a/segger/SEGGER_RTT.c +++ /dev/null @@ -1,1329 +0,0 @@ -/********************************************************************* -* SEGGER MICROCONTROLLER GmbH & Co. KG * -* Solutions for real time microcontroller applications * -********************************************************************** -* * -* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* * This software may in its unmodified form be freely redistributed * -* in source form. * -* * The source code may be modified, provided the source code * -* retains the above copyright notice, this list of conditions and * -* the following disclaimer. * -* * Modified versions of this software in source or linkable form * -* may not be distributed without prior consent of SEGGER. * -* * This software may only be used for communication with SEGGER * -* J-Link debug probes. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** -* * -* RTT version: 5.12e * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT.c -Purpose : Implementation of SEGGER real-time transfer (RTT) which - allows real-time communication on targets which support - debugger memory accesses while the CPU is running. - -Additional information: - Type "int" is assumed to be 32-bits in size - H->T Host to target communication - T->H Target to host communication - - RTT channel 0 is always present and reserved for Terminal usage. - Name is fixed to "Terminal" - - Effective buffer size: SizeOfBuffer - 1 - - WrOff == RdOff: Buffer is empty - WrOff == (RdOff - 1): Buffer is full - WrOff > RdOff: Free space includes wrap-around - WrOff < RdOff: Used space includes wrap-around - (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): - Buffer full and wrap-around after next byte - - ----------------------------------------------------------------------- -*/ - -#include "SEGGER_RTT.h" - -#include // for memcpy - -/********************************************************************* -* -* Configuration, default values -* -********************************************************************** -*/ - -#ifndef BUFFER_SIZE_UP - #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host -#endif - -#ifndef BUFFER_SIZE_DOWN - #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) -#endif - -#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS - #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target -#endif - -#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS - #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target -#endif - -#ifndef SEGGER_RTT_BUFFER_SECTION - #if defined SEGGER_RTT_SECTION - #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION - #endif -#endif - -#ifndef SEGGER_RTT_MODE_DEFAULT - #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP -#endif - -#ifndef SEGGER_RTT_LOCK - #define SEGGER_RTT_LOCK() -#endif - -#ifndef SEGGER_RTT_UNLOCK - #define SEGGER_RTT_UNLOCK() -#endif - -#ifndef STRLEN - #define STRLEN(a) strlen((a)) -#endif - -#ifndef MEMCPY - #define MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) -#endif - -#ifndef MIN - #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef MAX - #define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif -// -// For some environments, NULL may not be defined until certain headers are included -// -#ifndef NULL - #define NULL 0 -#endif - -/********************************************************************* -* -* Static const data -* -********************************************************************** -*/ - -static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - -/********************************************************************* -* -* Static data -* -********************************************************************** -*/ -// -// RTT Control Block and allocate buffers for channel 0 -// -#ifdef SEGGER_RTT_SECTION - #if (defined __GNUC__) - __attribute__ ((section (SEGGER_RTT_SECTION))) SEGGER_RTT_CB _SEGGER_RTT; - #elif (defined __ICCARM__) || (defined __ICCRX__) - #pragma location=SEGGER_RTT_SECTION - SEGGER_RTT_CB _SEGGER_RTT; - #elif (defined __CC_ARM__) - __attribute__ ((section (SEGGER_RTT_SECTION), zero_init)) SEGGER_RTT_CB _SEGGER_RTT; - #else - SEGGER_RTT_CB _SEGGER_RTT; - #endif -#else - SEGGER_RTT_CB _SEGGER_RTT; -#endif - -#ifdef SEGGER_RTT_BUFFER_SECTION - #if (defined __GNUC__) - __attribute__ ((section (SEGGER_RTT_BUFFER_SECTION))) static char _acUpBuffer [BUFFER_SIZE_UP]; - __attribute__ ((section (SEGGER_RTT_BUFFER_SECTION))) static char _acDownBuffer[BUFFER_SIZE_DOWN]; - #elif (defined __ICCARM__) || (defined __ICCRX__) - #pragma location=SEGGER_RTT_BUFFER_SECTION - static char _acUpBuffer [BUFFER_SIZE_UP]; - #pragma location=SEGGER_RTT_BUFFER_SECTION - static char _acDownBuffer[BUFFER_SIZE_DOWN]; - #elif (defined __CC_ARM__) - __attribute__ ((section (SEGGER_RTT_BUFFER_SECTION), zero_init)) static char _acUpBuffer [BUFFER_SIZE_UP]; - __attribute__ ((section (SEGGER_RTT_BUFFER_SECTION), zero_init)) static char _acDownBuffer[BUFFER_SIZE_DOWN]; - #else - static char _acUpBuffer [BUFFER_SIZE_UP]; - static char _acDownBuffer[BUFFER_SIZE_DOWN]; - #endif -#else - static char _acUpBuffer [BUFFER_SIZE_UP]; - static char _acDownBuffer[BUFFER_SIZE_DOWN]; -#endif - -static char _ActiveTerminal; - -/********************************************************************* -* -* Static functions -* -********************************************************************** -*/ - -/********************************************************************* -* -* _DoInit() -* -* Function description -* Initializes the control block an buffers. -* May only be called via INIT() to avoid overriding settings. -* -*/ -#define INIT() do { \ - if (_SEGGER_RTT.acID[0] == '\0') { _DoInit(); } \ - } while (0) -static void _DoInit(void) { - SEGGER_RTT_CB* p; - // - // Initialize control block - // - p = &_SEGGER_RTT; - p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; - p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; - // - // Initialize up buffer 0 - // - p->aUp[0].sName = "Terminal"; - p->aUp[0].pBuffer = _acUpBuffer; - p->aUp[0].SizeOfBuffer = sizeof(_acUpBuffer); - p->aUp[0].RdOff = 0u; - p->aUp[0].WrOff = 0u; - p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; - // - // Initialize down buffer 0 - // - p->aDown[0].sName = "Terminal"; - p->aDown[0].pBuffer = _acDownBuffer; - p->aDown[0].SizeOfBuffer = sizeof(_acDownBuffer); - p->aDown[0].RdOff = 0u; - p->aDown[0].WrOff = 0u; - p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; - // - // Finish initialization of the control block. - // Copy Id string in three steps to make sure "SEGGER RTT" is not found - // in initializer memory (usually flash) by J-Link - // - strcpy(&p->acID[7], "RTT"); - strcpy(&p->acID[0], "SEGGER"); - p->acID[6] = ' '; -} - -/********************************************************************* -* -* _WriteBlocking() -* -* Function description -* Stores a specified number of characters in SEGGER RTT ring buffer -* and updates the associated write pointer which is periodically -* read by the host. -* The caller is responsible for managing the write chunk sizes as -* _WriteBlocking() will block until all data has been posted successfully. -* -* Parameters -* pRing Ring buffer to post to. -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Return value -* >= 0 - Number of bytes written into buffer. -*/ -static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) { - unsigned NumBytesToWrite; - unsigned NumBytesWritten; - unsigned RdOff; - unsigned WrOff; - // - // Write data to buffer and handle wrap-around if necessary - // - NumBytesWritten = 0u; - WrOff = pRing->WrOff; - do { - RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime - if (RdOff > WrOff) { - NumBytesToWrite = RdOff - WrOff - 1u; - } else { - NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); - } - NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around - NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); - memcpy(pRing->pBuffer + WrOff, pBuffer, NumBytesToWrite); - NumBytesWritten += NumBytesToWrite; - pBuffer += NumBytesToWrite; - NumBytes -= NumBytesToWrite; - WrOff += NumBytesToWrite; - if (WrOff == pRing->SizeOfBuffer) { - WrOff = 0u; - } - pRing->WrOff = WrOff; - } while (NumBytes); - // - return NumBytesWritten; -} - -/********************************************************************* -* -* _WriteNoCheck() -* -* Function description -* Stores a specified number of characters in SEGGER RTT ring buffer -* and updates the associated write pointer which is periodically -* read by the host. -* It is callers responsibility to make sure data actually fits in buffer. -* -* Parameters -* pRing Ring buffer to post to. -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Notes -* (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking -*/ -static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) { - unsigned NumBytesAtOnce; - unsigned WrOff; - unsigned Rem; - - WrOff = pRing->WrOff; - Rem = pRing->SizeOfBuffer - WrOff; - if (Rem > NumBytes) { - // - // All data fits before wrap around - // - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); - pRing->WrOff = WrOff + NumBytes; - } else { - // - // We reach the end of the buffer, so need to wrap around - // - NumBytesAtOnce = Rem; - memcpy(pRing->pBuffer + WrOff, pData, NumBytesAtOnce); - NumBytesAtOnce = NumBytes - Rem; - memcpy(pRing->pBuffer, pData + Rem, NumBytesAtOnce); - pRing->WrOff = NumBytesAtOnce; - } -} - -/********************************************************************* -* -* _PostTerminalSwitch() -* -* Function description -* Switch terminal to the given terminal ID. It is the caller's -* responsibility to ensure the terminal ID is correct and there is -* enough space in the buffer for this to complete successfully. -* -* Parameters -* pRing Ring buffer to post to. -* TerminalId Terminal ID to switch to. -*/ -static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) { - char ac[2]; - - ac[0] = 0xFFu; - ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit - _WriteBlocking(pRing, ac, 2u); -} - -/********************************************************************* -* -* _GetAvailWriteSpace() -* -* Function description -* Returns the number of bytes that can be written to the ring -* buffer without blocking. -* -* Parameters -* pRing Ring buffer to check. -* -* Return value -* Number of bytes that are free in the buffer. -*/ -static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) { - unsigned RdOff; - unsigned WrOff; - unsigned r; - // - // Avoid warnings regarding volatile access order. It's not a problem - // in this case, but dampen compiler enthusiasm. - // - RdOff = pRing->RdOff; - WrOff = pRing->WrOff; - if (RdOff <= WrOff) { - r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; - } else { - r = RdOff - WrOff - 1u; - } - return r; -} - -/********************************************************************* -* -* Public code -* -********************************************************************** -*/ -/********************************************************************* -* -* SEGGER_RTT_ReadNoLock() -* -* Function description -* Reads characters from SEGGER real-time-terminal control block -* which have been previously stored by the host. -* Do not lock against interrupts and multiple access. -* -* Parameters -* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. -* BufferSize Size of the target application buffer. -* -* Return value -* Number of bytes that have been read. -*/ -unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { - unsigned NumBytesRem; - unsigned NumBytesRead; - unsigned RdOff; - unsigned WrOff; - unsigned char* pBuffer; - SEGGER_RTT_BUFFER_DOWN* pRing; - // - INIT(); - pRing = &_SEGGER_RTT.aDown[BufferIndex]; - pBuffer = (unsigned char*)pData; - RdOff = pRing->RdOff; - WrOff = pRing->WrOff; - NumBytesRead = 0u; - // - // Read from current read position to wrap-around of buffer, first - // - if (RdOff > WrOff) { - NumBytesRem = pRing->SizeOfBuffer - RdOff; - NumBytesRem = MIN(NumBytesRem, BufferSize); - memcpy(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); - NumBytesRead += NumBytesRem; - pBuffer += NumBytesRem; - BufferSize -= NumBytesRem; - RdOff += NumBytesRem; - // - // Handle wrap-around of buffer - // - if (RdOff == pRing->SizeOfBuffer) { - RdOff = 0u; - } - } - // - // Read remaining items of buffer - // - NumBytesRem = WrOff - RdOff; - NumBytesRem = MIN(NumBytesRem, BufferSize); - if (NumBytesRem > 0u) { - memcpy(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); - NumBytesRead += NumBytesRem; - pBuffer += NumBytesRem; - BufferSize -= NumBytesRem; - RdOff += NumBytesRem; - } - if (NumBytesRead) { - pRing->RdOff = RdOff; - } - // - return NumBytesRead; -} - -/********************************************************************* -* -* SEGGER_RTT_Read -* -* Function description -* Reads characters from SEGGER real-time-terminal control block -* which have been previously stored by the host. -* -* Parameters -* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. -* BufferSize Size of the target application buffer. -* -* Return value -* Number of bytes that have been read. -*/ -unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { - unsigned NumBytesRead; - // - SEGGER_RTT_LOCK(); - // - // Call the non-locking read function - // - NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); - // - // Finish up. - // - SEGGER_RTT_UNLOCK(); - // - return NumBytesRead; -} - -/********************************************************************* -* -* SEGGER_RTT_WriteWithOverwriteNoLock -* -* Function description -* Stores a specified number of characters in SEGGER RTT -* control block. -* SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application -* and overwrites data if the data does not fit into the buffer. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Notes -* (1) If there is not enough space in the "Up"-buffer, data is overwritten. -* (2) For performance reasons this function does not call Init() -* and may only be called after RTT has been initialized. -* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. -* (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link -* connection reads RTT data. -*/ -void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { - const char* pData; - SEGGER_RTT_BUFFER_UP* pRing; - unsigned Avail; - - pData = (const char *)pBuffer; - // - // Get "to-host" ring buffer and copy some elements into local variables. - // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; - // - // Check if we will overwrite data and need to adjust the RdOff. - // - if (pRing->WrOff == pRing->RdOff) { - Avail = pRing->SizeOfBuffer - 1u; - } else if ( pRing->WrOff < pRing->RdOff) { - Avail = pRing->RdOff - pRing->WrOff - 1u; - } else { - Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; - } - if (NumBytes > Avail) { - pRing->RdOff += (NumBytes - Avail); - while (pRing->RdOff >= pRing->SizeOfBuffer) { - pRing->RdOff -= pRing->SizeOfBuffer; - } - } - // - // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds - // - Avail = pRing->SizeOfBuffer - pRing->WrOff; - do { - if (Avail > NumBytes) { - // - // Last round - // -#if 1 // memcpy() is good for large amounts of data, but the overhead is too big for small amounts. Use a simple byte loop instead. - char* pDst; - pDst = pRing->pBuffer + pRing->WrOff; - pRing->WrOff += NumBytes; - do { - *pDst++ = *pData++; - } while (--NumBytes); -#else - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); - pRing->WrOff += NumBytes; -#endif - break; //Alternatively: NumBytes = 0; - } else { - // - // Wrap-around necessary, write until wrap-around and reset WrOff - // - memcpy(pRing->pBuffer + pRing->WrOff, pData, Avail); - pData += Avail; - pRing->WrOff = 0; - NumBytes -= Avail; - Avail = (pRing->SizeOfBuffer - 1); - } - } while (NumBytes); -} - -/********************************************************************* -* -* SEGGER_RTT_WriteSkipNoLock -* -* Function description -* Stores a specified number of characters in SEGGER RTT -* control block which is then read by the host. -* SEGGER_RTT_WriteSkipNoLock does not lock the application and -* skips all data, if the data does not fit into the buffer. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Return value -* Number of bytes which have been stored in the "Up"-buffer. -* -* Notes -* (1) If there is not enough space in the "Up"-buffer, all data is dropped. -* (2) For performance reasons this function does not call Init() -* and may only be called after RTT has been initialized. -* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. -*/ -unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { - const char* pData; - SEGGER_RTT_BUFFER_UP* pRing; - unsigned Avail; - unsigned RdOff; - unsigned WrOff; - unsigned Rem; - - pData = (const char *)pBuffer; - // - // Get "to-host" ring buffer and copy some elements into local variables. - // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; - RdOff = pRing->RdOff; - WrOff = pRing->WrOff; - // - // Handle the most common cases fastest. - // Which is: - // RdOff <= WrOff -> Space until wrap around is free. - // AND - // WrOff + NumBytes < SizeOfBuffer -> No Wrap around necessary. - // - // OR - // - // RdOff > WrOff -> Space until RdOff - 1 is free. - // AND - // WrOff + NumBytes < RdOff -> Data fits into buffer - // - if (RdOff <= WrOff) { - // - // Get space until WrOff will be at wrap around. - // - Avail = pRing->SizeOfBuffer - 1u - WrOff ; - if (Avail >= NumBytes) { -#if 1 // memcpy() is good for large amounts of data, but the overhead is too big for small amounts. Use a simple byte loop instead. - char* pDst; - pDst = pRing->pBuffer + WrOff; - WrOff += NumBytes; - do { - *pDst++ = *pData++; - } while (--NumBytes); - pRing->WrOff = WrOff + NumBytes; -#else - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); - pRing->WrOff = WrOff + NumBytes; -#endif - return 1; - } - // - // If data did not fit into space until wrap around calculate complete space in buffer. - // - Avail += RdOff; - // - // If there is still no space for the whole of this output, don't bother. - // - if (Avail >= NumBytes) { - // - // OK, we have enough space in buffer. Copy in one or 2 chunks - // - Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer - if (Rem > NumBytes) { - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); - pRing->WrOff = WrOff + NumBytes; - } else { - // - // We reach the end of the buffer, so need to wrap around - // - memcpy(pRing->pBuffer + WrOff, pData, Rem); - memcpy(pRing->pBuffer, pData + Rem, NumBytes - Rem); - pRing->WrOff = NumBytes - Rem; - } - return 1; - } - } else { - Avail = RdOff - WrOff - 1u; - if (Avail >= NumBytes) { - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); - pRing->WrOff = WrOff + NumBytes; - return 1; - } - } - // - // If we reach this point no data has been written - // - return 0; -} - -/********************************************************************* -* -* SEGGER_RTT_WriteNoLock -* -* Function description -* Stores a specified number of characters in SEGGER RTT -* control block which is then read by the host. -* SEGGER_RTT_WriteNoLock does not lock the application. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Return value -* Number of bytes which have been stored in the "Up"-buffer. -* -* Notes -* (1) If there is not enough space in the "Up"-buffer, remaining characters of pBuffer are dropped. -* (2) For performance reasons this function does not call Init() -* and may only be called after RTT has been initialized. -* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. -*/ -unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { - unsigned Status; - unsigned Avail; - const char* pData; - SEGGER_RTT_BUFFER_UP* pRing; - - pData = (const char *)pBuffer; - // - // Get "to-host" ring buffer. - // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; - // - // How we output depends upon the mode... - // - switch (pRing->Flags) { - case SEGGER_RTT_MODE_NO_BLOCK_SKIP: - // - // If we are in skip mode and there is no space for the whole - // of this output, don't bother. - // - Avail = _GetAvailWriteSpace(pRing); - if (Avail < NumBytes) { - Status = 0u; - } else { - Status = NumBytes; - _WriteNoCheck(pRing, pData, NumBytes); - } - break; - case SEGGER_RTT_MODE_NO_BLOCK_TRIM: - // - // If we are in trim mode, trim to what we can output without blocking. - // - Avail = _GetAvailWriteSpace(pRing); - Status = Avail < NumBytes ? Avail : NumBytes; - _WriteNoCheck(pRing, pData, Status); - break; - case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: - // - // If we are in blocking mode, output everything. - // - Status = _WriteBlocking(pRing, pData, NumBytes); - break; - default: - Status = 0u; - break; - } - // - // Finish up. - // - return Status; -} - -/********************************************************************* -* -* SEGGER_RTT_Write -* -* Function description -* Stores a specified number of characters in SEGGER RTT -* control block which is then read by the host. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). -* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. -* NumBytes Number of bytes to be stored in the SEGGER RTT control block. -* -* Return value -* Number of bytes which have been stored in the "Up"-buffer. -* -* Notes -* (1) If there is not enough space in the "Up"-buffer, remaining characters of pBuffer are dropped. -*/ -unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { - unsigned Status; - // - INIT(); - SEGGER_RTT_LOCK(); - // - // Call the non-locking write function - // - Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); - // - // Finish up. - // - SEGGER_RTT_UNLOCK(); - // - return Status; -} - -/********************************************************************* -* -* SEGGER_RTT_WriteString -* -* Function description -* Stores string in SEGGER RTT control block. -* This data is read by the host. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). -* s Pointer to string. -* -* Return value -* Number of bytes which have been stored in the "Up"-buffer. -* -* Notes -* (1) If there is not enough space in the "Up"-buffer, depending on configuration, -* remaining characters may be dropped or RTT module waits until there is more space in the buffer. -* (2) String passed to this function has to be \0 terminated -* (3) \0 termination character is *not* stored in RTT buffer -*/ -unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) { - unsigned Len; - - Len = STRLEN(s); - return SEGGER_RTT_Write(BufferIndex, s, Len); -} - -/********************************************************************* -* -* SEGGER_RTT_GetKey -* -* Function description -* Reads one character from the SEGGER RTT buffer. -* Host has previously stored data there. -* -* Return value -* < 0 - No character available (buffer empty). -* >= 0 - Character which has been read. (Possible values: 0 - 255) -* -* Notes -* (1) This function is only specified for accesses to RTT buffer 0. -*/ -int SEGGER_RTT_GetKey(void) { - char c; - int r; - - r = (int)SEGGER_RTT_Read(0u, &c, 1u); - if (r == 1) { - r = (int)(unsigned char)c; - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_WaitKey -* -* Function description -* Waits until at least one character is avaible in the SEGGER RTT buffer. -* Once a character is available, it is read and this function returns. -* -* Return value -* >=0 - Character which has been read. -* -* Notes -* (1) This function is only specified for accesses to RTT buffer 0 -* (2) This function is blocking if no character is present in RTT buffer -*/ -int SEGGER_RTT_WaitKey(void) { - int r; - - do { - r = SEGGER_RTT_GetKey(); - } while (r < 0); - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_HasKey -* -* Function description -* Checks if at least one character for reading is available in the SEGGER RTT buffer. -* -* Return value -* == 0 - No characters are available to read. -* == 1 - At least one character is available. -* -* Notes -* (1) This function is only specified for accesses to RTT buffer 0 -*/ -int SEGGER_RTT_HasKey(void) { - unsigned RdOff; - int r; - - INIT(); - RdOff = _SEGGER_RTT.aDown[0].RdOff; - if (RdOff != _SEGGER_RTT.aDown[0].WrOff) { - r = 1; - } else { - r = 0; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_HasData -* -* Function description -* Check if there is data from the host in the given buffer. -* -* Return value: -* ==0: No data -* !=0: Data in buffer -* -*/ -unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { - SEGGER_RTT_BUFFER_DOWN* pRing; - unsigned v; - - pRing = &_SEGGER_RTT.aDown[BufferIndex]; - v = pRing->WrOff; - return v - pRing->RdOff; -} - -/********************************************************************* -* -* SEGGER_RTT_AllocDownBuffer -* -* Function description -* Run-time configuration of the next down-buffer (H->T). -* The next buffer, which is not used yet is configured. -* This includes: Buffer address, size, name, flags, ... -* -* Parameters -* sName Pointer to a constant name string. -* pBuffer Pointer to a buffer to be used. -* BufferSize Size of the buffer. -* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). -* -* Return value -* >= 0 - O.K. Buffer Index -* < 0 - Error -*/ -int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { - int BufferIndex; - - INIT(); - SEGGER_RTT_LOCK(); - BufferIndex = 0; - do { - if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) { - break; - } - BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; - } else { - BufferIndex = -1; - } - SEGGER_RTT_UNLOCK(); - return BufferIndex; -} - -/********************************************************************* -* -* SEGGER_RTT_AllocUpBuffer -* -* Function description -* Run-time configuration of the next up-buffer (T->H). -* The next buffer, which is not used yet is configured. -* This includes: Buffer address, size, name, flags, ... -* -* Parameters -* sName Pointer to a constant name string. -* pBuffer Pointer to a buffer to be used. -* BufferSize Size of the buffer. -* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). -* -* Return value -* >= 0 - O.K. Buffer Index -* < 0 - Error -*/ -int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { - int BufferIndex; - - INIT(); - SEGGER_RTT_LOCK(); - BufferIndex = 0; - do { - if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) { - break; - } - BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; - } else { - BufferIndex = -1; - } - SEGGER_RTT_UNLOCK(); - return BufferIndex; -} - -/********************************************************************* -* -* SEGGER_RTT_ConfigUpBuffer -* -* Function description -* Run-time configuration of a specific up-buffer (T->H). -* Buffer to be configured is specified by index. -* This includes: Buffer address, size, name, flags, ... -* -* Parameters -* BufferIndex Index of the buffer to configure. -* sName Pointer to a constant name string. -* pBuffer Pointer to a buffer to be used. -* BufferSize Size of the buffer. -* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). -* -* Return value -* >= 0 - O.K. -* < 0 - Error -*/ -int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { - int r; - - INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { - SEGGER_RTT_LOCK(); - if (BufferIndex > 0u) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; - } - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; - SEGGER_RTT_UNLOCK(); - r = 0; - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_ConfigDownBuffer -* -* Function description -* Run-time configuration of a specific down-buffer (H->T). -* Buffer to be configured is specified by index. -* This includes: Buffer address, size, name, flags, ... -* -* Parameters -* BufferIndex Index of the buffer to configure. -* sName Pointer to a constant name string. -* pBuffer Pointer to a buffer to be used. -* BufferSize Size of the buffer. -* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). -* -* Return value -* >= 0 O.K. -* < 0 Error -*/ -int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { - int r; - - INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { - SEGGER_RTT_LOCK(); - if (BufferIndex > 0u) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; - } - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; - SEGGER_RTT_UNLOCK(); - r = 0; - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_SetNameUpBuffer -* -* Function description -* Run-time configuration of a specific up-buffer name (T->H). -* Buffer to be configured is specified by index. -* -* Parameters -* BufferIndex Index of the buffer to renamed. -* sName Pointer to a constant name string. -* -* Return value -* >= 0 O.K. -* < 0 Error -*/ -int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { - int r; - - INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { - SEGGER_RTT_LOCK(); - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - SEGGER_RTT_UNLOCK(); - r = 0; - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_SetNameDownBuffer -* -* Function description -* Run-time configuration of a specific Down-buffer name (T->H). -* Buffer to be configured is specified by index. -* -* Parameters -* BufferIndex Index of the buffer to renamed. -* sName Pointer to a constant name string. -* -* Return value -* >= 0 O.K. -* < 0 Error -*/ -int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { - int r; - - INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { - SEGGER_RTT_LOCK(); - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - SEGGER_RTT_UNLOCK(); - r = 0; - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_Init -* -* Function description -* Initializes the RTT Control Block. -* Should be used in RAM targets, at start of the application. -* -*/ -void SEGGER_RTT_Init (void) { - _DoInit(); -} - -/********************************************************************* -* -* SEGGER_RTT_SetTerminal -* -* Function description -* Sets the terminal to be used for output on channel 0. -* -* Parameters -* TerminalId Index of the terminal. -* -* Return value -* >= 0 O.K. -* < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) -*/ -int SEGGER_RTT_SetTerminal (char TerminalId) { - char ac[2]; - SEGGER_RTT_BUFFER_UP* pRing; - unsigned Avail; - int r; - // - INIT(); - // - r = 0; - ac[0] = 0xFFU; - if ((unsigned char)TerminalId < (unsigned char)sizeof(_aTerminalId)) { // We only support a certain number of channels - ac[1] = _aTerminalId[(unsigned char)TerminalId]; - pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed - SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing - if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { - _ActiveTerminal = TerminalId; - _WriteBlocking(pRing, ac, 2u); - } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes - Avail = _GetAvailWriteSpace(pRing); - if (Avail >= 2) { - _ActiveTerminal = TerminalId; // Only change active terminal in case of success - _WriteNoCheck(pRing, ac, 2u); - } else { - r = -1; - } - } - SEGGER_RTT_UNLOCK(); - } else { - r = -1; - } - return r; -} - -/********************************************************************* -* -* SEGGER_RTT_TerminalOut -* -* Function description -* Writes a string to the given terminal -* without changing the terminal for channel 0. -* -* Parameters -* TerminalId Index of the terminal. -* s String to be printed on the terminal. -* -* Return value -* >= 0 - Number of bytes written. -* < 0 - Error. -* -*/ -int SEGGER_RTT_TerminalOut (char TerminalId, const char* s) { - int Status; - unsigned FragLen; - unsigned Avail; - SEGGER_RTT_BUFFER_UP* pRing; - // - INIT(); - // - // Validate terminal ID. - // - if (TerminalId < (char)sizeof(_aTerminalId)) { // We only support a certain number of channels - // - // Get "to-host" ring buffer. - // - pRing = &_SEGGER_RTT.aUp[0]; - // - // Need to be able to change terminal, write data, change back. - // Compute the fixed and variable sizes. - // - FragLen = strlen(s); - // - // How we output depends upon the mode... - // - SEGGER_RTT_LOCK(); - Avail = _GetAvailWriteSpace(pRing); - switch (pRing->Flags & SEGGER_RTT_MODE_MASK) { - case SEGGER_RTT_MODE_NO_BLOCK_SKIP: - // - // If we are in skip mode and there is no space for the whole - // of this output, don't bother switching terminals at all. - // - if (Avail < (FragLen + 4u)) { - Status = 0; - } else { - _PostTerminalSwitch(pRing, TerminalId); - Status = (int)_WriteBlocking(pRing, s, FragLen); - _PostTerminalSwitch(pRing, _ActiveTerminal); - } - break; - case SEGGER_RTT_MODE_NO_BLOCK_TRIM: - // - // If we are in trim mode and there is not enough space for everything, - // trim the output but always include the terminal switch. If no room - // for terminal switch, skip that totally. - // - if (Avail < 4u) { - Status = -1; - } else { - _PostTerminalSwitch(pRing, TerminalId); - Status = (int)_WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); - _PostTerminalSwitch(pRing, _ActiveTerminal); - } - break; - case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: - // - // If we are in blocking mode, output everything. - // - _PostTerminalSwitch(pRing, TerminalId); - Status = (int)_WriteBlocking(pRing, s, FragLen); - _PostTerminalSwitch(pRing, _ActiveTerminal); - break; - default: - Status = -1; - break; - } - // - // Finish up. - // - SEGGER_RTT_UNLOCK(); - } else { - Status = -1; - } - return Status; -} - - -/*************************** End of file ****************************/ diff --git a/segger/SEGGER_RTT.h b/segger/SEGGER_RTT.h deleted file mode 100644 index d3cac44dd..000000000 --- a/segger/SEGGER_RTT.h +++ /dev/null @@ -1,234 +0,0 @@ -/********************************************************************* -* SEGGER MICROCONTROLLER GmbH & Co. KG * -* Solutions for real time microcontroller applications * -********************************************************************** -* * -* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* * This software may in its unmodified form be freely redistributed * -* in source form. * -* * The source code may be modified, provided the source code * -* retains the above copyright notice, this list of conditions and * -* the following disclaimer. * -* * Modified versions of this software in source or linkable form * -* may not be distributed without prior consent of SEGGER. * -* * This software may only be used for communication with SEGGER * -* J-Link debug probes. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** -* * -* RTT version: 5.12e * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT.h -Purpose : Implementation of SEGGER real-time transfer which allows - real-time communication on targets which support debugger - memory accesses while the CPU is running. ----------------------------------------------------------------------- -*/ - -#ifndef SEGGER_RTT_H -#define SEGGER_RTT_H - -#include "SEGGER_RTT_Conf.h" - -/********************************************************************* -* -* Defines, fixed -* -********************************************************************** -*/ - -/********************************************************************* -* -* Types -* -********************************************************************** -*/ - -// -// Description for a circular buffer (also called "ring buffer") -// which is used as up-buffer (T->H) -// -typedef struct { - const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" - char* pBuffer; // Pointer to start of buffer - unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. - unsigned WrOff; // Position of next item to be written by either target. - volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host. - unsigned Flags; // Contains configuration flags -} SEGGER_RTT_BUFFER_UP; - -// -// Description for a circular buffer (also called "ring buffer") -// which is used as down-buffer (H->T) -// -typedef struct { - const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" - char* pBuffer; // Pointer to start of buffer - unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. - volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host. - unsigned RdOff; // Position of next item to be read by target (down-buffer). - unsigned Flags; // Contains configuration flags -} SEGGER_RTT_BUFFER_DOWN; - -// -// RTT control block which describes the number of buffers available -// as well as the configuration for each buffer -// -// -typedef struct { - char acID[16]; // Initialized to "SEGGER RTT" - int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2) - int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) - SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host - SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target -} SEGGER_RTT_CB; - -/********************************************************************* -* -* Global data -* -********************************************************************** -*/ -extern SEGGER_RTT_CB _SEGGER_RTT; - -/********************************************************************* -* -* RTT API functions -* -********************************************************************** -*/ -#ifdef __cplusplus - extern "C" { -#endif -int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); -int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); -int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); -int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); -int SEGGER_RTT_GetKey (void); -unsigned SEGGER_RTT_HasData (unsigned BufferIndex); -int SEGGER_RTT_HasKey (void); -void SEGGER_RTT_Init (void); -unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); -unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); -int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName); -int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName); -int SEGGER_RTT_WaitKey (void); -unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s); -void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -// -// Function macro for performance optimization -// -#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff) - -/********************************************************************* -* -* RTT "Terminal" API functions -* -********************************************************************** -*/ -int SEGGER_RTT_SetTerminal (char TerminalId); -int SEGGER_RTT_TerminalOut (char TerminalId, const char* s); - -/********************************************************************* -* -* RTT printf functions (require SEGGER_RTT_printf.c) -* -********************************************************************** -*/ -int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...); -#ifdef __cplusplus - } -#endif - -/********************************************************************* -* -* Defines -* -********************************************************************** -*/ - -// -// Operating modes. Define behavior if buffer is full (not enough space for entire message) -// -#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0U) // Skip. Do not block, output nothing. (Default) -#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1U) // Trim: Do not block, output as much as fits. -#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2U) // Block: Wait until there is space in the buffer. -#define SEGGER_RTT_MODE_MASK (3U) - -// -// Control sequences, based on ANSI. -// Can be used to control color, and clear the screen -// -#define RTT_CTRL_RESET "" // Reset to default colors -#define RTT_CTRL_CLEAR "" // Clear screen, reposition cursor to top left - -#define RTT_CTRL_TEXT_BLACK "" -#define RTT_CTRL_TEXT_RED "" -#define RTT_CTRL_TEXT_GREEN "" -#define RTT_CTRL_TEXT_YELLOW "" -#define RTT_CTRL_TEXT_BLUE "" -#define RTT_CTRL_TEXT_MAGENTA "" -#define RTT_CTRL_TEXT_CYAN "" -#define RTT_CTRL_TEXT_WHITE "" - -#define RTT_CTRL_TEXT_BRIGHT_BLACK "" -#define RTT_CTRL_TEXT_BRIGHT_RED "" -#define RTT_CTRL_TEXT_BRIGHT_GREEN "" -#define RTT_CTRL_TEXT_BRIGHT_YELLOW "" -#define RTT_CTRL_TEXT_BRIGHT_BLUE "" -#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "" -#define RTT_CTRL_TEXT_BRIGHT_CYAN "" -#define RTT_CTRL_TEXT_BRIGHT_WHITE "" - -#define RTT_CTRL_BG_BLACK "" -#define RTT_CTRL_BG_RED "" -#define RTT_CTRL_BG_GREEN "" -#define RTT_CTRL_BG_YELLOW "" -#define RTT_CTRL_BG_BLUE "" -#define RTT_CTRL_BG_MAGENTA "" -#define RTT_CTRL_BG_CYAN "" -#define RTT_CTRL_BG_WHITE "" - -#define RTT_CTRL_BG_BRIGHT_BLACK "" -#define RTT_CTRL_BG_BRIGHT_RED "" -#define RTT_CTRL_BG_BRIGHT_GREEN "" -#define RTT_CTRL_BG_BRIGHT_YELLOW "" -#define RTT_CTRL_BG_BRIGHT_BLUE "" -#define RTT_CTRL_BG_BRIGHT_MAGENTA "" -#define RTT_CTRL_BG_BRIGHT_CYAN "" -#define RTT_CTRL_BG_BRIGHT_WHITE "" - - -#endif - -/*************************** End of file ****************************/ diff --git a/segger/SEGGER_RTT_Conf.h b/segger/SEGGER_RTT_Conf.h deleted file mode 100644 index aef3b4053..000000000 --- a/segger/SEGGER_RTT_Conf.h +++ /dev/null @@ -1,242 +0,0 @@ -/********************************************************************* -* SEGGER MICROCONTROLLER GmbH & Co. KG * -* Solutions for real time microcontroller applications * -********************************************************************** -* * -* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* * This software may in its unmodified form be freely redistributed * -* in source form. * -* * The source code may be modified, provided the source code * -* retains the above copyright notice, this list of conditions and * -* the following disclaimer. * -* * Modified versions of this software in source or linkable form * -* may not be distributed without prior consent of SEGGER. * -* * This software may only be used for communication with SEGGER * -* J-Link debug probes. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** -* * -* RTT version: 5.12e * -* * -********************************************************************** ----------------------------------------------------------------------- -File : SEGGER_RTT_Conf.h -Purpose : Implementation of SEGGER real-time transfer (RTT) which - allows real-time communication on targets which support - debugger memory accesses while the CPU is running. ----------------------------END-OF-HEADER------------------------------ -*/ - -#ifndef SEGGER_RTT_CONF_H -#define SEGGER_RTT_CONF_H - -#ifdef __ICCARM__ - #include -#endif - -/********************************************************************* -* -* Defines, configurable -* -********************************************************************** -*/ - -#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (2) // Max. number of up-buffers (T->H) available on this target (Default: 2) -#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (2) // Max. number of down-buffers (H->T) available on this target (Default: 2) - -#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k) -#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16) - -#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64) - -#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0) - -// -// Target is not allowed to perform other RTT operations while string still has not been stored completely. -// Otherwise we would probably end up with a mixed string in the buffer. -// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here. -// -// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4. -// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches. -// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly. -// (Higher priority = lower priority number) -// Default value for embOS: 128u -// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) -// In case of doubt mask all interrupts: 0u -// - -#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20) - -/********************************************************************* -* -* RTT lock configuration for SEGGER Embedded Studio, -* Rowley CrossStudio and GCC -*/ -#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__) - #ifdef __ARM_ARCH_6M__ - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - __asm volatile ("mrs %0, primask \n\t" \ - "mov r1, $1 \n\t" \ - "msr primask, r1 \n\t" \ - : "=r" (LockState) \ - : \ - : "r1" \ - ); - - #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \ - : \ - : "r" (LockState) \ - : \ - ); \ - } - - #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)) - #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY - #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) - #endif - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - __asm volatile ("mrs %0, basepri \n\t" \ - "mov r1, %1 \n\t" \ - "msr basepri, r1 \n\t" \ - : "=r" (LockState) \ - : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ - : "r1" \ - ); - - #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \ - : \ - : "r" (LockState) \ - : \ - ); \ - } - - #elif defined(__ARM_ARCH_7A__) - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - __asm volatile ("mrs r1, CPSR \n\t" \ - "mov %0, r1 \n\t" \ - "orr r1, r1, #0xC0 \n\t" \ - "msr CPSR_c, r1 \n\t" \ - : "=r" (LockState) \ - : \ - : "r1" \ - ); - - #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ - "mrs r1, CPSR \n\t" \ - "bic r1, r1, #0xC0 \n\t" \ - "and r0, r0, #0xC0 \n\t" \ - "orr r1, r1, r0 \n\t" \ - "msr CPSR_c, r1 \n\t" \ - : \ - : "r" (LockState) \ - : "r0", "r1" \ - ); \ - } -#else - #define SEGGER_RTT_LOCK() - #define SEGGER_RTT_UNLOCK() - #endif -#endif - -/********************************************************************* -* -* RTT lock configuration for IAR EWARM -*/ -#ifdef __ICCARM__ - #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = __get_PRIMASK(); \ - __set_PRIMASK(1); - - #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \ - } - #elif ((defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || (defined (__ARM7M__) && (__CORE__ == __ARM7M__))) - #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY - #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) - #endif - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = __get_BASEPRI(); \ - __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); - - #define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \ - } - #endif -#endif - -/********************************************************************* -* -* RTT lock configuration for KEIL ARM -*/ -#ifdef __CC_ARM - #if (defined __TARGET_ARCH_6S_M) - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - register unsigned char PRIMASK __asm( "primask"); \ - LockState = PRIMASK; \ - PRIMASK = 1u; \ - __schedule_barrier(); - - #define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \ - __schedule_barrier(); \ - } - #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) - #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY - #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) - #endif - #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - register unsigned char BASEPRI __asm( "basepri"); \ - LockState = BASEPRI; \ - BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ - __schedule_barrier(); - - #define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \ - __schedule_barrier(); \ - } - #endif -#endif - -/********************************************************************* -* -* RTT lock configuration fallback -*/ -#ifndef SEGGER_RTT_LOCK - #define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts) -#endif - -#ifndef SEGGER_RTT_UNLOCK - #define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) -#endif - -#endif -/*************************** End of file ****************************/ diff --git a/segger/SEGGER_RTT_SES.c b/segger/SEGGER_RTT_SES.c deleted file mode 100644 index e6634147c..000000000 --- a/segger/SEGGER_RTT_SES.c +++ /dev/null @@ -1,76 +0,0 @@ -/********************************************************************* -* SEGGER MICROCONTROLLER GmbH & Co. KG * -* Solutions for real time microcontroller applications * -********************************************************************** -* * -* (c) 2014 - 2015 SEGGER Microcontroller GmbH & Co. KG * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* * This software may in its unmodified form be freely redistributed * -* in source form. * -* * The source code may be modified, provided the source code * -* retains the above copyright notice, this list of conditions and * -* the following disclaimer. * -* * Modified versions of this software in source or linkable form * -* may not be distributed without prior consent of SEGGER. * -* * This software may only be used for communication with SEGGER * -* J-Link debug probes. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** --------- END-OF-HEADER --------------------------------------------- -File : SEGGER_RTT_Syscalls_SES.c -Purpose : Reimplementation of printf, puts and - implementation of __putchar and __getchar using RTT in SES. - To use RTT for printf output, include this file in your - application. ----------------------------------------------------------------------- -*/ -#include "SEGGER_RTT.h" -#include "__libc.h" -#include -#include - -int printf(const char *fmt,...) { - char buffer[128]; - va_list args; - va_start (args, fmt); - int n = vsnprintf(buffer, sizeof(buffer), fmt, args); - SEGGER_RTT_Write(0, buffer, n); - va_end(args); - return n; -} - -int puts(const char *s) { - return SEGGER_RTT_WriteString(0, s); -} - -int __putchar(int x, __printf_tag_ptr ctx) { - (void)ctx; - SEGGER_RTT_Write(0, (char *)&x, 1); - return x; -} - -int __getchar() { - return SEGGER_RTT_WaitKey(); -} - -/****** End Of File *************************************************/ diff --git a/segger/flash_placement.xml b/segger/flash_placement.xml deleted file mode 100644 index 70d131acb..000000000 --- a/segger/flash_placement.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/segger/nRF52832_xxAA_MemoryMap.xml b/segger/nRF52832_xxAA_MemoryMap.xml deleted file mode 100644 index 809e2a1e4..000000000 --- a/segger/nRF52832_xxAA_MemoryMap.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/segger/nRF52840_xxAA_MemoryMap.xml b/segger/nRF52840_xxAA_MemoryMap.xml deleted file mode 100644 index c37570c5d..000000000 --- a/segger/nRF52840_xxAA_MemoryMap.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/segger/nRF_Target.js b/segger/nRF_Target.js deleted file mode 100644 index 20560af43..000000000 --- a/segger/nRF_Target.js +++ /dev/null @@ -1,19 +0,0 @@ -/***************************************************************************** - * SEGGER Microcontroller GmbH & Co. KG * - * Solutions for real time microcontroller applications * - ***************************************************************************** - * * - * (c) 2017 SEGGER Microcontroller GmbH & Co. KG * - * * - * Internet: www.segger.com Support: support@segger.com * - * * - *****************************************************************************/ - -function Reset() { - TargetInterface.resetAndStop(); -} - -function EnableTrace(traceInterfaceType) { - // TODO: Enable trace -} - diff --git a/segger/nrf52840_Registers.xml b/segger/nrf52840_Registers.xml deleted file mode 100644 index 39f861f95..000000000 --- a/segger/nrf52840_Registers.xml +++ /dev/null @@ -1,22310 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/segger/thumb_crt0.s b/segger/thumb_crt0.s deleted file mode 100644 index 71820cb51..000000000 --- a/segger/thumb_crt0.s +++ /dev/null @@ -1,420 +0,0 @@ -// SEGGER Embedded Studio, runtime support. -// -// Copyright (c) 2014-2017 SEGGER Microcontroller GmbH & Co KG -// Copyright (c) 2001-2017 Rowley Associates Limited. -// -// This file may be distributed under the terms of the License Agreement -// provided with this software. -// -// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// -// Preprocessor Definitions -// ------------------------ -// APP_ENTRY_POINT -// -// Defines the application entry point function, if undefined this setting -// defaults to "main". -// -// INITIALIZE_STACK -// -// If defined, the contents of the stack will be initialized to a the -// value 0xCC. -// -// INITIALIZE_SECONDARY_SECTIONS -// -// If defined, the .data2, .text2, .rodata2 and .bss2 sections will be initialized. -// -// INITIALIZE_TCM_SECTIONS -// -// If defined, the .data_tcm, .text_tcm, .rodata_tcm and .bss_tcm sections -// will be initialized. -// -// INITIALIZE_USER_SECTIONS -// -// If defined, the function InitializeUserMemorySections will be called prior -// to entering main in order to allow the user to initialize any user defined -// memory sections. -// -// FULL_LIBRARY -// -// If defined then -// - argc, argv are setup by the debug_getargs. -// - the exit symbol is defined and executes on return from main. -// - the exit symbol calls destructors, atexit functions and then debug_exit. -// -// If not defined then -// - argc and argv are zero. -// - the exit symbol is defined, executes on return from main and loops -// - -#ifndef APP_ENTRY_POINT -#define APP_ENTRY_POINT main -#endif - -#ifndef ARGSSPACE -#define ARGSSPACE 128 -#endif - .syntax unified - - .global _start - .extern APP_ENTRY_POINT - .global exit - .weak exit - -#ifdef INITIALIZE_USER_SECTIONS - .extern InitializeUserMemorySections -#endif - - .section .init, "ax" - .code 16 - .align 2 - .thumb_func - -_start: - /* Set up main stack if size > 0 */ - ldr r1, =__stack_end__ - ldr r0, =__stack_start__ - subs r2, r1, r0 - beq 1f -#ifdef __ARM_EABI__ - movs r2, #0x7 - bics r1, r2 -#endif - mov sp, r1 -#ifdef INITIALIZE_STACK - movs r2, #0xCC - ldr r0, =__stack_start__ - bl memory_set -#endif -1: - - /* Set up process stack if size > 0 */ - ldr r1, =__stack_process_end__ - ldr r0, =__stack_process_start__ - subs r2, r1, r0 - beq 1f -#ifdef __ARM_EABI__ - movs r2, #0x7 - bics r1, r2 -#endif - msr psp, r1 - movs r2, #2 - msr control, r2 -#ifdef INITIALIZE_STACK - movs r2, #0xCC - bl memory_set -#endif -1: - - /* Copy initialized memory sections into RAM (if necessary). */ - ldr r0, =__data_load_start__ - ldr r1, =__data_start__ - ldr r2, =__data_end__ - bl memory_copy - ldr r0, =__text_load_start__ - ldr r1, =__text_start__ - ldr r2, =__text_end__ - bl memory_copy - ldr r0, =__fast_load_start__ - ldr r1, =__fast_start__ - ldr r2, =__fast_end__ - bl memory_copy - ldr r0, =__ctors_load_start__ - ldr r1, =__ctors_start__ - ldr r2, =__ctors_end__ - bl memory_copy - ldr r0, =__dtors_load_start__ - ldr r1, =__dtors_start__ - ldr r2, =__dtors_end__ - bl memory_copy - ldr r0, =__rodata_load_start__ - ldr r1, =__rodata_start__ - ldr r2, =__rodata_end__ - bl memory_copy - ldr r0, =__tdata_load_start__ - ldr r1, =__tdata_start__ - ldr r2, =__tdata_end__ - bl memory_copy -#ifdef INITIALIZE_SECONDARY_SECTIONS - ldr r0, =__data2_load_start__ - ldr r1, =__data2_start__ - ldr r2, =__data2_end__ - bl memory_copy - ldr r0, =__text2_load_start__ - ldr r1, =__text2_start__ - ldr r2, =__text2_end__ - bl memory_copy - ldr r0, =__rodata2_load_start__ - ldr r1, =__rodata2_start__ - ldr r2, =__rodata2_end__ - bl memory_copy -#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */ -#ifdef INITIALIZE_TCM_SECTIONS - ldr r0, =__data_tcm_load_start__ - ldr r1, =__data_tcm_start__ - ldr r2, =__data_tcm_end__ - bl memory_copy - ldr r0, =__text_tcm_load_start__ - ldr r1, =__text_tcm_start__ - ldr r2, =__text_tcm_end__ - bl memory_copy - ldr r0, =__rodata_tcm_load_start__ - ldr r1, =__rodata_tcm_start__ - ldr r2, =__rodata_tcm_end__ - bl memory_copy -#endif /* #ifdef INITIALIZE_TCM_SECTIONS */ - - /* Zero the bss. */ - ldr r0, =__bss_start__ - ldr r1, =__bss_end__ - movs r2, #0 - bl memory_set - ldr r0, =__tbss_start__ - ldr r1, =__tbss_end__ - movs r2, #0 - bl memory_set -#ifdef INITIALIZE_SECONDARY_SECTIONS - ldr r0, =__bss2_start__ - ldr r1, =__bss2_end__ - mov r2, #0 - bl memory_set -#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */ -#ifdef INITIALIZE_TCM_SECTIONS - ldr r0, =__bss_tcm_start__ - ldr r1, =__bss_tcm_end__ - mov r2, #0 - bl memory_set -#endif /* #ifdef INITIALIZE_TCM_SECTIONS */ - - /* Initialize the heap */ - ldr r0, = __heap_start__ - ldr r1, = __heap_end__ - subs r1, r1, r0 - cmp r1, #8 - blt 1f - movs r2, #0 - str r2, [r0] - adds r0, r0, #4 - str r1, [r0] -1: - -#ifdef INITIALIZE_USER_SECTIONS - ldr r2, =InitializeUserMemorySections - blx r2 -#endif - - /* Call constructors */ - ldr r0, =__ctors_start__ - ldr r1, =__ctors_end__ -ctor_loop: - cmp r0, r1 - beq ctor_end - ldr r2, [r0] - adds r0, #4 - push {r0-r1} - blx r2 - pop {r0-r1} - b ctor_loop -ctor_end: - - /* Setup initial call frame */ - movs r0, #0 - mov lr, r0 - mov r12, sp - - .type start, function -start: - /* Jump to application entry point */ -#ifdef FULL_LIBRARY - movs r0, #ARGSSPACE - ldr r1, =args - ldr r2, =debug_getargs - blx r2 - ldr r1, =args -#else - movs r0, #0 - movs r1, #0 -#endif - ldr r2, =APP_ENTRY_POINT - blx r2 - - .thumb_func -exit: -#ifdef FULL_LIBRARY - mov r5, r0 // save the exit parameter/return result - - /* Call destructors */ - ldr r0, =__dtors_start__ - ldr r1, =__dtors_end__ -dtor_loop: - cmp r0, r1 - beq dtor_end - ldr r2, [r0] - add r0, #4 - push {r0-r1} - blx r2 - pop {r0-r1} - b dtor_loop -dtor_end: - - /* Call atexit functions */ - ldr r2, =_execute_at_exit_fns - blx r2 - - /* Call debug_exit with return result/exit parameter */ - mov r0, r5 - ldr r2, =debug_exit - blx r2 -#endif - - /* Returned from application entry point, loop forever. */ -exit_loop: - b exit_loop - - .thumb_func -memory_copy: - cmp r0, r1 - beq 2f - subs r2, r2, r1 - beq 2f -1: - ldrb r3, [r0] - adds r0, r0, #1 - strb r3, [r1] - adds r1, r1, #1 - subs r2, r2, #1 - bne 1b -2: - bx lr - - .thumb_func -memory_set: - cmp r0, r1 - beq 1f - strb r2, [r0] - adds r0, r0, #1 - b memory_set -1: - bx lr - - // default C/C++ library helpers - -.macro HELPER helper_name - .section .text.\helper_name, "ax", %progbits - .global \helper_name - .weak \helper_name -\helper_name: - .thumb_func -.endm - -.macro JUMPTO name -#if defined(__thumb__) && !defined(__thumb2__) - mov r12, r0 - ldr r0, =\name - push {r0} - mov r0, r12 - pop {pc} -#else - b \name -#endif -.endm - -HELPER __aeabi_read_tp - ldr r0, =__tbss_start__-8 - bx lr -HELPER __heap_lock - bx lr -HELPER __heap_unlock - bx lr -HELPER __printf_lock - bx lr -HELPER __printf_unlock - bx lr -HELPER __scanf_lock - bx lr -HELPER __scanf_unlock - bx lr -HELPER __debug_io_lock - bx lr -HELPER __debug_io_unlock - bx lr -HELPER abort - b . -HELPER __assert - b . -HELPER __aeabi_assert - b . -HELPER __cxa_pure_virtual - b . -HELPER __cxa_guard_acquire - ldr r3, [r0] -#if defined(__thumb__) && !defined(__thumb2__) - movs r0, #1 - tst r3, r0 -#else - tst r3, #1 -#endif - beq 1f - movs r0, #0 - bx lr -1: - movs r0, #1 - bx lr -HELPER __cxa_guard_release - movs r3, #1 - str r3, [r0] - bx lr -HELPER __cxa_guard_abort - bx lr -HELPER __sync_synchronize - bx lr -HELPER __getchar - JUMPTO debug_getchar -HELPER __putchar - JUMPTO debug_putchar -HELPER __open - JUMPTO debug_fopen -HELPER __close - JUMPTO debug_fclose -HELPER __write - mov r3, r0 - mov r0, r1 - movs r1, #1 - JUMPTO debug_fwrite -HELPER __read - mov r3, r0 - mov r0, r1 - movs r1, #1 - JUMPTO debug_fread -HELPER __seek - push {r4, lr} - mov r4, r0 - bl debug_fseek - cmp r0, #0 - bne 1f - mov r0, r4 - bl debug_ftell - pop {r4, pc} -1: - ldr r0, =-1 - pop {r4, pc} - // char __user_locale_name_buffer[]; - .section .bss.__user_locale_name_buffer, "aw", %nobits - .global __user_locale_name_buffer - .weak __user_locale_name_buffer - __user_locale_name_buffer: - .word 0x0 - -#ifdef FULL_LIBRARY - .bss -args: - .space ARGSSPACE -#endif - - /* Setup attibutes of stack and heap sections so they don't take up room in the elf file */ - .section .stack, "wa", %nobits - .section .stack_process, "wa", %nobits - .section .heap, "wa", %nobits - diff --git a/src/boards/boards.c b/src/boards/boards.c index f12e459bd..ff88e8f12 100644 --- a/src/boards/boards.c +++ b/src/boards/boards.c @@ -50,6 +50,7 @@ void SysTick_Handler(void) { led_tick(); } +#if defined(BUTTON_DFU) || defined(BUTTON_DFU_OTA) void button_init(uint32_t pin) { if (BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN) { nrf_gpio_cfg_sense_input(pin, BUTTON_PULL, NRF_GPIO_PIN_SENSE_HIGH); @@ -62,6 +63,7 @@ bool button_pressed(uint32_t pin) { uint32_t const active_state = (BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN ? 1 : 0); return nrf_gpio_pin_read(pin) == active_state; } +#endif // This is declared so that a board specific init can be called from here. void __attribute__((weak)) board_init2(void) {} @@ -74,8 +76,12 @@ void board_init(void) { NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_RC; NRF_CLOCK->TASKS_LFCLKSTART = 1UL; +#ifdef BUTTON_DFU button_init(BUTTON_DFU); - button_init(BUTTON_FRESET); +#endif +#ifdef BUTTON_DFU_OTA + button_init(BUTTON_DFU_OTA); +#endif NRFX_DELAY_US(100); // wait for the pin state is stable #if LEDS_NUMBER > 0 diff --git a/src/boards/boards.h b/src/boards/boards.h index e85f76d33..6db378dd5 100644 --- a/src/boards/boards.h +++ b/src/boards/boards.h @@ -31,20 +31,13 @@ #include "nrf.h" #include "nrf_gpio.h" +#define PINNUM(port, pin) ((port) * 32 + (pin)) #include "board.h" #ifndef UF2_VOLUME_LABEL #define UF2_VOLUME_LABEL "NRF52BOOT " #endif -#ifndef BUTTON_DFU -#define BUTTON_DFU BUTTON_1 -#endif - -#ifndef BUTTON_FRESET -#define BUTTON_FRESET BUTTON_2 -#endif - // The primary LED is usually Red but not in all cases. #define LED_PRIMARY 0 // The secondary LED, when available, is usually blue. @@ -104,13 +97,10 @@ void led_tick(void); //--------------------------------------------------------------------+ // BUTTONS //--------------------------------------------------------------------+ -// Make sure we have at least two buttons (DFU + FRESET since DFU+FRST=OTA) -#if BUTTONS_NUMBER < 2 -#error "At least two buttons required in the BSP (see 'BUTTONS_NUMBER')" -#endif - +#if defined(BUTTON_DFU) || defined(BUTTON_DFU_OTA) void button_init(uint32_t pin); bool button_pressed(uint32_t pin); +#endif bool is_ota(void); diff --git a/src/boards/heltec_t096/board.h b/src/boards/heltec_t096/board.h index cf52e1ae6..930d6033c 100644 --- a/src/boards/heltec_t096/board.h +++ b/src/boards/heltec_t096/board.h @@ -25,26 +25,23 @@ #ifndef _HELTEC_T096_H #define _HELTEC_T096_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 28) // White +#define LED_PRIMARY_PIN PINNUM(0, 28) // White #define LED_STATE_ON 0 -// #define LED_NEOPIXEL _PINNUM(0, 14) -// #define NEOPIXEL_POWER_PIN _PINNUM(0, 21) +// #define LED_NEOPIXEL PINNUM(0, 14) +// #define NEOPIXEL_POWER_PIN PINNUM(0, 21) // #define NEOPIXELS_NUMBER 2 #define BOARD_RGB_BRIGHTNESS 0x040404 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(1, 10) -#define BUTTON_2 _PINNUM(1, 2) // stock bootloader has this set to 34 +#define BUTTON_DFU PINNUM(1, 10) +#define BUTTON_DFU_OTA PINNUM(1, 2) // stock bootloader has this set to 34 #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ @@ -52,19 +49,19 @@ //--------------------------------------------------------------------+ // VSensor required to power the display -#define DISPLAY_VSENSOR_PIN _PINNUM(0, 26) +#define DISPLAY_VSENSOR_PIN PINNUM(0, 26) #define DISPLAY_VSENSOR_ON 1 // #define DISPLAY_CONTROLLER_ST7789 #define DISPLAY_CONTROLLER_ST7735 -#define DISPLAY_PIN_SCK _PINNUM(0, 20) -#define DISPLAY_PIN_MOSI _PINNUM(0, 17) +#define DISPLAY_PIN_SCK PINNUM(0, 20) +#define DISPLAY_PIN_MOSI PINNUM(0, 17) -#define DISPLAY_PIN_CS _PINNUM(0, 22) -#define DISPLAY_PIN_DC _PINNUM(0, 15) -#define DISPLAY_PIN_RST _PINNUM(0, 13) -#define DISPLAY_PIN_BL _PINNUM(1, 12) +#define DISPLAY_PIN_CS PINNUM(0, 22) +#define DISPLAY_PIN_DC PINNUM(0, 15) +#define DISPLAY_PIN_RST PINNUM(0, 13) +#define DISPLAY_PIN_BL PINNUM(1, 12) #define DISPLAY_BL_ON 0 // GPIO state to enable back light #define DISPLAY_WIDTH 160 diff --git a/src/boards/heltec_t1/board.h b/src/boards/heltec_t1/board.h index a8ba1be2e..a542d9068 100644 --- a/src/boards/heltec_t1/board.h +++ b/src/boards/heltec_t1/board.h @@ -25,26 +25,23 @@ #ifndef _HELTEC_T1_H #define _HELTEC_T1_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 16) +#define LED_PRIMARY_PIN PINNUM(0, 16) #define LED_STATE_ON 0 -// #define LED_NEOPIXEL _PINNUM(0, 14) -// #define NEOPIXEL_POWER_PIN _PINNUM(0, 21) +// #define LED_NEOPIXEL PINNUM(0, 14) +// #define NEOPIXEL_POWER_PIN PINNUM(0, 21) // #define NEOPIXELS_NUMBER 2 // #define BOARD_RGB_BRIGHTNESS 0x040404 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(1, 10) -#define BUTTON_2 _PINNUM(1, 2) // stock bootloader has this set to 34 +#define BUTTON_DFU PINNUM(1, 10) +#define BUTTON_DFU_OTA PINNUM(1, 2) // stock bootloader has this set to 34 #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ @@ -52,18 +49,18 @@ //--------------------------------------------------------------------+ // VSensor required to power the display -#define DISPLAY_VSENSOR_PIN _PINNUM(0, 13) +#define DISPLAY_VSENSOR_PIN PINNUM(0, 13) #define DISPLAY_VSENSOR_ON 0 #define DISPLAY_CONTROLLER_ST7735 -#define DISPLAY_PIN_SCK _PINNUM(1, 0) -#define DISPLAY_PIN_MOSI _PINNUM(0, 24) +#define DISPLAY_PIN_SCK PINNUM(1, 0) +#define DISPLAY_PIN_MOSI PINNUM(0, 24) -#define DISPLAY_PIN_CS _PINNUM(0, 12) -#define DISPLAY_PIN_DC _PINNUM(0, 22) -#define DISPLAY_PIN_RST _PINNUM(0, 20) -#define DISPLAY_PIN_BL _PINNUM(0, 15) +#define DISPLAY_PIN_CS PINNUM(0, 12) +#define DISPLAY_PIN_DC PINNUM(0, 22) +#define DISPLAY_PIN_RST PINNUM(0, 20) +#define DISPLAY_PIN_BL PINNUM(0, 15) #define DISPLAY_BL_ON 0 // GPIO state to enable back light #define DISPLAY_WIDTH 160 diff --git a/src/boards/heltec_t114/board.h b/src/boards/heltec_t114/board.h index 348f0bdb9..677badc69 100644 --- a/src/boards/heltec_t114/board.h +++ b/src/boards/heltec_t114/board.h @@ -25,26 +25,23 @@ #ifndef _HELTEC_T114_H #define _HELTEC_T114_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(1, 3) // Green +#define LED_PRIMARY_PIN PINNUM(1, 3) // Green #define LED_STATE_ON 0 -#define LED_NEOPIXEL _PINNUM(0, 14) -#define NEOPIXEL_POWER_PIN _PINNUM(0, 21) +#define LED_NEOPIXEL PINNUM(0, 14) +#define NEOPIXEL_POWER_PIN PINNUM(0, 21) #define NEOPIXELS_NUMBER 2 #define BOARD_RGB_BRIGHTNESS 0x040404 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(1, 10) -#define BUTTON_2 _PINNUM(1, 10) +#define BUTTON_DFU PINNUM(1, 10) +#define BUTTON_DFU_OTA PINNUM(1, 10) #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ @@ -52,18 +49,18 @@ //--------------------------------------------------------------------+ // VSensor required to power the display -#define DISPLAY_VSENSOR_PIN _PINNUM(0, 3) +#define DISPLAY_VSENSOR_PIN PINNUM(0, 3) #define DISPLAY_VSENSOR_ON 0 #define DISPLAY_CONTROLLER_ST7789 -#define DISPLAY_PIN_SCK _PINNUM(1, 8) -#define DISPLAY_PIN_MOSI _PINNUM(1, 9) +#define DISPLAY_PIN_SCK PINNUM(1, 8) +#define DISPLAY_PIN_MOSI PINNUM(1, 9) -#define DISPLAY_PIN_CS _PINNUM(0, 11) -#define DISPLAY_PIN_DC _PINNUM(0, 12) -#define DISPLAY_PIN_RST _PINNUM(0, 2) -#define DISPLAY_PIN_BL _PINNUM(0, 15) +#define DISPLAY_PIN_CS PINNUM(0, 11) +#define DISPLAY_PIN_DC PINNUM(0, 12) +#define DISPLAY_PIN_RST PINNUM(0, 2) +#define DISPLAY_PIN_BL PINNUM(0, 15) #define DISPLAY_BL_ON 0 // GPIO state to enable back light #define DISPLAY_WIDTH 240 diff --git a/src/boards/lilygo_techo/board.h b/src/boards/lilygo_techo/board.h index 0e03a5cc9..50d45c1fa 100644 --- a/src/boards/lilygo_techo/board.h +++ b/src/boards/lilygo_techo/board.h @@ -23,23 +23,20 @@ #ifndef _LILYGO_TECHO_H #define _LILYGO_TECHO_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3 /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 14) // Blue +#define LED_PRIMARY_PIN PINNUM(0, 14) // Blue #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 // hold down user button on boot to enter OTA DFU mode. -#define BUTTON_1 _PINNUM(1, 10) // user button -#define BUTTON_2 _PINNUM(1, 10) +#define BUTTON_DFU PINNUM(1, 10) // user button +#define BUTTON_DFU_OTA PINNUM(1, 10) #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/minewsemi_mx25le01/board.h b/src/boards/minewsemi_mx25le01/board.h index 1f4ad5c94..ba353c5c8 100644 --- a/src/boards/minewsemi_mx25le01/board.h +++ b/src/boards/minewsemi_mx25le01/board.h @@ -25,22 +25,19 @@ #ifndef _MINEWSEMI_MX25LE01_H #define _MINEWSEMI_MX25LE01_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 2 -#define LED_PRIMARY_PIN _PINNUM(1, 7) -#define LED_SECONDARY_PIN _PINNUM(1, 5) +#define LED_PRIMARY_PIN PINNUM(1, 7) +#define LED_SECONDARY_PIN PINNUM(1, 5) #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 27) -#define BUTTON_2 _PINNUM(0, 11) +#define BUTTON_DFU PINNUM(0, 27) +#define BUTTON_DFU_OTA PINNUM(0, 11) #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/promicro_nrf52840/board.h b/src/boards/promicro_nrf52840/board.h index 2a85aaea6..12a156d74 100644 --- a/src/boards/promicro_nrf52840/board.h +++ b/src/boards/promicro_nrf52840/board.h @@ -25,23 +25,20 @@ #ifndef _PROMICRO_NRF52840_H #define _PROMICRO_NRF52840_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3 /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 15) // Blue +#define LED_PRIMARY_PIN PINNUM(0, 15) // Blue #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 // changed to GPIO32, default for meshcore and meshtastic -#define BUTTON_1 _PINNUM(1, 0) // user button -#define BUTTON_2 _PINNUM(1, 0) +#define BUTTON_DFU PINNUM(1, 0) // user button +#define BUTTON_DFU_OTA PINNUM(1, 0) #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/sensecap_solar_p1/board.h b/src/boards/sensecap_solar_p1/board.h index 3c3e0e8f8..d8c5d6318 100644 --- a/src/boards/sensecap_solar_p1/board.h +++ b/src/boards/sensecap_solar_p1/board.h @@ -1,66 +1,63 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2018 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _SEEED_SOLAR_NODE_P1_H -#define _SEEED_SOLAR_NODE_P1_H - -#define _PINNUM(port, pin) ((port)*32 + (pin)) - -/*------------------------------------------------------------------*/ -/* LED - *------------------------------------------------------------------*/ -#define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 19) -#define LED_STATE_ON 1 - -#define NEOPIXELS_NUMBER 0 - -/*------------------------------------------------------------------*/ -/* BUTTON - *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(1, 1) // Hold user button while pressing reset to enter OTA DFU mode -#define BUTTON_2 _PINNUM(1, 1) -#define BUTTON_PULL NRF_GPIO_PIN_PULLUP - -//--------------------------------------------------------------------+ -// BLE OTA -//--------------------------------------------------------------------+ -#define BLEDIS_MANUFACTURER "Seeed" -#define BLEDIS_MODEL "SenseCAP Solar Node P1" - -//--------------------------------------------------------------------+ -// USB -//--------------------------------------------------------------------+ -#define USB_DESC_VID 0x2886 -#define USB_DESC_UF2_PID 0x0044 -#define USB_DESC_CDC_ONLY_PID 0x0044 - -//------------- UF2 -------------// -#define UF2_PRODUCT_NAME "Seeed Solar Node P1" -#define UF2_VOLUME_LABEL "SENSECAP" -#define UF2_BOARD_ID "nRF52840-SeeedSenseCAPSolarP1-v1" -#define UF2_INDEX_URL "https://www.seeedstudio.com/" - -#endif // _SEEED_SOLAR_NODE_P1_H +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ha Thach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SEEED_SOLAR_NODE_P1_H +#define _SEEED_SOLAR_NODE_P1_H + +/*------------------------------------------------------------------*/ +/* LED + *------------------------------------------------------------------*/ +#define LEDS_NUMBER 1 +#define LED_PRIMARY_PIN PINNUM(0, 19) +#define LED_STATE_ON 1 + +#define NEOPIXELS_NUMBER 0 + +/*------------------------------------------------------------------*/ +/* BUTTON + *------------------------------------------------------------------*/ +#define BUTTON_DFU PINNUM(1, 1) // Hold user button while pressing reset to enter OTA DFU mode +#define BUTTON_DFU_OTA PINNUM(1, 1) +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP + +//--------------------------------------------------------------------+ +// BLE OTA +//--------------------------------------------------------------------+ +#define BLEDIS_MANUFACTURER "Seeed" +#define BLEDIS_MODEL "SenseCAP Solar Node P1" + +//--------------------------------------------------------------------+ +// USB +//--------------------------------------------------------------------+ +#define USB_DESC_VID 0x2886 +#define USB_DESC_UF2_PID 0x0044 +#define USB_DESC_CDC_ONLY_PID 0x0044 + +//------------- UF2 -------------// +#define UF2_PRODUCT_NAME "Seeed Solar Node P1" +#define UF2_VOLUME_LABEL "SENSECAP" +#define UF2_BOARD_ID "nRF52840-SeeedSenseCAPSolarP1-v1" +#define UF2_INDEX_URL "https://www.seeedstudio.com/" + +#endif // _SEEED_SOLAR_NODE_P1_H diff --git a/src/boards/heltec_t096/board.cmake b/src/boards/t1000_e/board.cmake similarity index 100% rename from src/boards/heltec_t096/board.cmake rename to src/boards/t1000_e/board.cmake diff --git a/src/boards/t1000_e/board.h b/src/boards/t1000_e/board.h index 1a0874163..58a52c9fe 100644 --- a/src/boards/t1000_e/board.h +++ b/src/boards/t1000_e/board.h @@ -25,43 +25,40 @@ #ifndef _T1000_E_H #define _T1000_E_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ -#define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 24) // Green -#define LED_STATE_ON 0 +#define LEDS_NUMBER 1 +#define LED_PRIMARY_PIN PINNUM(0, 24) // Green +#define LED_STATE_ON 0 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 6) // Primary Button -#define BUTTON_2 _PINNUM(0, 18) // unusable: RESET -#define BUTTON_PULL NRF_GPIO_PIN_PULLUP +#define BUTTON_DFU PINNUM(0, 6) // Primary Button +#define BUTTON_DFU_OTA PINNUM(0, 18) // unusable: RESET +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ // BLE OTA //--------------------------------------------------------------------+ -#define BLEDIS_MANUFACTURER "Seeed Studio" -#define BLEDIS_MODEL "T1000-E" +#define BLEDIS_MANUFACTURER "Seeed Studio" +#define BLEDIS_MODEL "T1000-E" //--------------------------------------------------------------------+ // USB //--------------------------------------------------------------------+ -#define USB_DESC_VID 0x2886 -#define USB_DESC_UF2_PID 0x0057 -#define USB_DESC_CDC_ONLY_PID 0x0057 +#define USB_DESC_VID 0x2886 +#define USB_DESC_UF2_PID 0x0057 +#define USB_DESC_CDC_ONLY_PID 0x0057 //--------------------------------------------------------------------+ // UF2 //--------------------------------------------------------------------+ -#define UF2_PRODUCT_NAME "Seeed T1000-E for Meshtastic" -#define UF2_VOLUME_LABEL "T1000-E" -#define UF2_BOARD_ID "nRF52840-T1000-E-v1" -#define UF2_INDEX_URL "https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html" +#define UF2_PRODUCT_NAME "Seeed T1000-E for Meshtastic" +#define UF2_VOLUME_LABEL "T1000-E" +#define UF2_BOARD_ID "nRF52840-T1000-E-v1" +#define UF2_INDEX_URL "https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html" #endif /* _T1000_E_H */ diff --git a/src/boards/t1000_e/board.mk b/src/boards/t1000_e/board.mk index 8ca19f066..554e02efe 100644 --- a/src/boards/t1000_e/board.mk +++ b/src/boards/t1000_e/board.mk @@ -1,3 +1,4 @@ MCU_SUB_VARIANT = nrf52840 SD_VERSION = 7.3.0 -CFLAGS += -DDEVICE_NAME='"T1KE_DFU"' \ No newline at end of file + +CFLAGS += -DDEVICE_NAME='"T1KE_DFU"' diff --git a/src/boards/thinknode_m1/board.cmake b/src/boards/thinknode_m1/board.cmake deleted file mode 100644 index 25daf71d0..000000000 --- a/src/boards/thinknode_m1/board.cmake +++ /dev/null @@ -1 +0,0 @@ -set(MCU_VARIANT nrf52840) diff --git a/src/boards/thinknode_m1/board.h b/src/boards/thinknode_m1/board.h index 1efb6596a..e97703ad7 100644 --- a/src/boards/thinknode_m1/board.h +++ b/src/boards/thinknode_m1/board.h @@ -23,22 +23,19 @@ #ifndef _THINKNODE_M1_H #define _THINKNODE_M1_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 14) // Blue LED +#define LED_PRIMARY_PIN PINNUM(0, 14) // Blue LED #define LED_STATE_ON 0 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -// #define BUTTON_1 _PINNUM(1, 7) // Function button (TBN) -#define BUTTON_1 _PINNUM(1, 10) // Hold page turn to enter OTA DFU mode. -#define BUTTON_2 _PINNUM(1, 10) // Page Turn button +// #define BUTTON_DFU PINNUM(1, 7) // Function button (TBN) +#define BUTTON_DFU PINNUM(1, 10) // Hold page turn to enter OTA DFU mode. +#define BUTTON_DFU_OTA PINNUM(1, 10) // Page Turn button #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/thinknode_m3/board.h b/src/boards/thinknode_m3/board.h index 158ec3c60..8950bac9c 100644 --- a/src/boards/thinknode_m3/board.h +++ b/src/boards/thinknode_m3/board.h @@ -23,21 +23,18 @@ #ifndef _THINKNODE_M3_H #define _THINKNODE_M3_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(1, 5) // Blue +#define LED_PRIMARY_PIN PINNUM(1, 5) // Blue #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 // these pins were reversed from the stock bootloader -#define BUTTON_1 _PINNUM(0, 11) // probably unconnected? -#define BUTTON_2 _PINNUM(0, 12) // user button +#define BUTTON_DFU PINNUM(0, 11) // probably unconnected? +#define BUTTON_DFU_OTA PINNUM(0, 12) // user button #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/thinknode_m6/board.h b/src/boards/thinknode_m6/board.h index c7bece768..faaf6a9f7 100644 --- a/src/boards/thinknode_m6/board.h +++ b/src/boards/thinknode_m6/board.h @@ -23,21 +23,18 @@ #ifndef _THINKNODE_M6_H #define _THINKNODE_M6_H -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 7) // Blue +#define LED_PRIMARY_PIN PINNUM(0, 7) // Blue #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 // hold down user button on boot to enter OTA DFU mode. -#define BUTTON_1 _PINNUM(0, 17) // user button -#define BUTTON_2 _PINNUM(0, 17) +#define BUTTON_DFU PINNUM(0, 17) // user button +#define BUTTON_DFU_OTA PINNUM(0, 17) #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/wio_tracker_l1/board.h b/src/boards/wio_tracker_l1/board.h index 67670f749..ed5b9f608 100644 --- a/src/boards/wio_tracker_l1/board.h +++ b/src/boards/wio_tracker_l1/board.h @@ -1,66 +1,63 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2018 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _TRACKER_L1 -#define _TRACKER_L1 - -#define _PINNUM(port, pin) ((port)*32 + (pin)) - -/*------------------------------------------------------------------*/ -/* LED - *------------------------------------------------------------------*/ -#define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(1, 1) -#define LED_STATE_ON 1 - -#define NEOPIXELS_NUMBER 0 - -/*------------------------------------------------------------------*/ -/* BUTTON - *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 8) // user button -#define BUTTON_2 _PINNUM(0, 8) -#define BUTTON_PULL NRF_GPIO_PIN_PULLUP - -//--------------------------------------------------------------------+ -// BLE OTA -//--------------------------------------------------------------------+ -#define BLEDIS_MANUFACTURER "Seeed" -#define BLEDIS_MODEL "Wio Tracker L1" - -//--------------------------------------------------------------------+ -// USB -//--------------------------------------------------------------------+ -#define USB_DESC_VID 0x2886 -#define USB_DESC_UF2_PID 0x1667 -#define USB_DESC_CDC_ONLY_PID 0x1667 - -//------------- UF2 -------------// -#define UF2_PRODUCT_NAME "Seeed TRACKER L1" -#define UF2_VOLUME_LABEL "TRACKER L1" -#define UF2_BOARD_ID "TRACKER L1" -#define UF2_INDEX_URL "https://www.seeedstudio.com/" - -#endif // _TRACKER_L1 +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ha Thach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _TRACKER_L1 +#define _TRACKER_L1 + +/*------------------------------------------------------------------*/ +/* LED + *------------------------------------------------------------------*/ +#define LEDS_NUMBER 1 +#define LED_PRIMARY_PIN PINNUM(1, 1) +#define LED_STATE_ON 1 + +#define NEOPIXELS_NUMBER 0 + +/*------------------------------------------------------------------*/ +/* BUTTON + *------------------------------------------------------------------*/ +#define BUTTON_DFU PINNUM(0, 8) // user button +#define BUTTON_DFU_OTA PINNUM(0, 8) +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP + +//--------------------------------------------------------------------+ +// BLE OTA +//--------------------------------------------------------------------+ +#define BLEDIS_MANUFACTURER "Seeed" +#define BLEDIS_MODEL "Wio Tracker L1" + +//--------------------------------------------------------------------+ +// USB +//--------------------------------------------------------------------+ +#define USB_DESC_VID 0x2886 +#define USB_DESC_UF2_PID 0x1667 +#define USB_DESC_CDC_ONLY_PID 0x1667 + +//------------- UF2 -------------// +#define UF2_PRODUCT_NAME "Seeed TRACKER L1" +#define UF2_VOLUME_LABEL "TRACKER L1" +#define UF2_BOARD_ID "TRACKER L1" +#define UF2_INDEX_URL "https://www.seeedstudio.com/" + +#endif // _TRACKER_L1 diff --git a/src/boards/wio_tracker_l1/board.mk b/src/boards/wio_tracker_l1/board.mk index c8ac6aadf..f255dd1ab 100644 --- a/src/boards/wio_tracker_l1/board.mk +++ b/src/boards/wio_tracker_l1/board.mk @@ -1,3 +1,3 @@ -MCU_SUB_VARIANT = nrf52840 -SD_VERSION = 7.3.0 +MCU_SUB_VARIANT = nrf52840 +SD_VERSION = 7.3.0 CFLAGS += -DDEVICE_NAME='"WTL1_DFU"' \ No newline at end of file diff --git a/src/boards/wio_tracker_l1/pinconfig.c b/src/boards/wio_tracker_l1/pinconfig.c index 2a7e0a621..2a592df91 100644 --- a/src/boards/wio_tracker_l1/pinconfig.c +++ b/src/boards/wio_tracker_l1/pinconfig.c @@ -1,19 +1,19 @@ -#include "boards.h" -#include "uf2/configkeys.h" - -__attribute__((used, section(".bootloaderConfig"))) -const uint32_t bootloaderConfig[] = -{ - /* CF2 START */ - CFG_MAGIC0, CFG_MAGIC1, // magic - 5, 100, // used entries, total entries - - 204, 0x100000, // FLASH_BYTES = 0x100000 - 205, 0x40000, // RAM_BYTES = 0x40000 - 208, (USB_DESC_VID << 16) | USB_DESC_UF2_PID, // BOOTLOADER_BOARD_ID = USB VID+PID, used for verification when updating bootloader via uf2 - 209, 0xada52840, // UF2_FAMILY = 0xada52840 - 210, 0x20, // PINS_PORT_SIZE = PA_32 - - 0, 0, 0, 0, 0, 0, 0, 0 - /* CF2 END */ +#include "boards.h" +#include "uf2/configkeys.h" + +__attribute__((used, section(".bootloaderConfig"))) +const uint32_t bootloaderConfig[] = +{ + /* CF2 START */ + CFG_MAGIC0, CFG_MAGIC1, // magic + 5, 100, // used entries, total entries + + 204, 0x100000, // FLASH_BYTES = 0x100000 + 205, 0x40000, // RAM_BYTES = 0x40000 + 208, (USB_DESC_VID << 16) | USB_DESC_UF2_PID, // BOOTLOADER_BOARD_ID = USB VID+PID, used for verification when updating bootloader via uf2 + 209, 0xada52840, // UF2_FAMILY = 0xada52840 + 210, 0x20, // PINS_PORT_SIZE = PA_32 + + 0, 0, 0, 0, 0, 0, 0, 0 + /* CF2 END */ }; \ No newline at end of file diff --git a/src/boards/wiscore_rak3401/board.h b/src/boards/wiscore_rak3401/board.h index ae5c86bee..11a08d21b 100644 --- a/src/boards/wiscore_rak3401/board.h +++ b/src/boards/wiscore_rak3401/board.h @@ -28,22 +28,19 @@ // change default 1.8v to 3.3v, add by taylor #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3 -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 2 -#define LED_PRIMARY_PIN _PINNUM(1, 3) -#define LED_SECONDARY_PIN _PINNUM(1, 4) +#define LED_PRIMARY_PIN PINNUM(1, 3) +#define LED_SECONDARY_PIN PINNUM(1, 4) #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. -#define BUTTON_2 _PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. +#define BUTTON_DFU PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. +#define BUTTON_DFU_OTA PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/wiscore_rak4631_board/board.h b/src/boards/wiscore_rak4631_board/board.h index 7886cc334..40a974dfc 100644 --- a/src/boards/wiscore_rak4631_board/board.h +++ b/src/boards/wiscore_rak4631_board/board.h @@ -28,22 +28,19 @@ // change default 1.8v to 3.3v, add by taylor #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3 -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 2 -#define LED_PRIMARY_PIN _PINNUM(1, 3) -#define LED_SECONDARY_PIN _PINNUM(1, 4) +#define LED_PRIMARY_PIN PINNUM(1, 3) +#define LED_SECONDARY_PIN PINNUM(1, 4) #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. -#define BUTTON_2 _PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. +#define BUTTON_DFU PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. +#define BUTTON_DFU_OTA PINNUM(0, 8) // change default 0.0 to 0.8, add by Michael. This pin is not connected on 4631. #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/wismesh_tag/board.h b/src/boards/wismesh_tag/board.h index 4a1507c0f..c2206df55 100644 --- a/src/boards/wismesh_tag/board.h +++ b/src/boards/wismesh_tag/board.h @@ -28,22 +28,19 @@ // change default 1.8v to 3.3v, add by taylor #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3 -#define _PINNUM(port, pin) ((port)*32 + (pin)) - /*------------------------------------------------------------------*/ /* LED *------------------------------------------------------------------*/ #define LEDS_NUMBER 2 -#define LED_PRIMARY_PIN _PINNUM(1, 4) -#define LED_SECONDARY_PIN _PINNUM(1, 3) +#define LED_PRIMARY_PIN PINNUM(1, 4) +#define LED_SECONDARY_PIN PINNUM(1, 3) #define LED_STATE_ON 1 /*------------------------------------------------------------------*/ /* BUTTON *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 9) // Allow booting to OTA DFU from button -#define BUTTON_2 _PINNUM(0, 9) // Allow booting to OTA DFU from button +#define BUTTON_DFU PINNUM(0, 9) // Allow booting to OTA DFU from button +#define BUTTON_DFU_OTA PINNUM(0, 9) // Allow booting to OTA DFU from button #define BUTTON_PULL NRF_GPIO_PIN_PULLUP //--------------------------------------------------------------------+ diff --git a/src/boards/heltec_t1/board.cmake b/src/boards/xiao_nrf52840_ble/board.cmake similarity index 100% rename from src/boards/heltec_t1/board.cmake rename to src/boards/xiao_nrf52840_ble/board.cmake diff --git a/src/boards/xiao_nrf52840_ble/board.h b/src/boards/xiao_nrf52840_ble/board.h index 9f4c45e6e..b04dc39b6 100644 --- a/src/boards/xiao_nrf52840_ble/board.h +++ b/src/boards/xiao_nrf52840_ble/board.h @@ -1,68 +1,65 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2018 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _XIAO_BLE -#define _XIAO_BLE - -#define _PINNUM(port, pin) ((port)*32 + (pin)) - -/*------------------------------------------------------------------*/ -/* LED - *------------------------------------------------------------------*/ -// The board has 3 leds, but changing the number here causes OTA issues. -#define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 26) -#define LED_STATE_ON 0 - -#define NEOPIXELS_NUMBER 0 - -/*------------------------------------------------------------------*/ -/* BUTTON - *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 18) -// Button 2 is defined as D1 from expansion board. -#define BUTTON_2 _PINNUM(0, 3) -#define BUTTON_PULL NRF_GPIO_PIN_PULLUP - -//--------------------------------------------------------------------+ -// BLE OTA -//--------------------------------------------------------------------+ -#define BLEDIS_MANUFACTURER "Seeed" -#define BLEDIS_MODEL "XIAO nRF52840" - -//--------------------------------------------------------------------+ -// USB -//--------------------------------------------------------------------+ -#define USB_DESC_VID 0x2886 -#define USB_DESC_UF2_PID 0x0044 -#define USB_DESC_CDC_ONLY_PID 0x0044 - -//------------- UF2 -------------// -#define UF2_PRODUCT_NAME "Seeed XIAO nRF52840" -#define UF2_VOLUME_LABEL "XIAO-BOOT" -#define UF2_BOARD_ID "nRF52840-SeeedXiao-v1" -#define UF2_INDEX_URL "https://www.seeedstudio.com/" - -#endif // _XIAO_BLE +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ha Thach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _XIAO_BLE +#define _XIAO_BLE + +/*------------------------------------------------------------------*/ +/* LED + *------------------------------------------------------------------*/ +#define LEDS_NUMBER 2 +#define LED_PRIMARY_PIN PINNUM(0, 26) // red +#define LED_SECONDARY_PIN PINNUM(0, 6) // blue +#define LED_STATE_ON 0 + +#define NEOPIXELS_NUMBER 0 + +/*------------------------------------------------------------------*/ +/* BUTTON + *------------------------------------------------------------------*/ +#define BUTTON_DFU PINNUM(0, 18) +// Button 2 is defined as D1 from expansion board. +#define BUTTON_DFU_OTA PINNUM(0, 3) +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP + +//--------------------------------------------------------------------+ +// BLE OTA +//--------------------------------------------------------------------+ +#define BLEDIS_MANUFACTURER "Seeed" +#define BLEDIS_MODEL "XIAO nRF52840" + +//--------------------------------------------------------------------+ +// USB +//--------------------------------------------------------------------+ +#define USB_DESC_VID 0x2886 +#define USB_DESC_UF2_PID 0x0044 +#define USB_DESC_CDC_ONLY_PID 0x0044 + +//------------- UF2 -------------// +#define UF2_PRODUCT_NAME "Seeed XIAO nRF52840" +#define UF2_VOLUME_LABEL "XIAO-BOOT" +#define UF2_BOARD_ID "nRF52840-SeeedXiao-v1" +#define UF2_INDEX_URL "https://www.seeedstudio.com/" + +#endif // _XIAO_BLE diff --git a/src/boards/xiao_nrf52840_ble/board.mk b/src/boards/xiao_nrf52840_ble/board.mk index 5ddfcdac1..f4577d07d 100644 --- a/src/boards/xiao_nrf52840_ble/board.mk +++ b/src/boards/xiao_nrf52840_ble/board.mk @@ -1,3 +1,3 @@ MCU_SUB_VARIANT = nrf52840 SD_VERSION = 7.3.0 -CFLAGS += -DDEVICE_NAME='"XIAO_DFU"' \ No newline at end of file +CFLAGS += -DDEVICE_NAME='"XIAO_DFU"' diff --git a/src/boards/heltec_t114/board.cmake b/src/boards/xiao_nrf52840_ble_sense/board.cmake similarity index 100% rename from src/boards/heltec_t114/board.cmake rename to src/boards/xiao_nrf52840_ble_sense/board.cmake diff --git a/src/boards/xiao_nrf52840_ble_sense/board.h b/src/boards/xiao_nrf52840_ble_sense/board.h index e512c1b78..cd74bc926 100644 --- a/src/boards/xiao_nrf52840_ble_sense/board.h +++ b/src/boards/xiao_nrf52840_ble_sense/board.h @@ -1,68 +1,65 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2018 Ha Thach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _XIAO_BLE_SENSE -#define _XIAO_BLE_SENSE - -#define _PINNUM(port, pin) ((port)*32 + (pin)) - -/*------------------------------------------------------------------*/ -/* LED - *------------------------------------------------------------------*/ -// The board has 3 leds, but changing the number here causes OTA issues. -#define LEDS_NUMBER 1 -#define LED_PRIMARY_PIN _PINNUM(0, 26) -#define LED_STATE_ON 0 - -#define NEOPIXELS_NUMBER 0 - -/*------------------------------------------------------------------*/ -/* BUTTON - *------------------------------------------------------------------*/ -#define BUTTONS_NUMBER 2 -#define BUTTON_1 _PINNUM(0, 18) -// Button 2 is defined as D1 from expansion board. -#define BUTTON_2 _PINNUM(0, 3) -#define BUTTON_PULL NRF_GPIO_PIN_PULLUP - -//--------------------------------------------------------------------+ -// BLE OTA -//--------------------------------------------------------------------+ -#define BLEDIS_MANUFACTURER "Seeed" -#define BLEDIS_MODEL "XIAO nRF52840 Sense" - -//--------------------------------------------------------------------+ -// USB -//--------------------------------------------------------------------+ -#define USB_DESC_VID 0x2886 -#define USB_DESC_UF2_PID 0x0045 -#define USB_DESC_CDC_ONLY_PID 0x0045 - -//------------- UF2 -------------// -#define UF2_PRODUCT_NAME "Seeed XIAO nRF52840" -#define UF2_VOLUME_LABEL "XIAO-SENSE" -#define UF2_BOARD_ID "nRF52840-SeeedXiaoSense-v1" -#define UF2_INDEX_URL "https://www.seeedstudio.com/" - -#endif // _XIAO_BLE_SENSE +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ha Thach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _XIAO_BLE_SENSE +#define _XIAO_BLE_SENSE + +/*------------------------------------------------------------------*/ +/* LED + *------------------------------------------------------------------*/ +#define LEDS_NUMBER 2 +#define LED_PRIMARY_PIN PINNUM(0, 26) // red +#define LED_SECONDARY_PIN PINNUM(0, 6) // blue +#define LED_STATE_ON 0 + +#define NEOPIXELS_NUMBER 0 + +/*------------------------------------------------------------------*/ +/* BUTTON + *------------------------------------------------------------------*/ +#define BUTTON_DFU PINNUM(0, 18) +// Button 2 is defined as D1 from expansion board. +#define BUTTON_DFU_OTA PINNUM(0, 3) +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP + +//--------------------------------------------------------------------+ +// BLE OTA +//--------------------------------------------------------------------+ +#define BLEDIS_MANUFACTURER "Seeed" +#define BLEDIS_MODEL "XIAO nRF52840 Sense" + +//--------------------------------------------------------------------+ +// USB +//--------------------------------------------------------------------+ +#define USB_DESC_VID 0x2886 +#define USB_DESC_UF2_PID 0x0045 +#define USB_DESC_CDC_ONLY_PID 0x0045 + +//------------- UF2 -------------// +#define UF2_PRODUCT_NAME "Seeed XIAO nRF52840" +#define UF2_VOLUME_LABEL "XIAO-SENSE" +#define UF2_BOARD_ID "nRF52840-SeeedXiaoSense-v1" +#define UF2_INDEX_URL "https://www.seeedstudio.com/" + +#endif // _XIAO_BLE_SENSE diff --git a/src/boards/xiao_nrf52840_ble_sense/board.mk b/src/boards/xiao_nrf52840_ble_sense/board.mk index 5ddfcdac1..f4577d07d 100644 --- a/src/boards/xiao_nrf52840_ble_sense/board.mk +++ b/src/boards/xiao_nrf52840_ble_sense/board.mk @@ -1,3 +1,3 @@ MCU_SUB_VARIANT = nrf52840 SD_VERSION = 7.3.0 -CFLAGS += -DDEVICE_NAME='"XIAO_DFU"' \ No newline at end of file +CFLAGS += -DDEVICE_NAME='"XIAO_DFU"' diff --git a/src/dfu_init.c b/src/dfu_init.c index e19cffa36..612fed9cf 100644 --- a/src/dfu_init.c +++ b/src/dfu_init.c @@ -66,16 +66,24 @@ * If the init packet is signed by a trusted source, it must be decrypted before it can be * processed. */ - + #include "dfu_init.h" #include #include #include #include "nrf_error.h" + +#ifndef SIGNED_FW #include "crc16.h" +#else +#include +#include +#include +#include +#endif /* ADAFRUIT - * - All firmware init data must has Device Type ADAFRUIT_DEVICE_TYPE (nrf52832 and nrf52840) + * - All firmware init data must have Device Type ADAFRUIT_DEVICE_TYPE (nrf52832 and nrf52840) * - SD + Bootloader upgrade must have correct Device Revision to make sure bootloader is not flashed * on the wrong device (e.g flah nRF52832's bootloader on nRF52840 board and vice versa) * - nrf52832 dev-rev is 0xADAF @@ -93,122 +101,230 @@ #error Unknown MCU #endif +#ifdef SIGNED_FW + +// The following is the layout of the extended init packet if using image length and sha256 to validate image +// and NIST P-256 + SHA256 to sign the init_package including the extended part +#define DFU_INIT_PACKET_POS_EXT_IDENTIFIER 0 //< Position of the identifier for the ext package +#define DFU_INIT_PACKET_POS_EXT_IMAGE_LENGTH 4 //< Position of the image length +#define DFU_INIT_PACKET_POS_EXT_IMAGE_HASH256 8 //< Position of the 256 +#define DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_R 40 //< Position of the Signature R +#define DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_S 72 //< Position of the Signature S +#define DFU_INIT_PACKET_EXT_LENGTH_SIGNED 40 //< Length of the extended init packet that is part of the signed data +#define DFU_INIT_PACKET_EXT_BEGIN + +#define DFU_SHA256_DIGEST_LENGTH 32 //< Length of SHA-256 digest +#define DFU_SIGNATURE_R_LENGTH 32 //< Length of the signature part r +#define DFU_SIGNATURE_S_LENGTH 32 //< Length of the signature part s + +#define DFU_INIT_PACKET_USES_CRC16 (0) +#define DFU_INIT_PACKET_USES_HASH (1) +#define DFU_INIT_PACKET_USES_ECDS (2) + +#if !defined(SIGNED_FW_QX) || !defined(SIGNED_FW_QY) +# error Missing definitions for SIGNED_FW_QX and/or SIGNED_FW_QY required for signed firmware verification +#endif + +/** @snippet [DFU BLE Signing public key curve points] */ +static const uint8_t pk[] = { + /* x-coord : static uint8_t Qx[] = {*/ + SIGNED_FW_QX + /* 0x39, 0xb0, 0x58, 0x3d, 0x27, 0x07, 0x91, 0x38, + 0x6a, 0xa3, 0x36, 0x0f, 0xa2, 0xb5, 0x86, 0x7e, + 0xae, 0xba, 0xf7, 0xa3, 0xf4, 0x81, 0x5f, 0x78, + 0x02, 0xf2, 0xa1, 0x21, 0xd5, 0x21, 0x84, 0x12 */ + /* };*/ + , + /* y-coord : static uint8_t Qy[] = {*/ + SIGNED_FW_QY + /* 0x4a, 0x0d, 0xfe, 0xa4, 0x77, 0x50, 0xb1, 0xb5, 0x26, 0xc0, 0x9d, 0xdd, 0xf0, 0x24, 0x90, 0x57, 0x6c, 0x64, 0x3b, 0xd3, 0xdf, 0x92, 0x3b, 0xb3, 0x47, 0x97, 0x83, 0xd4, 0xfc, 0x76, 0xf5, 0x9d */ + /* };*/ +}; +/** @snippet [DFU BLE Signing public key curve points] */ +// Helper macros for stringification +//#define VSTRINGIFY(...) #__VA_ARGS__ +//#define TO_STRING(...) VSTRINGIFY(__VA_ARGS__) +//#pragma message ("Qx: " TO_STRING(SIGNED_FW_QX)) +//#pragma message ("Qy: " TO_STRING(SIGNED_FW_QY)) -#define DFU_INIT_PACKET_EXT_LENGTH_MIN 2 //< Minimum length of the extended init packet. The extended init packet may contain a CRC, a HASH, or other data. This value must be changed according to the requirements of the system. The template uses a minimum value of two in order to hold a CRC. */ -#define DFU_INIT_PACKET_EXT_LENGTH_MAX 10 //< Maximum length of the extended init packet. The extended init packet may contain a CRC, a HASH, or other data. This value must be changed according to the requirements of the system. The template uses a maximum value of 10 in order to hold a CRC and any padded data on transport layer without overflow. */ +_Static_assert(sizeof(pk) == 64, "Public key must be 64 bytes in size"); + +#endif + +#define DFU_INIT_PACKET_EXT_LENGTH_MIN 2 //< Minimum length of the extended init packet. Init packet and CRC16 +#define DFU_INIT_PACKET_EXT_LENGTH_MAX 104 //< Identifier (4 bytes) + Image length (4 bytes) + SHA-256 digest (32 bytes) + NIST P-256 using SHA-256 (64 bytes) static uint8_t m_extended_packet[DFU_INIT_PACKET_EXT_LENGTH_MAX]; //< Data array for storage of the extended data received. The extended data follows the normal init data of type \ref dfu_init_packet_t. Extended data can be used for a CRC, hash, signature, or other data. */ static uint8_t m_extended_packet_length; //< Length of the extended data received with init packet. */ - uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len, uint8_t image_type) { - uint32_t i = 0; - - // In order to support signing or encryption then any init packet decryption function / library - // should be called from here or implemented at this location. - - // Length check to ensure valid data are parsed. - if (init_data_len < sizeof(dfu_init_packet_t)) - { - return NRF_ERROR_INVALID_LENGTH; - } - - // Current template uses clear text data so they can be casted for pre-check. - dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data; - - m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) - - (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]; - if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN) - { - return NRF_ERROR_INVALID_LENGTH; - } - - if (((uint32_t)p_init_data + init_data_len) < - (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]) - { - return NRF_ERROR_INVALID_LENGTH; - } - - memcpy(m_extended_packet, - &p_init_packet->softdevice[p_init_packet->softdevice_len], - m_extended_packet_length); - - /** [DFU init application version] */ - // To support application versioning, this check should be updated. - // This template allows for any application to be installed. However, - // customers can place a revision number at the bottom of the application - // to be verified by the bootloader. This can be done at a location - // relative to the application, for example the application start - // address + 0x0100. - /** [DFU init application version] */ - - // First check to verify the image to be transfered matches the device type. - // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted. + uint32_t i = 0; + + // In order to support signing or encryption then any init packet decryption function / library + // should be called from here or implemented at this location. + + // Length check to ensure valid data are parsed. + if (init_data_len < sizeof(dfu_init_packet_t)) + { + return NRF_ERROR_INVALID_LENGTH; + } + + // Current template uses clear text data so they can be casted for pre-check. + dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data; + + m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) - + (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]; + if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN) + { + return NRF_ERROR_INVALID_LENGTH; + } + + if (((uint32_t)p_init_data + init_data_len) < + (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]) + { + return NRF_ERROR_INVALID_LENGTH; + } + + memcpy(m_extended_packet, + &p_init_packet->softdevice[p_init_packet->softdevice_len], + m_extended_packet_length); + + /** [DFU init application version] */ + // To support application versioning, this check should be updated. + // This template allows for any application to be installed. However, + // customers can place a revision number at the bottom of the application + // to be verified by the bootloader. This can be done at a location + // relative to the application, for example the application start + // address + 0x0100. + /** [DFU init application version] */ + + // First check to verify the image to be transfered matches the device type. + // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted. // if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) && // (p_init_packet->device_type != DFU_DEVICE_INFO->device_type)) // { // return NRF_ERROR_INVALID_DATA; // } - - // Second check to verify the image to be transfered matches the device revision. - // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted. - // if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) && - // (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev)) - - if ( p_init_packet->device_type != ADAFRUIT_DEVICE_TYPE ) - { - return NRF_ERROR_FORBIDDEN; - } - - // Adafruit unlock code must match to upgrade SoftDevice and/or Bootloader - if ( image_type & (DFU_UPDATE_SD | DFU_UPDATE_BL) ) - { - if (p_init_packet->device_rev != ADAFRUIT_DEV_REV) - { - return NRF_ERROR_FORBIDDEN; - } - } - - // Third check: Check the array of supported SoftDevices by this application. - // If the installed SoftDevice does not match any SoftDevice in the list then an - // error is returned. - while (i < p_init_packet->softdevice_len) - { - if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY || - p_init_packet->softdevice[i++] == SD_FWID_GET(MBR_SIZE)) - { - return NRF_SUCCESS; - } - } - - // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA. - return NRF_ERROR_INVALID_DATA; + + // Second check to verify the image to be transfered matches the device revision. + // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted. + // if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) && + // (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev)) + + if ( p_init_packet->device_type != ADAFRUIT_DEVICE_TYPE ) + { + return NRF_ERROR_FORBIDDEN; + } + + // Adafruit unlock code must match to upgrade SoftDevice and/or Bootloader + if ( image_type & (DFU_UPDATE_SD | DFU_UPDATE_BL) ) + { + if (p_init_packet->device_rev != ADAFRUIT_DEV_REV) + { + return NRF_ERROR_FORBIDDEN; + } + } + + // Third check: Check the array of supported SoftDevices by this application. + // If the installed SoftDevice does not match any SoftDevice in the list then an + // error is returned. + while (i < p_init_packet->softdevice_len) + { + if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY || + p_init_packet->softdevice[i] == SD_FWID_GET(MBR_SIZE)) + { + // Found a match. Break the loop. + break; + } + ++i; + } + + // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA. + if (i >= p_init_packet->softdevice_len) + return NRF_ERROR_INVALID_DATA; + +#ifndef SIGNED_FW + return NRF_SUCCESS; +#else + // Check that we have the correct identifier indicating that ECDS is used + if(*(uint32_t*)&m_extended_packet[DFU_INIT_PACKET_POS_EXT_IDENTIFIER] != DFU_INIT_PACKET_USES_ECDS) + { + return NRF_ERROR_INVALID_DATA; + } + + uint8_t* msg = p_init_data; + size_t msg_len = (init_data_len - m_extended_packet_length) + DFU_INIT_PACKET_EXT_LENGTH_SIGNED; + + // Create a sha256 digest + struct tc_sha256_state_struct state = {0}; + uint8_t digest[TC_SHA256_DIGEST_SIZE]; + if (tc_sha256_init(&state) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + if (tc_sha256_update(&state,msg,msg_len) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + if (tc_sha256_final(digest,&state) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + + // And verify signature + const struct uECC_Curve_t * curve = uECC_secp256r1(); + if (uECC_valid_public_key(pk, curve) != 0) + return NRF_ERROR_INVALID_DATA; + + unsigned char* sig = &m_extended_packet[DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_R]; +# if (DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_S - DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_R) != DFU_SIGNATURE_R_LENGTH +# error Incorrect layout: r and s must be contiguous! +# endif + + return uECC_verify(pk, digest, sizeof(digest), sig, curve) == 1 ? NRF_SUCCESS : NRF_ERROR_INVALID_DATA; +#endif } uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len) { - uint16_t image_crc; - uint16_t received_crc; - - // In order to support hashing (and signing) then the (decrypted) hash should be fetched and - // the corresponding hash should be calculated over the image at this location. - // If hashing (or signing) is added to the system then the CRC validation should be removed. - - // calculate CRC from active block. - image_crc = crc16_compute(p_image, image_len, NULL); - - // Decode the received CRC from extended data. - received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]); - - // Compare the received and calculated CRC. - if (image_crc != received_crc) - { - return NRF_ERROR_INVALID_DATA; - } - - return NRF_SUCCESS; +#ifndef SIGNED_FW + uint16_t image_crc; + uint16_t received_crc; + + // calculate CRC from active block. + image_crc = crc16_compute(p_image, image_len, NULL); + + // Decode the received CRC from extended data. + received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]); + + // Compare the received and calculated CRC. + if (image_crc != received_crc) + { + return NRF_ERROR_INVALID_DATA; + } + + return NRF_SUCCESS; + +#else + + // Compare image size received with signed init_packet data + if(image_len != *(uint32_t*)&m_extended_packet[DFU_INIT_PACKET_POS_EXT_IMAGE_LENGTH]) + { + return NRF_ERROR_INVALID_DATA; + } + + uint8_t image_digest[DFU_SHA256_DIGEST_LENGTH]; + uint8_t * received_digest; + + // Create a sha256 digest + struct tc_sha256_state_struct state = {0}; + if (tc_sha256_init(&state) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + if (tc_sha256_update(&state, p_image, image_len) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + if (tc_sha256_final(image_digest, &state) != TC_CRYPTO_SUCCESS) return NRF_ERROR_INVALID_DATA; + + received_digest = &m_extended_packet[DFU_INIT_PACKET_POS_EXT_IMAGE_HASH256]; + + // Compare the received and calculated digests. + if (memcmp(&image_digest[0], received_digest, DFU_SHA256_DIGEST_LENGTH) != 0) + { + return NRF_ERROR_INVALID_DATA; + } + + return NRF_SUCCESS; +#endif } diff --git a/src/flash_nrf5x.c b/src/flash_nrf5x.c index 12c6797e8..ddea500eb 100644 --- a/src/flash_nrf5x.c +++ b/src/flash_nrf5x.c @@ -26,48 +26,88 @@ #include "nrf_sdm.h" #include "flash_nrf5x.h" #include "boards.h" +#include "dfu_types.h" -#define FLASH_PAGE_SIZE 4096 #define FLASH_CACHE_INVALID_ADDR 0xffffffff static uint32_t _fl_addr = FLASH_CACHE_INVALID_ADDR; -static uint8_t _fl_buf[FLASH_PAGE_SIZE] __attribute__((aligned(4))); +static uint8_t _fl_buf[CODE_PAGE_SIZE] __attribute__((aligned(4))); -void flash_nrf5x_flush (bool need_erase) +void flash_nrf5x_erase (uint32_t dst, uint32_t len) { - if ( _fl_addr == FLASH_CACHE_INVALID_ADDR ) return; - - // skip the write if contents matches - if ( memcmp(_fl_buf, (void *) _fl_addr, FLASH_PAGE_SIZE) != 0 ) - { - // - nRF52832 dfu via uart can miss incoming byte when erasing because cpu is blocked for > 2ms. - // Since dfu_prepare_func_app_erase() already erase the page for us, we can skip it here. - // - nRF52840 dfu serial/uf2 are USB-based which are DMA and should have no problems. - // - // Note: MSC uf2 does not erase page in advance like dfu serial - if ( need_erase ) + uint32_t page_addr = dst & ~(CODE_PAGE_SIZE - 1); + uint32_t const page_count = NRFX_CEIL_DIV(len, CODE_PAGE_SIZE); + for ( uint32_t i = 0; i < page_count; i++ ) { - PRINTF("Erase and "); - nrfx_nvmc_page_erase(_fl_addr); + uint32_t const addr = page_addr + i * CODE_PAGE_SIZE; + PRINTF("Erase 0x%08lX\r\n", addr); + nrfx_nvmc_page_erase(addr); } +} + - PRINTF("Write 0x%08lX\r\n", _fl_addr); - nrfx_nvmc_words_write(_fl_addr, (uint32_t *) _fl_buf, FLASH_PAGE_SIZE / 4); - } +void flash_nrf5x_flush (bool need_erase) +{ + if ( _fl_addr == FLASH_CACHE_INVALID_ADDR ) + return; + + // skip the write if contents matches + if ( memcmp(_fl_buf, (void *) _fl_addr, CODE_PAGE_SIZE) != 0 ) + { + // - nRF52832 dfu via uart can miss incoming byte when erasing because cpu is blocked for > 2ms. + // Since dfu_prepare_func_app_erase() already erase the page for us, we can skip it here. + // - nRF52840 dfu serial/uf2 are USB-based which are DMA and should have no problems. + // + // Note: MSC uf2 does not erase page in advance like dfu serial + if ( need_erase ) + { + PRINTF("Erase and "); + nrfx_nvmc_page_erase(_fl_addr); + } + + PRINTF("Write 0x%08lX\r\n", _fl_addr); + nrfx_nvmc_words_write(_fl_addr, (uint32_t *) _fl_buf, CODE_PAGE_SIZE / 4); + } - _fl_addr = FLASH_CACHE_INVALID_ADDR; + _fl_addr = FLASH_CACHE_INVALID_ADDR; } -void flash_nrf5x_write (uint32_t dst, void const *src, int len, bool need_erase) +void flash_nrf5x_write (uint32_t dst, void const *src, uint32_t len, bool need_erase) { - uint32_t newAddr = dst & ~(FLASH_PAGE_SIZE - 1); - - if ( newAddr != _fl_addr ) - { - flash_nrf5x_flush(need_erase); - _fl_addr = newAddr; - memcpy(_fl_buf, (void *) newAddr, FLASH_PAGE_SIZE); - } - memcpy(_fl_buf + (dst & (FLASH_PAGE_SIZE - 1)), src, len); + // While something to write... + while (len > 0) { + + // Align to start of page + uint32_t page_addr = dst & ~(CODE_PAGE_SIZE - 1); + + // If page changed, write modified contents + if ( page_addr != _fl_addr ) + { + flash_nrf5x_flush(need_erase); + + // Remember new page + _fl_addr = page_addr; + + // And read its contents + memcpy(_fl_buf, (void *) page_addr, CODE_PAGE_SIZE); + } + + // Compute the write offset into the current page + uint32_t offset_in_page = dst & (CODE_PAGE_SIZE - 1); + + // Compute how many bytes remaining to complete the page + uint32_t bytes_to_end = CODE_PAGE_SIZE - offset_in_page; + + // Limit the count to the available bytes in the current page + uint32_t max_bytes = bytes_to_end < len ? bytes_to_end : len; + + // Copy contents to our buffer + memcpy(_fl_buf + offset_in_page, src, max_bytes); + + // Update variables + len -= max_bytes; + dst += max_bytes; + src = (void const *) ((uint8_t*)src + max_bytes); + }; } diff --git a/src/flash_nrf5x.h b/src/flash_nrf5x.h index 9ab4619e1..d3fbb4906 100644 --- a/src/flash_nrf5x.h +++ b/src/flash_nrf5x.h @@ -34,7 +34,8 @@ extern "C" { #endif -void flash_nrf5x_write (uint32_t dst, void const *src, int len, bool need_erase); +void flash_nrf5x_erase (uint32_t dst, uint32_t len); +void flash_nrf5x_write (uint32_t dst, void const *src, uint32_t len, bool need_erase); void flash_nrf5x_flush (bool need_erase); #ifdef __cplusplus diff --git a/src/main.c b/src/main.c index bd9971379..9c52809ce 100644 --- a/src/main.c +++ b/src/main.c @@ -43,9 +43,7 @@ #include "nrfx_power.h" #include "nrfx_pwm.h" -#include "nordic_common.h" #include "sdk_common.h" -#include "dfu_transport.h" #include "bootloader.h" #include "bootloader_util.h" @@ -65,7 +63,6 @@ #include "pstorage_platform.h" #include "nrf_mbr.h" #include "pstorage.h" -#include "nrfx_nvmc.h" #ifdef NRF_USBD @@ -125,12 +122,9 @@ extern void tusb_hal_nrf_power_event(uint32_t event); // DFU_DBL_RESET magic is used to determined which mode is entered #define APP_ASKS_FOR_SINGLE_TAP_RESET() (*((uint32_t*)(DFU_BANK_0_REGION_START + 0x200)) == 0x87eeb07c) -// These values must match the values in dfu_transport_ble.c and MAX_DFU_PKT_LEN should match BLEGATT_ATT_MTU_MAX - 3 -#define BLEGAP_EVENT_LENGTH 6 -#define BLEGATT_ATT_MTU_MAX 247 -enum { - BLE_CONN_CFG_HIGH_BANDWIDTH = 1 -}; +#define BLEGAP_EVENT_LENGTH 12 +#define BLEGATTS_HVN_QSIZE 12 +#define BLEGATTC_WRCMD_QSIZE 2 //--------------------------------------------------------------------+ // @@ -140,6 +134,7 @@ uint32_t* dbl_reset_mem = ((uint32_t*) DFU_DBL_RESET_MEM); // true if ble, false if serial bool _ota_dfu = false; bool _ota_connected = false; +bool _ota_was_connected = false; bool _sd_inited = false; bool is_ota(void) { @@ -157,6 +152,15 @@ static void mbr_init_sd(void) { sd_mbr_command(&com); } +// Disable the SoftDevice if it is enabled. +static void disable_softdevice(void) { + uint8_t sd_enabled = 0; + sd_softdevice_is_enabled(&sd_enabled); + if (sd_enabled == 1) { + sd_softdevice_disable(); + } +} + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -189,6 +193,10 @@ int main(void) { // Return when DFU process is complete (or not entered at all) check_dfu_mode(); + // Check if we must reenter the bootloader after reset, instead of + // launching the user application + bool bootloader_must_be_reentered = bootloader_must_reset_to_self(); + // Reset peripherals board_teardown(); @@ -199,24 +207,34 @@ int main(void) { * - sd_softdevice_vector_table_base_set(APP_ADDR) * - jump to App reset */ - if (bootloader_app_is_valid() && !bootloader_dfu_sd_in_progress()) { + if (!bootloader_must_be_reentered && + bootloader_app_is_valid() && + !bootloader_dfu_sd_in_progress()) { PRINTF("App is valid\r\n"); if (is_sd_existed()) { // MBR forward IRQ to SD (if not already) if (!_sd_inited) mbr_init_sd(); // Make sure SD is disabled - sd_softdevice_disable(); + disable_softdevice(); } // clear in case we kept DFU_DBL_RESET_APP there (*dbl_reset_mem) = 0; // start application + PRINTF("Starting app...\r\n"); bootloader_app_start(); } - NRF_POWER->GPREGRET = 0xA8; // No application was loaded, reset the system with the OTA DFU update + // No application was loaded or we need to reenter the bootloader + + // Reset the system with the OTA DFU update in case we were in it, + // to allow completion of FLASHING, otherwise, default to normal reset + if (_ota_was_connected) { + NRF_POWER->GPREGRET = DFU_MAGIC_OTA_RESET; + } + NVIC_SystemReset(); } @@ -242,31 +260,49 @@ static void check_dfu_mode(void) { (((*dbl_reset_mem) == DFU_DBL_RESET_MAGIC) && reason_reset_pin); // Clear GPREGRET if it is our values - if (dfu_start || dfu_skip) NRF_POWER->GPREGRET = 0; + if (dfu_start || dfu_skip) { + NRF_POWER->GPREGRET = 0; + } // skip dfu entirely - if (dfu_skip) return; + if (dfu_skip) { + return; + } /*------------- Determine DFU mode (Serial, OTA, FRESET or normal) -------------*/ // DFU button pressed +#if defined(BUTTON_DFU) dfu_start = dfu_start || button_pressed(BUTTON_DFU); +#endif // DFU + FRESET are pressed --> OTA - _ota_dfu = _ota_dfu || (button_pressed(BUTTON_DFU) && button_pressed(BUTTON_FRESET)); +#if defined(BUTTON_DFU) && defined(BUTTON_DFU_OTA) + _ota_dfu = _ota_dfu || (button_pressed(BUTTON_DFU) && button_pressed(BUTTON_DFU_OTA)); +#endif bool const valid_app = bootloader_app_is_valid(); bool const just_start_app = valid_app && !dfu_start && (*dbl_reset_mem) == DFU_DBL_RESET_APP; - if (!just_start_app && APP_ASKS_FOR_SINGLE_TAP_RESET()) dfu_start = 1; + if (!just_start_app && APP_ASKS_FOR_SINGLE_TAP_RESET()) { + dfu_start = 1; + } + +#ifdef DEFAULT_TO_OTA_DFU + // Default to OTA DFU mode, instead of Serial DFU mode, if there is no app present, + // because otherwise, if there is no application, it will restart in Serial DFU mode, + // making it IMPOSSIBLE to recover devices in the field if there are no user + // accessible USB ports + if (!valid_app || dfu_start) { + _ota_dfu = 1; + } +#endif // App mode: Double Reset detection or DFU startup for nrf52832 if (!(just_start_app || dfu_start)) { // removed !valid_app check to allow double reset even when no app #ifdef NRF52832_XXAA /* Even DFU is not active, we still force an 1000 ms dfu serial mode when startup * to support auto programming from Arduino IDE - * - * Note: Double Reset WONT work with nrf52832 since all its SRAM got cleared with GPIO reset. - */ + * Note: Double Reset WONT work with nrf52832 since all its SRAM got cleared with GPIO reset. */ bootloader_dfu_start(false, DFU_SERIAL_STARTUP_INTERVAL, false); #else // Note: RESETREAS is not clear by bootloader, it should be cleared by application upon init() @@ -316,7 +352,7 @@ static void check_dfu_mode(void) { } if (_ota_dfu) { - sd_softdevice_disable(); + disable_softdevice(); usb_teardown(); // allow booting to app after ota even if usb is connected } else { usb_teardown(); @@ -324,7 +360,11 @@ static void check_dfu_mode(void) { } } -// Initializes the SotdDevice by following SD specs section +//--------------------------------------------------------------------+ +// BLE +//--------------------------------------------------------------------+ + +// Initializes the SoftDevice by following SD specs section // "Master Boot Record and SoftDevice initializaton procedure" static uint32_t ble_stack_init(void) { // Forward vector table to bootloader address so that we can handle BLE events @@ -337,7 +377,11 @@ static uint32_t ble_stack_init(void) { .rc_temp_ctiv = 2, .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM }; - sd_softdevice_enable(&clock_cfg, app_error_fault_handler); + #ifdef ANT_LICENSE_KEY + sd_softdevice_enable(&clock_cfg, app_error_fault_handler, ANT_LICENSE_KEY); + #else + sd_softdevice_enable(&clock_cfg, app_error_fault_handler); + #endif sd_nvic_EnableIRQ(SD_EVT_IRQn); /*------------- Configure BLE params -------------*/ @@ -372,36 +416,99 @@ static uint32_t ble_stack_init(void) { blecfg.conn_cfg.params.gap_conn_cfg.event_length = BLEGAP_EVENT_LENGTH; sd_ble_cfg_set(BLE_CONN_CFG_GAP, &blecfg, ram_start); + // HVN queue size + varclr(&blecfg); + blecfg.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_HIGH_BANDWIDTH; + blecfg.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = BLEGATTS_HVN_QSIZE; + sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &blecfg, ram_start); + + // WRITE COMMAND queue size + varclr(&blecfg); + blecfg.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_HIGH_BANDWIDTH; + blecfg.conn_cfg.params.gattc_conn_cfg.write_cmd_tx_queue_size = BLEGATTC_WRCMD_QSIZE; + sd_ble_cfg_set(BLE_CONN_CFG_GATTC, &blecfg, ram_start); + // Enable BLE stack. // Note: Interrupt state (enabled, forwarding) is not work properly if not enable ble sd_ble_enable(&ram_start); -// #if 0 +#if BLEGATT_ATT_MTU_MAX > 23 || defined(GPIO_PA_PIN) || defined(GPIO_LNA_PIN) ble_opt_t opt; +#endif + +#if BLEGATT_ATT_MTU_MAX > 23 varclr(&opt); opt.common_opt.conn_evt_ext.enable = 1; // enable Data Length Extension sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt); -// #endif +#endif - return NRF_SUCCESS; -} +#if defined(GPIO_PA_LNA_MODE_PIN) + // Set PA / LNA Mode Pin: Low for Normal operation + nrf_gpio_cfg_output(GPIO_PA_LNA_MODE_PIN); + nrf_gpio_pin_clear(GPIO_PA_LNA_MODE_PIN); +#endif -//--------------------------------------------------------------------+ -// Error Handler -//--------------------------------------------------------------------+ -void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) { - volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ - if ((*ARM_CM_DHCSR) & 1UL) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ - NVIC_SystemReset(); -} +#if defined(GPIO_PA_LNA_SELECT_PIN) + // Set PA / LNA Select Pin: low for u.FL + nrf_gpio_cfg_output(GPIO_PA_LNA_SELECT_PIN); + nrf_gpio_pin_clear(GPIO_PA_LNA_SELECT_PIN); +#endif -void assert_nrf_callback(uint16_t line_num, uint8_t const* p_file_name) { - app_error_fault_handler(0xDEADBEEF, 0, 0); + // Configure SoftDevice PA / LNA assist if required +#if defined(GPIO_PA_PIN) || defined(GPIO_LNA_PIN) + + static const uint32_t gpio_toggle_ch = 0; + static const uint32_t ppi_set_ch = 0; + static const uint32_t ppi_clr_ch = 1; + + varclr(&opt); + + // Common PA / LNA config + // GPIOTE channel + opt.common_opt.pa_lna.gpiote_ch_id = gpio_toggle_ch; + // PPI channel for pin learing + opt.common_opt.pa_lna.ppi_ch_id_clr = ppi_clr_ch; + // PPI channel for pin setting + opt.common_opt.pa_lna.ppi_ch_id_set = ppi_set_ch; + +# if defined(GPIO_PA_PIN) + // -- PA config -- + // Set the pin to be active high + opt.common_opt.pa_lna.pa_cfg.active_high = GPIO_PA_PIN_ACTIVE_STATE; + // Enable toggling + opt.common_opt.pa_lna.pa_cfg.enable = 1; + // The GPIO pin to toggle + opt.common_opt.pa_lna.pa_cfg.gpio_pin = GPIO_PA_PIN; +# endif + +# if defined(GPIO_LNA_PIN) + // -- LNA config -- + // Set the pin to be active high + opt.common_opt.pa_lna.lna_cfg.active_high = GPIO_LNA_PIN_ACTIVE_STATE; + // Enable toggling + opt.common_opt.pa_lna.lna_cfg.enable = 1; + + // The GPIO pin to toggle + opt.common_opt.pa_lna.lna_cfg.gpio_pin = GPIO_LNA_PIN; + sd_ble_opt_set(BLE_COMMON_OPT_PA_LNA, &opt); +# endif + + // Set TX power for scan responses + sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, 0, RADIO_TXPOWER_TXPOWER_Neg8dBm); + + // Set TX power for advertisements + sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, RADIO_TXPOWER_TXPOWER_Neg8dBm); + // (Tx power setting for connections inherit the scan or advertising power setting) + +#endif + + return NRF_SUCCESS; } /*------------------------------------------------------------------*/ /* SoftDevice Event handler *------------------------------------------------------------------*/ +extern void ble_evt_dispatch(ble_evt_t *p_ble_evt); // Process BLE event from SD uint32_t proc_ble(void) { @@ -418,10 +525,22 @@ uint32_t proc_ble(void) { // Handle valid event, ignore error if (NRF_SUCCESS == err) { switch (evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: + case BLE_GAP_EVT_CONNECTED: { + // Try to enable 2M phy,if phone allows it + ble_gap_phys_t const phys = + { + .rx_phys = BLE_GAP_PHY_AUTO, + .tx_phys = BLE_GAP_PHY_AUTO, + }; + sd_ble_gap_phy_update(evt->evt.gap_evt.conn_handle, &phys); + _ota_connected = true; + + // Remember someone connected to BLE + _ota_was_connected = true; led_state(STATE_BLE_CONNECTED); break; + } case BLE_GAP_EVT_DISCONNECTED: _ota_connected = false; @@ -433,7 +552,6 @@ uint32_t proc_ble(void) { } // from dfu_transport_ble - extern void ble_evt_dispatch(ble_evt_t* p_ble_evt); ble_evt_dispatch(evt); } @@ -454,7 +572,9 @@ uint32_t proc_soc(void) { (soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY : (soc_evt == NRF_EVT_POWER_USB_REMOVED) ? NRFX_POWER_USB_EVT_REMOVED : -1; - if (usbevt >= 0) tusb_hal_nrf_power_event((uint32_t) usbevt); + if (usbevt >= 0) { + tusb_hal_nrf_power_event((uint32_t)usbevt); + } #endif } @@ -476,6 +596,22 @@ void SD_EVT_IRQHandler(void) { app_sched_event_put(NULL, 0, proc_sd_task); } +//--------------------------------------------------------------------+ +// Error Handler +//--------------------------------------------------------------------+ +void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) { + volatile uint32_t *ARM_CM_DHCSR = ((volatile uint32_t *)0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ + if ((*ARM_CM_DHCSR) & 1UL) { + __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ + } + NVIC_SystemReset(); +} + +void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) { + app_error_fault_handler(0xDEADBEEF, 0, 0); +} + + //--------------------------------------------------------------------+ // RTT printf retarget for Debug //--------------------------------------------------------------------+ diff --git a/src/pstorage_platform.h b/src/pstorage_platform.h index bbc573cc2..959005c53 100644 --- a/src/pstorage_platform.h +++ b/src/pstorage_platform.h @@ -78,7 +78,7 @@ static __INLINE uint32_t pstorage_flash_page_end() #define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR #define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */ -#define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */ +#define PSTORAGE_CMD_QUEUE_SIZE 18 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */ /**@breif Define this flag in case Raw access to persistent memory is to be enabled. Raw mode * unlike the data mode is for uses other than storing data from various mode. This mode is diff --git a/src/sdk_config.h b/src/sdk_config.h index 4e55b1736..b61b1f0c5 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -38,8 +38,6 @@ * */ - - #ifndef SDK_CONFIG_H #define SDK_CONFIG_H @@ -66,7 +64,7 @@ #define HCI_MEM_POOL_ENABLED 1 #define HCI_TX_BUF_SIZE 600 // not used #define HCI_RX_BUF_SIZE 600 -#define HCI_RX_BUF_QUEUE_SIZE 16 // must be power of 2 +#define HCI_RX_BUF_QUEUE_SIZE 16 // must be power of 2 //========================================================== // UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver @@ -119,6 +117,12 @@ #define CRC16_ENABLED 1 #define NRF_STRERROR_ENABLED 1 +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +#define BLEGATT_ATT_MTU_MAX 247 +#define BLE_CONN_CFG_HIGH_BANDWIDTH 1 + #endif //SDK_CONFIG_H diff --git a/src/usb/msc_uf2.c b/src/usb/msc_uf2.c index ea7a2511d..15b0cbdfd 100644 --- a/src/usb/msc_uf2.c +++ b/src/usb/msc_uf2.c @@ -145,9 +145,19 @@ int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* uint32_t count = 0; while ( count < bufsize ) { + int written; + // Consider non-uf2 block write as successful // only break if write_block is busy with flashing (return 0) - if ( 0 == write_block(lba, buffer, &_wr_state) ) break; + written = write_block(lba, buffer, &_wr_state); + if ( written > 0 ) + { + bootloader_dfu_activity_mark(); + } + else if ( written == 0 ) + { + break; + } lba++; buffer += 512; @@ -171,6 +181,7 @@ void tud_msc_write10_complete_cb(uint8_t lun) dfu_update_status_t update_status; memset(&update_status, 0, sizeof(dfu_update_status_t )); update_status.status_code = DFU_RESET; + update_status.restart_into_bootloader = false; bootloader_dfu_update_process(update_status); @@ -195,9 +206,10 @@ void tud_msc_write10_complete_cb(uint8_t lun) { // update bootloader always end with reset update_status.status_code = DFU_RESET; + update_status.restart_into_bootloader = false; // Location of current stored new bootloader - uint32_t * new_bootloader = (uint32_t *) BOOTLOADER_ADDR_NEW_RECIEVED; + uint32_t * new_bootloader = (uint32_t *) BOOTLOADER_ADDR_NEW_RECEIVED; PRINT_HEX(new_bootloader); diff --git a/src/usb/tusb_config.h b/src/usb/tusb_config.h index b76c87b66..e75a63da4 100644 --- a/src/usb/tusb_config.h +++ b/src/usb/tusb_config.h @@ -53,7 +53,9 @@ //------------- Class enabled -------------// #define CFG_TUD_CDC 1 +#if !defined(SIGNED_FW) || defined(FORCE_UF2) #define CFG_TUD_MSC 1 +#endif /*------------------------------------------------------------------*/ /* CLASS DRIVER diff --git a/src/usb/uf2/uf2cfg.h b/src/usb/uf2/uf2cfg.h index e5a63988c..c23a12ef6 100644 --- a/src/usb/uf2/uf2cfg.h +++ b/src/usb/uf2/uf2cfg.h @@ -32,4 +32,4 @@ #define BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS // Address where new bootloader is written before activation (skip application data) -#define BOOTLOADER_ADDR_NEW_RECIEVED (USER_FLASH_END-DFU_BL_IMAGE_MAX_SIZE) +#define BOOTLOADER_ADDR_NEW_RECEIVED (USER_FLASH_END-DFU_BL_IMAGE_MAX_SIZE) diff --git a/src/usb/usb.c b/src/usb/usb.c index 30d91c0d4..b89e9e965 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -33,6 +33,7 @@ #include "uf2/uf2.h" #include "boards.h" +#include "bootloader.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -94,7 +95,9 @@ void usb_init(bool cdc_only) { } usb_desc_init(cdc_only); +#if CFG_TUD_MSC uf2_init(); +#endif tusb_init(); #ifdef DISPLAY_PIN_SCK @@ -113,6 +116,7 @@ void usb_teardown(void) { //--------------------------------------------------------------------+ void tud_mount_cb(void) { led_state(STATE_USB_MOUNTED); + bootloader_mark_usb_mounted(); } void tud_umount_cb(void) { diff --git a/src/usb/usb_desc.c b/src/usb/usb_desc.c index ac1a8acde..4db68ec7b 100644 --- a/src/usb/usb_desc.c +++ b/src/usb/usb_desc.c @@ -33,8 +33,10 @@ enum { STRID_MSC }; +#if !defined(SIGNED_FW) || defined(FORCE_UF2) // CDC + MSC or CDC only mode static bool _cdc_only = false; +#endif // Serial is 64-bit DeviceID -> 16 chars len static char desc_str_serial[1+16]; @@ -84,6 +86,7 @@ enum { ITF_NUM_TOTAL }; +#if CFG_TUD_MSC uint8_t desc_configuration_cdc_msc[] = { // Interface count, string index, total length, attribute, power in mA @@ -95,6 +98,7 @@ uint8_t desc_configuration_cdc_msc[] = // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, STRID_MSC, 0x03, 0x83, 64), }; +#endif uint8_t desc_configuration_cdc_only[] = { @@ -112,15 +116,22 @@ uint8_t desc_configuration_cdc_only[] = uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations +#if CFG_TUD_MSC return _cdc_only ? desc_configuration_cdc_only : desc_configuration_cdc_msc; +#else + return desc_configuration_cdc_only; +#endif } // Enumerate as CDC + MSC or CDC only void usb_desc_init(bool cdc_only) { - _cdc_only = cdc_only; + (void)cdc_only; // for non MSC build +#if CFG_TUD_MSC + _cdc_only = cdc_only; if ( cdc_only ) +#endif { // Change PID to CDC only desc_device.idProduct = USB_DESC_CDC_ONLY_PID; @@ -154,7 +165,9 @@ char const* string_desc_arr [] = BLEDIS_MODEL, // 2: Product desc_str_serial, // 3: Serials, should use chip ID "nRF Serial", // 4: CDC Interface +#if CFG_TUD_MSC "nRF UF2", // 5: MSC Interface +#endif }; // up to 64 unicode characters diff --git a/supported_boards.md b/supported_boards.md new file mode 100644 index 000000000..61399d0da --- /dev/null +++ b/supported_boards.md @@ -0,0 +1,28 @@ +# Supported Boards + +## Adafruit Boards + +| Board | Name | VID PID | URL | +| --- | --- | --- | --- | + +## 3rd Party Boards + +| Board | Name | VID PID | URL | +| --- | --- | --- | --- | +| heltec_t096 | Heltec-T096 | 0x239A:0x0071 | http://heltec.org/ | +| heltec_t1 | Heltec-T1 | 0x239A:0x0071 | http://heltec.org/ | +| heltec_t114 | HT-n5262 | 0x239A:0x0071 | HT-n5262 | +| lilygo_techo | LilyGo T-Echo | 0x239A:0x0029 | https://lilygo.cc/products/t-echo-lilygo | +| minewsemi_mx25le01 | MinewSemi MX25LE01 | 0x239A:0x0029 | https://www.minewsemi.com | +| promicro_nrf52840 | ProMicro NRF52840 | 0x239A:0x00B3 | https://www.nologo.tech/product/otherboard/NRF52840.html | +| sensecap_solar_p1 | Seeed Solar Node P1 | 0x2886:0x0044 | https://www.seeedstudio.com/ | +| t1000_e | Seeed T1000-E for Meshtastic | 0x2886:0x0057 | https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html | +| thinknode_m1 | ELECROW ThinkNodeM1 | 0x239A:0x00DA | https://www.elecrow.com | +| thinknode_m3 | ELECROW ThinkNode-M3 | 0x239A:0x00DA | https://www.elecrow.com | +| thinknode_m6 | ELECROW ThinkNodeM6 | 0x239A:0x00DA | https://www.elecrow.com | +| wio_tracker_l1 | Seeed TRACKER L1 | 0x2886:0x1667 | https://www.seeedstudio.com/ | +| wiscore_rak3401 | WisBlock RAK3401 Board | 0x239A:0x0029 | https://store.rakwireless.com/collections/wisblock-core | +| wiscore_rak4631_board | WisBlock RAK4631 Board | 0x239A:0x0029 | https://store.rakwireless.com/collections/wisblock-core | +| wismesh_tag | WisMesh Tag | 0x239A:0x0029 | https://store.rakwireless.com/products/wismesh-tag-meshtastic-gps-lora-tracker-ip66 | +| xiao_nrf52840_ble | Seeed XIAO nRF52840 | 0x2886:0x0044 | https://www.seeedstudio.com/ | +| xiao_nrf52840_ble_sense | Seeed XIAO nRF52840 | 0x2886:0x0045 | https://www.seeedstudio.com/ | diff --git a/tools/gen_boards.py b/tools/gen_boards.py new file mode 100644 index 000000000..140a0dd46 --- /dev/null +++ b/tools/gen_boards.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import re +from pathlib import Path + + +BOARD_H_GLOB = "src/boards/*/board.h" + + +def _first_match(pattern: str, text: str) -> str | None: + match = re.search(pattern, text, flags=re.MULTILINE) + return match.group(1).strip() if match else None + + +def _parse_int(value: str | None) -> int | None: + if value is None: + return None + value = value.strip() + if value.lower().startswith("0x"): + try: + return int(value, 16) + except ValueError: + return None + try: + return int(value, 10) + except ValueError: + return None + + +def _fmt_vid_pid(vid: int | None, pid: int | None) -> str: + if vid is None or pid is None: + return "N/A" + return f"0x{vid:04X}:0x{pid:04X}" + + +def _escape_md(value: str) -> str: + return value.replace("|", "\\|") + + +def _load_board(board_h: Path, repo_root: Path) -> dict[str, str]: + text = board_h.read_text(errors="ignore") + board = board_h.parent.name + name = _first_match(r'^\s*#define\s+UF2_PRODUCT_NAME\s+"([^"]+)"', text) + url = _first_match(r'^\s*#define\s+UF2_INDEX_URL\s+"([^"]+)"', text) + vid = _parse_int(_first_match(r"^\s*#define\s+USB_DESC_VID\s+([0-9A-Fa-fxX]+)", text)) + pid = _parse_int( + _first_match(r"^\s*#define\s+USB_DESC_UF2_PID\s+([0-9A-Fa-fxX]+)", text) + ) + + return { + "board": board, + "name": name or "N/A", + "vid_pid": _fmt_vid_pid(vid, pid), + "url": url or "N/A", + } + + +def generate(repo_root: Path, output: Path) -> None: + boards: list[dict[str, str]] = [] + for board_h in sorted(repo_root.glob(BOARD_H_GLOB)): + boards.append(_load_board(board_h, repo_root)) + + lines: list[str] = [] + lines.append("# Supported Boards") + lines.append("") + def _is_adafruit(entry: dict[str, str]) -> bool: + name = entry["name"].lower() + board = entry["board"].lower() + return name.startswith("adafruit") or board.startswith("adafruit") + + def _render_table(entries: list[dict[str, str]]) -> None: + lines.append("| Board | Name | VID PID | URL |") + lines.append("| --- | --- | --- | --- |") + for entry in sorted(entries, key=lambda e: e["board"].lower()): + lines.append( + f"| {_escape_md(entry['board'])} | {_escape_md(entry['name'])} | " + f"{_escape_md(entry['vid_pid'])} | {_escape_md(entry['url'])} |" + ) + lines.append("") + + adafruit = [entry for entry in boards if _is_adafruit(entry)] + third_party = [entry for entry in boards if not _is_adafruit(entry)] + + lines.append("## Adafruit Boards") + lines.append("") + _render_table(adafruit) + + lines.append("## 3rd Party Boards") + lines.append("") + _render_table(third_party) + + output.write_text("\n".join(lines)) + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Generate supported_boards.md from src/boards/*/board.h" + ) + parser.add_argument( + "--output", + default="supported_boards.md", + help="Output markdown file (default: supported_boards.md)", + ) + args = parser.parse_args() + + repo_root = Path(__file__).resolve().parents[1] + output = Path(args.output) + if not output.is_absolute(): + output = repo_root / output + + generate(repo_root, output) + + +if __name__ == "__main__": + main()