diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCITransportDriver.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCITransportDriver.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/README.md similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/README.md diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/libcordio_stack_nordic.a b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/libcordio_stack_nordic.a similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/libcordio_stack_nordic.a rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/libcordio_stack_nordic.a diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/mbed_lib.json similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/mbed_lib.json diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/CHANGELOG.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/CHANGELOG.md similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/CHANGELOG.md rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/CHANGELOG.md diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/LICENSE b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/LICENSE similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/LICENSE rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/LICENSE diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/apache-2.0.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/apache-2.0.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/apache-2.0.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/apache-2.0.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/s110_nrf51822_8.0.0_bootloader.hex b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/s110_nrf51822_8.0.0_bootloader.hex similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/s110_nrf51822_8.0.0_bootloader.hex rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/s110_nrf51822_8.0.0_bootloader.hex diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/s130_nrf51_1.0.0_bootloader.hex b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/s130_nrf51_1.0.0_bootloader.hex similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/s130_nrf51_1.0.0_bootloader.hex rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/s130_nrf51_1.0.0_bootloader.hex diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/softdevice_nrf51822_licence_agreement.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/softdevice_nrf51822_licence_agreement.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/bootloader/softdevice_nrf51822_licence_agreement.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/bootloader/softdevice_nrf51822_licence_agreement.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/hal_patch/critical_section_api.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/hal_patch/critical_section_api.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/hal_patch/critical_section_api.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/hal_patch/critical_section_api.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/hal_patch/sleep.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/hal_patch/sleep.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/hal_patch/sleep.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/hal_patch/sleep.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/module.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/module.json similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/module.json rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/module.json diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/BSD-3clause-Nordic.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/BSD-3clause-Nordic.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/BSD-3clause-Nordic.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/BSD-3clause-Nordic.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/CHANGELOG.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/CHANGELOG.md similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/CHANGELOG.md rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/CHANGELOG.md diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/LICENSE b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/LICENSE similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/LICENSE rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/LICENSE diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/README.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/README.md similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/README.md rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/README.md diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/apache-2.0.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/apache-2.0.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/apache-2.0.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/apache-2.0.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/module.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/module.json similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/module.json rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/module.json diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/copyright_header.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/copyright_header.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/copyright_header.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/copyright_header.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/pick_nrf51_files.py b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/pick_nrf51_files.py similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/pick_nrf51_files.py rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/pick_nrf51_files.py diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/replace_headers.py b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/replace_headers.py similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/replace_headers.py rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/replace_headers.py diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/required_files.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/required_files.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/script/required_files.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/script/required_files.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_radio_notification/ble_radio_notification.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/ble_services/ble_dfu/ble_dfu.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_advdata.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_params.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_conn_state.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_date_time.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_date_time.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_date_time.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_date_time.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_gatt_db.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_gatt_db.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_gatt_db.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_gatt_db.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_sensor_location.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_sensor_location.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_sensor_location.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_sensor_location.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/common/ble_srv_common.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/config/device_manager_cnfg.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/config/device_manager_cnfg.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/config/device_manager_cnfg.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/config/device_manager_cnfg.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager_peripheral.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager_peripheral.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager_peripheral.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager_peripheral.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/id_manager.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_data_storage.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_database.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_id.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_manager_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_manager_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_manager_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/peer_manager_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_buffer.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/ble/peer_manager/pm_mutex.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/compiler_abstraction.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/compiler_abstraction.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/compiler_abstraction.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/compiler_abstraction.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51_bitfields.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51_bitfields.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51_bitfields.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51_bitfields.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51_deprecated.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51_deprecated.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/device/nrf51_deprecated.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/device/nrf51_deprecated.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/ble_flash/ble_flash.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/delay/nrf_delay.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_ecb.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpio.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpio.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpio.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpio.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpiote.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpiote.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpiote.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_gpiote.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_nvmc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_temp.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_temp.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_temp.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_temp.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_wdt.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_wdt.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_wdt.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/hal/nrf_wdt.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/config/pstorage_platform.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/config/pstorage_platform.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/config/pstorage_platform.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/config/pstorage_platform.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/drivers_nrf/pstorage/pstorage.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/bootloader_util.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_app_handler.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_bank_internal.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_bank_internal.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_bank_internal.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_bank_internal.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc_internal.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc_internal.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc_internal.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_ble_svc_internal.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init_template.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init_template.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init_template.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_init_template.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_transport.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_transport.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_transport.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_transport.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/dfu_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/hci_transport/hci_mem_pool_internal.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/hci_transport/hci_mem_pool_internal.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/hci_transport/hci_mem_pool_internal.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/bootloader_dfu/hci_transport/hci_mem_pool_internal.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/crc16/crc16.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/experimental_section_vars/section_vars.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/experimental_section_vars/section_vars.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/experimental_section_vars/section_vars.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/experimental_section_vars/section_vars.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_config.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_config.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_config.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_config.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_types_internal.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_types_internal.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_types_internal.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fds/fds_types_internal.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_config.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_config.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_config.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_config.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_nosd.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_nosd.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_nosd.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/fstorage/fstorage_nosd.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/hci/hci_mem_pool.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/scheduler/app_scheduler.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/timer/app_timer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/timer/app_timer.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/timer/app_timer.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/timer/app_timer.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_error.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/app_util_platform.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/common.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/common.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/common.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nordic_common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nordic_common.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nordic_common.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nordic_common.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/nrf_assert.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_common.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_common.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_common.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_errors.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_errors.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_errors.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_errors.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_mapped_flags.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_os.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_os.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_os.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/libraries/util/sdk_os.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/prevent_bootloader_frame_pointer.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/prevent_bootloader_frame_pointer.cmake similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/prevent_bootloader_frame_pointer.cmake rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/prevent_bootloader_frame_pointer.cmake diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ant_stack_handler_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ant_stack_handler_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ant_stack_handler_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ant_stack_handler_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ble_stack_handler_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ble_stack_handler_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ble_stack_handler_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/ble_stack_handler_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.c b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.c similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.c rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.c diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/common/softdevice_handler/softdevice_handler_appsh.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_err.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_err.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_err.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_err.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gap.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gap.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gap.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatt.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatt.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatt.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatt.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gattc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gattc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gattc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gattc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatts.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatts.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatts.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_gatts.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_hci.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_hci.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_hci.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_hci.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_l2cap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_l2cap.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_l2cap.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_l2cap.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_ranges.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_ranges.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_ranges.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_ranges.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_types.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_types.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_types.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/ble_types.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_ble.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_ble.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_ble.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_ble.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_sdm.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_sdm.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_sdm.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_sdm.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_soc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_soc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_soc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_error_soc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_mbr.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_mbr.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_mbr.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_mbr.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_sdm.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_sdm.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_sdm.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_sdm.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_soc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_soc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_soc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_soc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_svc.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_svc.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_svc.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/nrf_svc.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/softdevice_assert.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/softdevice_assert.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/softdevice_assert.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/softdevice/s130/headers/softdevice_assert.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/supress-warnings.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/supress-warnings.cmake similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/supress-warnings.cmake rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/supress-warnings.cmake diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/toolchain/system_nrf51.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/toolchain/system_nrf51.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sdk/source/toolchain/system_nrf51.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/sdk/source/toolchain/system_nrf51.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/softdevice_nrf51822_licence_agreement.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/softdevice_nrf51822_licence_agreement.txt similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/softdevice_nrf51822_licence_agreement.txt rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/softdevice_nrf51822_licence_agreement.txt diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_advertising.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_advertising.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_advertising.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_advertising.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_advertising.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_advertising.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_advertising.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_advertising.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_discovery.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_discovery.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_discovery.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_discovery.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_discovery.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_discovery.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_discovery.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_discovery.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_gap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_gap.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_gap.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_gap.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_gap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_gap.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_gap.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_gap.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_security.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_security.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_security.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_security.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_security.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_security.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/btle_security.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/btle_security.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/btle/custom/custom_helper.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/ansi_escape.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/ansi_escape.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/ansi_escape.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/ansi_escape.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/assertion.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/assertion.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/assertion.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/assertion.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/binary.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/binary.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/binary.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/binary.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/ble_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/ble_error.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/ble_error.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/ble_error.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/common.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/common.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/common.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/compiler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/compiler.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/common/compiler.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/common/compiler.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xCharacteristicDescriptorDiscoverer.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xDiscoveredCharacteristic.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGap.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGap.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGap.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGap.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGap.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGap.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattClient.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattClient.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattClient.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattClient.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattClient.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattClient.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattClient.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattClient.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattServer.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattServer.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattServer.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattServer.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattServer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattServer.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xGattServer.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xGattServer.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xSecurityManager.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xSecurityManager.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xSecurityManager.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xServiceDiscovery.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xn.cpp similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xn.cpp rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xn.cpp diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xn.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xn.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/nRF5xn.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/projectconfig.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/projectconfig.h similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/projectconfig.h rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/projectconfig.h diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/supress-warnings.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/supress-warnings.cmake similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/supress-warnings.cmake rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_MCU_NRF51822/source/supress-warnings.cmake diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/CHANGELOG.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/CHANGELOG.md new file mode 100644 index 0000000000..bb4dad9a4a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/CHANGELOG.md @@ -0,0 +1,344 @@ +# Change Log + +## [v2.5.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.3) (2016-02-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.2...v2.5.3) + +**Merged pull requests:** + +- Fix for compilation errors with S110 softdevice in btle.cpp [\#109](https://github.com/ARMmbed/ble-nrf51822/pull/109) ([ddavidebor](https://github.com/ddavidebor)) + +## [v2.5.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.2) (2016-02-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.1...v2.5.2) + +**Merged pull requests:** + +- Sync develop against master [\#113](https://github.com/ARMmbed/ble-nrf51822/pull/113) ([pan-](https://github.com/pan-)) +- Fix incorrect handles of characteristics descriptors. [\#112](https://github.com/ARMmbed/ble-nrf51822/pull/112) ([pan-](https://github.com/pan-)) + +## [v2.5.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.1) (2016-01-27) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.0...v2.5.1) + +**Merged pull requests:** + +- Remove Gap::state updates from this module [\#108](https://github.com/ARMmbed/ble-nrf51822/pull/108) ([andresag01](https://github.com/andresag01)) +- merge version [\#106](https://github.com/ARMmbed/ble-nrf51822/pull/106) ([pan-](https://github.com/pan-)) + +## [v2.5.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.0) (2016-01-12) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.1...v2.5.0) + +**Merged pull requests:** + +- Fix access to enum member [\#105](https://github.com/ARMmbed/ble-nrf51822/pull/105) ([pan-](https://github.com/pan-)) +- Hotfix dependency [\#104](https://github.com/ARMmbed/ble-nrf51822/pull/104) ([pan-](https://github.com/pan-)) +- Finish implementation of getAddressesFromBondTable [\#103](https://github.com/ARMmbed/ble-nrf51822/pull/103) ([andresag01](https://github.com/andresag01)) + +## [v2.4.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.1) (2016-01-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.0...v2.4.1) + +**Merged pull requests:** + +- merge branch develop \(v2.4.0\) [\#100](https://github.com/ARMmbed/ble-nrf51822/pull/100) ([pan-](https://github.com/pan-)) + +## [v2.4.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.0) (2016-01-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.1...v2.4.0) + +**Merged pull requests:** + +- Add implementation of experimental whitelisting API [\#99](https://github.com/ARMmbed/ble-nrf51822/pull/99) ([andresag01](https://github.com/andresag01)) + +## [v2.3.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.1) (2016-01-07) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.0...v2.3.1) + +**Merged pull requests:** + +- Update yotta module dependencies [\#98](https://github.com/ARMmbed/ble-nrf51822/pull/98) ([pan-](https://github.com/pan-)) + +## [v2.3.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.0) (2015-12-23) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.10...v2.3.0) + +**Merged pull requests:** + +- Implementation of Characteristic descriptor discovery [\#74](https://github.com/ARMmbed/ble-nrf51822/pull/74) ([pan-](https://github.com/pan-)) + +## [v2.2.10](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.10) (2015-12-23) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.9...v2.2.10) + +**Fixed bugs:** + +- nRF5xn::init don't verify if errors have occurred during btle\_init [\#59](https://github.com/ARMmbed/ble-nrf51822/issues/59) + +**Closed issues:** + +- A call to shutdown does not clear the state of some components of BLE API [\#85](https://github.com/ARMmbed/ble-nrf51822/issues/85) +- Memory allocation issue on the NRF51DK board. [\#76](https://github.com/ARMmbed/ble-nrf51822/issues/76) +- Terrible handling of initLen / minLen and variable length characteristics. [\#56](https://github.com/ARMmbed/ble-nrf51822/issues/56) + +**Merged pull requests:** + +- Fix shutdown of Gap instance to avoid NULL refs [\#96](https://github.com/ARMmbed/ble-nrf51822/pull/96) ([andresag01](https://github.com/andresag01)) +- Add check for return code of ble\_init [\#95](https://github.com/ARMmbed/ble-nrf51822/pull/95) ([andresag01](https://github.com/andresag01)) + +## [v2.2.9](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.9) (2015-12-18) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.8...v2.2.9) + +**Closed issues:** + +- Cannot open source input file "system\_nrf51.h" [\#52](https://github.com/ARMmbed/ble-nrf51822/issues/52) + +**Merged pull requests:** + +- Remove occurrence of deprecated appearance enum [\#92](https://github.com/ARMmbed/ble-nrf51822/pull/92) ([andresag01](https://github.com/andresag01)) + +## [v2.2.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.8) (2015-12-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.7...v2.2.8) + +## [v2.2.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.7) (2015-12-15) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.6...v2.2.7) + +**Merged pull requests:** + +- Replace deprecated inclusions of mbed.h [\#89](https://github.com/ARMmbed/ble-nrf51822/pull/89) ([andresag01](https://github.com/andresag01)) +- Improve shutdown to clear BLE API and not just SD [\#87](https://github.com/ARMmbed/ble-nrf51822/pull/87) ([andresag01](https://github.com/andresag01)) + +## [v2.2.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.6) (2015-12-15) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.5...v2.2.6) + +**Merged pull requests:** + +- follow the extraction of address related types from Gap.h into BLEProtocol.h [\#88](https://github.com/ARMmbed/ble-nrf51822/pull/88) ([rgrover](https://github.com/rgrover)) + +## [v2.2.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.5) (2015-12-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.3...v2.2.5) + +**Merged pull requests:** + +- Added SecurityManager::setLinkSecurity call for elevating security settings on a particular connection. [\#86](https://github.com/ARMmbed/ble-nrf51822/pull/86) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.2.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.3) (2015-12-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.2...v2.2.3) + +## [v2.2.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.2) (2015-12-08) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.1...v2.2.2) + +**Merged pull requests:** + +- Add -Wno-unused-function to supress-warnings.cmake [\#83](https://github.com/ARMmbed/ble-nrf51822/pull/83) ([andresag01](https://github.com/andresag01)) + +## [v2.2.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.1) (2015-12-08) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.0...v2.2.1) + +**Merged pull requests:** + +- WIP: UUID endian change [\#82](https://github.com/ARMmbed/ble-nrf51822/pull/82) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.2.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.0) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.4...v2.2.0) + +## [v2.1.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.4) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.3...v2.1.4) + +## [v2.1.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.3) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.2...v2.1.3) + +## [v2.1.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.2) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.1...v2.1.2) + +**Merged pull requests:** + +- Allow GattAttributes to have variable length [\#81](https://github.com/ARMmbed/ble-nrf51822/pull/81) ([andresag01](https://github.com/andresag01)) + +## [v2.1.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.1) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.0...v2.1.1) + +**Merged pull requests:** + +- Fixed endianness bug in nRF5xServiceDiscovery::processDiscoverUUIDResponse so it is consistent with BLE API. [\#80](https://github.com/ARMmbed/ble-nrf51822/pull/80) ([marcuschangarm](https://github.com/marcuschangarm)) +- Fixed bug in nRF5xGap.setAddress where random adresses where not set properly. [\#79](https://github.com/ARMmbed/ble-nrf51822/pull/79) ([marcuschangarm](https://github.com/marcuschangarm)) +- Separate concept of minlen and len for BLE chars [\#78](https://github.com/ARMmbed/ble-nrf51822/pull/78) ([andresag01](https://github.com/andresag01)) +- Split nordic sdk into its own module [\#75](https://github.com/ARMmbed/ble-nrf51822/pull/75) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.0) (2015-11-27) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.8...v2.1.0) + +**Merged pull requests:** + +- Update to sdk 8.1 [\#77](https://github.com/ARMmbed/ble-nrf51822/pull/77) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.0.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.8) (2015-11-26) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.7...v2.0.8) + +## [v2.0.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.7) (2015-11-26) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.6...v2.0.7) + +**Closed issues:** + +- test2000 [\#72](https://github.com/ARMmbed/ble-nrf51822/issues/72) +- test1000000 [\#71](https://github.com/ARMmbed/ble-nrf51822/issues/71) +- test4 [\#70](https://github.com/ARMmbed/ble-nrf51822/issues/70) +- test3 [\#69](https://github.com/ARMmbed/ble-nrf51822/issues/69) +- test2 [\#68](https://github.com/ARMmbed/ble-nrf51822/issues/68) + +**Merged pull requests:** + +- use Extern c around \#include to use nordic sdk headers implemented in C [\#73](https://github.com/ARMmbed/ble-nrf51822/pull/73) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.0.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.6) (2015-11-17) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.5...v2.0.6) + +**Closed issues:** + +- test [\#66](https://github.com/ARMmbed/ble-nrf51822/issues/66) + +**Merged pull requests:** + +- add Nordic's license agreement. [\#67](https://github.com/ARMmbed/ble-nrf51822/pull/67) ([rgrover](https://github.com/rgrover)) + +## [v2.0.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.5) (2015-11-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.4...v2.0.5) + +**Merged pull requests:** + +- Post radio notification callback through minar [\#65](https://github.com/ARMmbed/ble-nrf51822/pull/65) ([andresag01](https://github.com/andresag01)) + +## [v2.0.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.4) (2015-11-13) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.3...v2.0.4) + +**Merged pull requests:** + +- Fix assembly sequence to start bootloader in GCC [\#64](https://github.com/ARMmbed/ble-nrf51822/pull/64) ([andresag01](https://github.com/andresag01)) + +## [v2.0.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.3) (2015-11-09) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.2...v2.0.3) + +**Merged pull requests:** + +- Added watchdog header file from Nordic SDK 8.1 [\#62](https://github.com/ARMmbed/ble-nrf51822/pull/62) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.0.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.2) (2015-11-03) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-release-15-11...v2.0.2) + +## [mbedos-release-15-11](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-release-15-11) (2015-11-03) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.1...mbedos-release-15-11) + +## [v2.0.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.1) (2015-11-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.0...v2.0.1) + +**Merged pull requests:** + +- Ensure that the initialization flags is set to false if the BLE stack is shutdown properly. [\#58](https://github.com/ARMmbed/ble-nrf51822/pull/58) ([pan-](https://github.com/pan-)) + +## [v2.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.0) (2015-11-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.1.0...v2.0.0) + +**Closed issues:** + +- Nordic SDK and SoftDevice [\#57](https://github.com/ARMmbed/ble-nrf51822/issues/57) +- shouldn't eab6631cb be merged into master? [\#54](https://github.com/ARMmbed/ble-nrf51822/issues/54) + +**Merged pull requests:** + +- Introduced changes for memory savings [\#55](https://github.com/ARMmbed/ble-nrf51822/pull/55) ([andresag01](https://github.com/andresag01)) + +## [v1.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.1.0) (2015-10-28) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.0.0...v1.1.0) + +**Closed issues:** + +- target dependencies in module.json [\#50](https://github.com/ARMmbed/ble-nrf51822/issues/50) + +**Merged pull requests:** + +- When connecting, if no scanning parameters are passed, use values from Gap parent. [\#53](https://github.com/ARMmbed/ble-nrf51822/pull/53) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v1.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.0.0) (2015-10-19) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-techcon-oob2...v1.0.0) + +## [mbedos-techcon-oob2](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-techcon-oob2) (2015-10-19) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.8...mbedos-techcon-oob2) + +**Closed issues:** + +- rename the bootloader files with \_fota in the name? [\#51](https://github.com/ARMmbed/ble-nrf51822/issues/51) + +**Merged pull requests:** + +- Update S110 detection macros, again [\#49](https://github.com/ARMmbed/ble-nrf51822/pull/49) ([jpbrucker](https://github.com/jpbrucker)) +- Error check number of characteristics [\#48](https://github.com/ARMmbed/ble-nrf51822/pull/48) ([Timmmm](https://github.com/Timmmm)) + +## [v0.4.8](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.8) (2015-09-25) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.7...v0.4.8) + +**Closed issues:** + +- Error real cause loss in nRF5xGattServer.cpp [\#44](https://github.com/ARMmbed/ble-nrf51822/issues/44) + +**Merged pull requests:** + +- rgrover patch fixed [\#47](https://github.com/ARMmbed/ble-nrf51822/pull/47) ([fabiencomte](https://github.com/fabiencomte)) +- Update S110 detection macros [\#43](https://github.com/ARMmbed/ble-nrf51822/pull/43) ([jpbrucker](https://github.com/jpbrucker)) +- remove some unnecessary include paths [\#42](https://github.com/ARMmbed/ble-nrf51822/pull/42) ([autopulated](https://github.com/autopulated)) +- Add FOTA bootloader image [\#41](https://github.com/ARMmbed/ble-nrf51822/pull/41) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.7](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.7) (2015-08-13) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.6...v0.4.7) + +## [v0.4.6](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.6) (2015-08-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.5...v0.4.6) + +**Closed issues:** + +- remove duplication of global static variable BLE\_EVT\_BUFFER [\#39](https://github.com/ARMmbed/ble-nrf51822/issues/39) +- clearScanResponse\(\) [\#30](https://github.com/ARMmbed/ble-nrf51822/issues/30) +- Debug builds fail due to missing bsp.h [\#11](https://github.com/ARMmbed/ble-nrf51822/issues/11) + +**Merged pull requests:** + +- Disable GattClient features when using S110 SoftDevice [\#38](https://github.com/ARMmbed/ble-nrf51822/pull/38) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.5](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.5) (2015-08-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.4...v0.4.5) + +## [v0.4.4](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.4) (2015-08-07) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.3...v0.4.4) + +**Closed issues:** + +- nrf51822 hangs after calling sd\_flash\_page\_erase\(\) [\#35](https://github.com/ARMmbed/ble-nrf51822/issues/35) +- nRF5xn::getVersion return \(Unknown\) with version 8 soft device [\#29](https://github.com/ARMmbed/ble-nrf51822/issues/29) + +**Merged pull requests:** + +- Changed Gap:: to GapAdvertisingParams:: because of change in BLE [\#34](https://github.com/ARMmbed/ble-nrf51822/pull/34) ([jslater8](https://github.com/jslater8)) +- Select the clock source dynamically on SoftDevice initialisation [\#32](https://github.com/ARMmbed/ble-nrf51822/pull/32) ([jpbrucker](https://github.com/jpbrucker)) +- Add S110 SoftDevice compatibility [\#28](https://github.com/ARMmbed/ble-nrf51822/pull/28) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.3](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.3) (2015-07-22) +**Closed issues:** + +- Target polling failed [\#24](https://github.com/ARMmbed/ble-nrf51822/issues/24) +- support handling of HVX Events \(notifications and indications\). [\#22](https://github.com/ARMmbed/ble-nrf51822/issues/22) +- provide an implementation for GattServer::areUpdatesEnabled\(\) [\#21](https://github.com/ARMmbed/ble-nrf51822/issues/21) +- getValueHandle\(\) returns characteristicIndex instead of attribute-handle [\#20](https://github.com/ARMmbed/ble-nrf51822/issues/20) +- Clash With Definition And Enum Naming [\#16](https://github.com/ARMmbed/ble-nrf51822/issues/16) +- Errors in GCC build [\#14](https://github.com/ARMmbed/ble-nrf51822/issues/14) +- bring s110 support back [\#10](https://github.com/ARMmbed/ble-nrf51822/issues/10) +- Allow adding a User Description descriptor to a GattCharacteristic. [\#9](https://github.com/ARMmbed/ble-nrf51822/issues/9) +- device\_manager\_peripheral.c includes app\_trace.h [\#7](https://github.com/ARMmbed/ble-nrf51822/issues/7) +- linking esb\_gcc.a \(nrf51822 enhanced shock burst\) with mbed [\#5](https://github.com/ARMmbed/ble-nrf51822/issues/5) +- The app\_timer usage may conflict [\#2](https://github.com/ARMmbed/ble-nrf51822/issues/2) +- Nordic License [\#1](https://github.com/ARMmbed/ble-nrf51822/issues/1) + +**Merged pull requests:** + +- Develop [\#25](https://github.com/ARMmbed/ble-nrf51822/pull/25) ([zoujixing](https://github.com/zoujixing)) +- Remove unnecessary 'compiler\_abstraction.h' to get rid of duplicate '… [\#23](https://github.com/ARMmbed/ble-nrf51822/pull/23) ([adfernandes](https://github.com/adfernandes)) +- restructure for minimal yotta compatibility [\#15](https://github.com/ARMmbed/ble-nrf51822/pull/15) ([autopulated](https://github.com/autopulated)) +- Fix various GCC compilation issues. [\#12](https://github.com/ARMmbed/ble-nrf51822/pull/12) ([adfernandes](https://github.com/adfernandes)) +- Fix for GCC lost in SDK v8.0 update [\#8](https://github.com/ARMmbed/ble-nrf51822/pull/8) ([rosterloh](https://github.com/rosterloh)) +- new target DELTA\_DFCM\_NNN40 with nrf51822 chip, config internal RC crystal. [\#6](https://github.com/ARMmbed/ble-nrf51822/pull/6) ([Marcomissyou](https://github.com/Marcomissyou)) +- Updated return value for nRF51GattServer::updateValue. Will now report w... [\#4](https://github.com/ARMmbed/ble-nrf51822/pull/4) ([marcuschangarm](https://github.com/marcuschangarm)) +- Added optional data and length fields to the return struct for authorize... [\#3](https://github.com/ARMmbed/ble-nrf51822/pull/3) ([marcuschangarm](https://github.com/marcuschangarm)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/LICENSE b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/LICENSE new file mode 100644 index 0000000000..60744edab2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/LICENSE @@ -0,0 +1,6 @@ +This module contains softdevice which comes with The Nordic Softdevice License Agreement, +a BSD-like licence for binary distributions, offered by Nordic for use in mbed. Some +other files come from the mbed SDK, and are licensed under Apache-2.0. Unless +specifically indicated otherwise in a file, files are licensed under the +Apache 2.0 license, as can be found in: apache-2.0.txt. The Nordic Semiconductor Softdevice +License Agreement can be found in softdevice_nrf51822_licence_agreement.txt. diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/apache-2.0.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/apache-2.0.txt new file mode 100644 index 0000000000..9327527edd --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/apache-2.0.txt @@ -0,0 +1,13 @@ +Copyright (c) 2015 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/module.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/module.json new file mode 100644 index 0000000000..b45b894f0e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/module.json @@ -0,0 +1,36 @@ +{ + "name": "ble-nrf51822", + "version": "2.7.1", + "description": "Nordic stack and drivers for the mbed BLE API.", + "keywords": [ + "Bluetooth", + "BLE", + "mbed", + "mbed-official" + ], + "author": "Rohit Grover", + "repository": { + "url": "git@github.com:ARMmbed/ble-nRF51822.git", + "type": "git" + }, + "homepage": "https://developer.mbed.org/teams/Nordic-Semiconductor/", + "licenses": [ + { + "url": "https://spdx.org/licenses/Apache-2.0", + "type": "Apache-2.0" + }, + { + "type": "LicenseRef-softdevice_nrf51822_licence_agreement.txt" + } + ], + "dependencies": { + "ble": "^2.6.0", + "nrf51-sdk": "^2.4.0" + }, + "extraIncludes": [ + "source/btle", + "source/btle/custom", + "source/common" + ], + "targetDependencies": {} +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/softdevice_nrf51822_licence_agreement.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/softdevice_nrf51822_licence_agreement.txt new file mode 100644 index 0000000000..8e447f4c64 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/softdevice_nrf51822_licence_agreement.txt @@ -0,0 +1,30 @@ +/* + * S110/S120/S130 License Agreement + * + * Copyright (c) 2015, Nordic Semiconductor ASA, All rights reserved. + * + * Redistribution. Redistribution and use in binary form, without modification, + * are permitted provided that the following conditions are met: + * + * • Redistributions must reproduce the above copyright notice and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * • Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * • No reverse engineering, decompilation, or disassembly of this software is + * permitted. + * + * DISCLAIMER. + * 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * / diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.cpp new file mode 100644 index 0000000000..764c79781a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.cpp @@ -0,0 +1,266 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common/common.h" +#include "nordic_common.h" + +#include "btle.h" +#include "btle_clock.h" + +#include "ble_flash.h" +#include "ble_conn_params.h" + +#include "btle_gap.h" +#include "custom/custom_helper.h" + +#include "ble/GapEvents.h" +#include "nRF5xn.h" + +#ifdef S110 + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 1 +#elif defined(S130) || defined(S132) + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 0 +#endif + +extern "C" { +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + #include "pstorage.h" +#else + #include "fstorage.h" + #include "fds.h" + #include "ble_conn_state.h" +#endif + +#include "softdevice_handler.h" +#include "ble_stack_handler_types.h" +} + +#include "nrf_ble_hci.h" + +#include "nRF5xPalGattClient.h" +#include "nRF5xPalSecurityManager.h" + + +bool isEventsSignaled = false; + +extern "C" void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name); +void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name); +extern "C" void SD_EVT_IRQHandler(void); // export the softdevice event handler for registration by nvic-set-vector. + + +void btle_handler(ble_evt_t *p_ble_evt); + +static void sys_evt_dispatch(uint32_t sys_evt) +{ +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + pstorage_sys_event_handler(sys_evt); +#else + // Forward Softdevice events to the fstorage module + fs_sys_event_handler(sys_evt); +#endif +} + +/** + * This function is called in interrupt context to handle BLE events; i.e. pull + * system and user events out of the pending events-queue of the BLE stack. The + * BLE stack signals the availability of events by the triggering the SWI2 + * interrupt, which forwards the handling to this function. + * + * The event processing loop is implemented in intern_softdevice_events_execute(). + * + * This function will signal to the user code by calling signalEventsToProcess + * that their is events to process and BLE::processEvents should be called. + */ +static uint32_t signalEvent() +{ + if(isEventsSignaled == false) { + isEventsSignaled = true; + nRF5xn::Instance(BLE::DEFAULT_INSTANCE).signalEventsToProcess(BLE::DEFAULT_INSTANCE); + } + return NRF_SUCCESS; +} + + +error_t btle_init(void) +{ + nrf_clock_lf_cfg_t clockConfiguration; + + // register softdevice handler vector + NVIC_SetVector(SD_EVT_IRQn, (uint32_t) SD_EVT_IRQHandler); + + // Configure the LF clock according to values provided by btle_clock.h. + // It is input from the chain of the yotta configuration system. + clockConfiguration.source = LFCLK_CONF_SOURCE; + clockConfiguration.xtal_accuracy = LFCLK_CONF_ACCURACY; + clockConfiguration.rc_ctiv = LFCLK_CONF_RC_CTIV; + clockConfiguration.rc_temp_ctiv = LFCLK_CONF_RC_TEMP_CTIV; + + SOFTDEVICE_HANDLER_INIT(&clockConfiguration, signalEvent); + + // Enable BLE stack + + ble_enable_params_t ble_enable_params; + uint32_t err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, + PERIPHERAL_LINK_COUNT, + &ble_enable_params); + + ble_enable_params.gatts_enable_params.attr_tab_size = GATTS_ATTR_TAB_SIZE; + ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT; + ble_enable_params.common_enable_params.vs_uuid_count = UUID_TABLE_MAX_ENTRIES; + + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + if (softdevice_enable(&ble_enable_params) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + +#if (NRF_SD_BLE_API_VERSION <= 2) + ble_gap_addr_t addr; + if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } +#else + +#endif + + ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler)); + ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch)); + + return btle_gap_init(); +} + +void btle_handler(ble_evt_t *p_ble_evt) +{ + using ble::pal::vendor::nordic::nRF5xGattClient; + using ble::pal::vendor::nordic::nRF5xSecurityManager; + + /* Library service handlers */ +#if SDK_CONN_PARAMS_MODULE_ENABLE + ble_conn_params_on_ble_evt(p_ble_evt); +#endif + +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) +#else + // Forward BLE events to the Connection State module. + // This must be called before any event handler that uses this module. + ble_conn_state_on_ble_evt(p_ble_evt); +#endif + +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + nRF5xGattClient::handle_events(p_ble_evt); +#endif + + nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); + nRF5xGap &gap = (nRF5xGap &) ble.getGap(); + nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer(); + nRF5xSecurityManager &securityManager = nRF5xSecurityManager::get_security_manager(); + + /* Custom event handler */ + switch (p_ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + gap.on_connection( + p_ble_evt->evt.gap_evt.conn_handle, + p_ble_evt->evt.gap_evt.params.connected + ); + break; + + case BLE_GAP_EVT_DISCONNECTED: { + Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; + // Since we are not in a connection and have not started advertising, + // store bonds + gap.setConnectionHandle (BLE_CONN_HANDLE_INVALID); + + Gap::DisconnectionReason_t reason; + switch (p_ble_evt->evt.gap_evt.params.disconnected.reason) { + case BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION: + reason = Gap::LOCAL_HOST_TERMINATED_CONNECTION; + break; + case BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION: + reason = Gap::REMOTE_USER_TERMINATED_CONNECTION; + break; + case BLE_HCI_CONN_INTERVAL_UNACCEPTABLE: + reason = Gap::CONN_INTERVAL_UNACCEPTABLE; + break; + default: + /* Please refer to the underlying transport library for an + * interpretion of this reason's value. */ + reason = static_cast(p_ble_evt->evt.gap_evt.params.disconnected.reason); + break; + } + +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + // Close all pending discoveries for this connection + nRF5xGattClient::handle_connection_termination(handle); +#endif + + gap.processDisconnectionEvent(handle, reason); + break; + } + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { + Gap::Handle_t connection = p_ble_evt->evt.gap_evt.conn_handle; + const ble_gap_evt_conn_param_update_request_t *update_request = + &p_ble_evt->evt.gap_evt.params.conn_param_update_request; + + sd_ble_gap_conn_param_update(connection, &update_request->conn_params); + break; + } + + case BLE_GAP_EVT_TIMEOUT: + gap.processTimeoutEvent(static_cast(p_ble_evt->evt.gap_evt.params.timeout.src)); + break; + + case BLE_GATTC_EVT_TIMEOUT: + case BLE_GATTS_EVT_TIMEOUT: + // Disconnect on GATT Server and Client timeout events. + // ASSERT_STATUS_RET_VOID (sd_ble_gap_disconnect(m_conn_handle, + // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); + break; + + case BLE_GAP_EVT_ADV_REPORT: + gap.on_advertising_packet(p_ble_evt->evt.gap_evt.params.adv_report); + break; + + default: + break; + } + + // Process security manager events + securityManager.sm_handler(p_ble_evt); + + gattServer.hwCallback(p_ble_evt); +} + +/*! @brief Callback when an error occurs inside the SoftDevice or ASSERT in debug*/ +void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) +{ + error("nrf failure at %s:%d", p_file_name, line_num); +} + +/*! + @brief Handler for general errors above the SoftDevice layer. + Typically we can' recover from this so we do a reset. +*/ +void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name) +{ + ASSERT_STATUS_RET_VOID( error_code ); + NVIC_SystemReset(); +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.h new file mode 100644 index 0000000000..cb0e1e09d0 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle.h @@ -0,0 +1,86 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BTLE_H_ +#define _BTLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common/common.h" + +#include "ble_srv_common.h" +#include "headers/nrf_ble.h" + +/* number of central links used by the application. + * When changing this number remember to adjust the RAM settings */ +#ifndef NRF_SDH_BLE_CENTRAL_LINK_COUNT + #define CENTRAL_LINK_COUNT 3 +#else + #define CENTRAL_LINK_COUNT NRF_SDH_BLE_CENTRAL_LINK_COUNT +#endif + +/* number of peripheral links used by the application. + * When changing this number remember to adjust the RAM settings */ +#ifndef NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + #define PERIPHERAL_LINK_COUNT 1 +#else + #define PERIPHERAL_LINK_COUNT NRF_SDH_BLE_PERIPHERAL_LINK_COUNT +#endif + + +/* GATTS attribite table size. + * When changing this number remember to adjust the RAM settings */ +#ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE + #define GATTS_ATTR_TAB_SIZE 0x600 +#else + #define GATTS_ATTR_TAB_SIZE NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE +#endif + + +/** + * Using this call, the application can select whether to include the + * Service Changed characteristic in the GATT Server. The default in all + * previous releases has been to include the Service Changed characteristic, + * but this affects how GATT clients behave. Specifically, it requires + * clients to subscribe to this attribute and not to cache attribute handles + * between connections unless the devices are bonded. If the application + * does not need to change the structure of the GATT server attributes at + * runtime this adds unnecessary complexity to the interaction with peer + * clients. If the SoftDevice is enabled with the Service Changed + * Characteristics turned off, then clients are allowed to cache attribute + * handles making applications simpler on both sides. + */ +#ifndef NRF_SDH_BLE_SERVICE_CHANGED + #define IS_SRVC_CHANGED_CHARACT_PRESENT 1 +#else + #define IS_SRVC_CHANGED_CHARACT_PRESENT NRF_SDH_BLE_SERVICE_CHANGED +#endif + +error_t btle_init(void); + +// flag indicating if events have been signaled or not +// It is used by processEvents and signalEventsToProcess +// signalEventsToProcess raise the flag and processEvents +// clears it. +extern bool isEventsSignaled; + +#ifdef __cplusplus +} +#endif + +#endif // ifndef _BTLE_H_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_clock.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_clock.h new file mode 100644 index 0000000000..bc4c1e29f4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_clock.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA + * integrated circuit in a product or a software update for such product, must reproduce + * the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific prior + * written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary or object form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _BTLE_CLOCK_H_ +#define _BTLE_CLOCK_H_ + +#include "nrf5x_lf_clk_helper.h" + +/** + * @brief Module that generates settings for the low-frequency (LF) clock configuration. + * + * This module provides macros that are generated from the mbed config system macros. + * + * + * + * As a result, this module provides the following: @n + * - literal value LFCLK_CONF_SOURCE @n + * - literal value LFCLK_CONF_ACCURACY @n + * - literal value LFCLK_CONF_RC_CTIV @n + * - literal value LFCLK_CONF_RC_TEMP_CTIV + */ + + + +#include "nrf_sdm.h" + +#define DEFAULT_LFCLK_CONF_ACCURACY NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM + +#ifdef NRF52 + #define MAX_LFCLK_CONF_RC_CTIV 32 +#else + #define MAX_LFCLK_CONF_RC_CTIV 64 +#endif + +#define MAX_LFCLK_CONF_RC_TEMP_CTIV 33 + +#define DEFAULT_LFCLK_CONF_RC_CTIV 16 // Check temperature every 16 * 250ms. +#define DEFAULT_LFCLK_CONF_RC_TEMP_CTIV 1 // Only calibrate if temperature has changed. + +#define NRF_LF_SRC_XTAL 2 +#define NRF_LF_SRC_SYNTH 3 +#define NRF_LF_SRC_RC 4 + +#if MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_RC + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_RC + + #ifdef MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL + #define LFCLK_CONF_RC_CTIV MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL + #else + #define LFCLK_CONF_RC_CTIV DEFAULT_LFCLK_CONF_RC_CTIV + #endif + + #ifdef MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG + #define LFCLK_CONF_RC_TEMP_CTIV MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG + #else + #define LFCLK_CONF_RC_TEMP_CTIV DEFAULT_LFCLK_CONF_RC_TEMP_CTIV + #endif + + #if (LFCLK_CONF_RC_CTIV < 1) || (LFCLK_CONF_RC_CTIV > MAX_LFCLK_CONF_RC_CTIV) + #error Calibration timer interval out of range! + #endif + + #if (LFCLK_CONF_RC_TEMP_CTIV < 0 ) || (LFCLK_CONF_RC_TEMP_CTIV > 33) + #error Number/mode of LF RC calibration intervals out of range! + #endif + +#elif MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_SYNTH + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_SYNTH + #define LFCLK_CONF_RC_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + #define LFCLK_CONF_RC_TEMP_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + + #ifdef MBED_CONF_NORDIC_LF_CLOCK_HF_SYNTH_ACCURACY + #define LFCLK_CONF_ACCURACY MBED_CONF_NORDIC_LF_CLOCK_HF_SYNTH_ACCURACY + #endif + +#else // default is NRF_LF_SRC_SYNTH + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_XTAL + #define LFCLK_CONF_RC_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + #define LFCLK_CONF_RC_TEMP_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + + #ifdef MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY + #define LFCLK_CONF_ACCURACY MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY + #endif + +#endif + +#ifndef LFCLK_CONF_ACCURACY + #define LFCLK_CONF_ACCURACY DEFAULT_LFCLK_CONF_ACCURACY +#endif + +#if (LFCLK_CONF_ACCURACY > NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM) || (LFCLK_CONF_ACCURACY < NRF_CLOCK_LF_XTAL_ACCURACY_250_PPM) + #error Low frequency clock accuracy out of range! +#endif + + +#endif //_BTLE_CLOCK_H_ + + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.cpp new file mode 100644 index 0000000000..8bc8600d7b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.cpp @@ -0,0 +1,99 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "common/common.h" + +#include "headers/nrf_ble_gap.h" +#include "ble_conn_params.h" + +static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) ATTR_ALWAYS_INLINE ATTR_CONST; +#if SDK_CONN_PARAMS_MODULE_ENABLE +static void error_callback(uint32_t nrf_error); +#endif // SDK_CONN_PARAMS_MODULE_ENABLE + +/**************************************************************************/ +/*! + @brief Initialise GAP in the underlying SoftDevice + + @returns +*/ +/**************************************************************************/ +error_t btle_gap_init(void) +{ + ble_gap_conn_params_t gap_conn_params = {0}; + + gap_conn_params.min_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MIN_INTERVAL_MS); // in 1.25ms units + gap_conn_params.max_conn_interval = msec_to_1_25msec(CFG_GAP_CONNECTION_MAX_INTERVAL_MS); // in 1.25ms unit + gap_conn_params.slave_latency = CFG_GAP_CONNECTION_SLAVE_LATENCY; + gap_conn_params.conn_sup_timeout = CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS / 10; // in 10ms unit + + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed + + ASSERT_STATUS( sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) CFG_GAP_LOCAL_NAME, strlen(CFG_GAP_LOCAL_NAME))); + ASSERT_STATUS( sd_ble_gap_appearance_set(CFG_GAP_APPEARANCE)); + ASSERT_STATUS( sd_ble_gap_ppcp_set(&gap_conn_params)); + ASSERT_STATUS( sd_ble_gap_tx_power_set(CFG_BLE_TX_POWER_LEVEL)); + + /** + * Call to conn_params_init() is not necessary; and so is disabled by default. + * This API should be exposed to the user to be invoked when necessary. + */ +#if SDK_CONN_PARAMS_MODULE_ENABLE + /* Connection Parameters */ + enum { + FIRST_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER), + NEXT_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER), + MAX_UPDATE_COUNT = 3 + }; + + ble_conn_params_init_t cp_init = {0}; + + cp_init.p_conn_params = NULL; + cp_init.first_conn_params_update_delay = FIRST_UPDATE_DELAY; + cp_init.next_conn_params_update_delay = NEXT_UPDATE_DELAY; + cp_init.max_conn_params_update_count = MAX_UPDATE_COUNT; + cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; + cp_init.disconnect_on_fail = true; + cp_init.evt_handler = NULL; + cp_init.error_handler = error_callback; + + ASSERT_STATUS ( ble_conn_params_init(&cp_init)); +#endif // SDK_CONN_PARAMS_MODULE_ENABLE + + return ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Converts msecs to an integer representing 1.25ms units + + @param[in] ms + The number of milliseconds to conver to 1.25ms units + + @returns The number of 1.25ms units in the supplied number of ms +*/ +/**************************************************************************/ +static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) +{ + return (interval_ms * 4) / 5; +} + +#if SDK_CONN_PARAMS_MODULE_ENABLE +static void error_callback(uint32_t nrf_error) +{ + ASSERT_STATUS_RET_VOID( nrf_error ); +} +#endif // SDK_CONN_PARAMS_MODULE_ENABLE diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.h new file mode 100644 index 0000000000..828da3cd78 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/btle_gap.h @@ -0,0 +1,24 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BTLE_GAP_H_ +#define _BTLE_GAP_H_ + +#include "common/common.h" + +error_t btle_gap_init(void); + +#endif // ifndef _BTLE_GAP_H_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.cpp new file mode 100644 index 0000000000..6a85387330 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.cpp @@ -0,0 +1,362 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "custom_helper.h" + +/* + * The current version of the soft-device doesn't handle duplicate 128-bit UUIDs + * very well. It is therefore necessary to filter away duplicates before + * passing long UUIDs to sd_ble_uuid_vs_add(). The following types and data + * structures involved in maintaining a local cache of 128-bit UUIDs. + */ +typedef struct { + UUID::LongUUIDBytes_t uuid; + uint8_t type; +} converted_uuid_table_entry_t; + +static unsigned uuidTableEntries = 0; /* current usage of the table */ +converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; + +namespace { + +static void set_perm(ble_gap_conn_sec_mode_t& dest, GattAttribute::Security_t src) { + switch (src.value()) { + case GattAttribute::Security_t::NONE: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dest); + break; + + case GattAttribute::Security_t::UNAUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dest); + break; + + case GattAttribute::Security_t::AUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&dest); + break; + + case GattAttribute::Security_t::SC_AUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&dest); + break; + + default: + break; + } +} + +} + + +void custom_reset_128bits_uuid_table() { + uuidTableEntries = 0; +} + +/** + * lookup the cache of previously converted 128-bit UUIDs to find a type value. + * @param uuid base 128-bit UUID + * @param recoveredType the type field of the 3-byte nRF's uuid. + * @return true if a match is found. + */ +static bool +lookupConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t *recoveredType) +{ + unsigned i; + for (i = 0; i < uuidTableEntries; i++) { + unsigned byteIndex; + for (byteIndex = 0; byteIndex < UUID::LENGTH_OF_LONG_UUID; byteIndex++) { + /* Skip bytes 2 and 3, because they contain the shortUUID (16-bit) version of the + * long UUID; and we're comparing against the remainder. */ + if ((byteIndex == 2) || (byteIndex == 3)) { + continue; + } + + if (convertedUUIDTable[i].uuid[byteIndex] != uuid[byteIndex]) { + break; + } + } + + if (byteIndex == UUID::LENGTH_OF_LONG_UUID) { + *recoveredType = convertedUUIDTable[i].type; + return true; + } + } + + return false; +} + +static void +addToConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t type) +{ + if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) { + return; /* recovery needed; or at least the user should be warned about this fact.*/ + } + + memcpy(convertedUUIDTable[uuidTableEntries].uuid, uuid, UUID::LENGTH_OF_LONG_UUID); + convertedUUIDTable[uuidTableEntries].uuid[2] = 0; + convertedUUIDTable[uuidTableEntries].uuid[3] = 0; + convertedUUIDTable[uuidTableEntries].type = type; + uuidTableEntries++; +} + +/** + * The nRF transport has its own 3-byte representation of a UUID. If the user- + * specified UUID is 128-bits wide, then the UUID base needs to be added to the + * soft-device and converted to a 3-byte handle before being used further. This + * function is responsible for this translation of user-specified UUIDs into + * nRF's representation. + * + * @param[in] uuid + * user-specified UUID + * @return nRF + * 3-byte UUID (containing a type and 16-bit UUID) representation + * to be used with SVC calls. + */ +ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid) +{ + ble_uuid_t nordicUUID; + nordicUUID.uuid = uuid.getShortUUID(); + nordicUUID.type = BLE_UUID_TYPE_UNKNOWN; /* to be set below */ + + if (uuid.shortOrLong() == UUID::UUID_TYPE_SHORT) { + nordicUUID.type = BLE_UUID_TYPE_BLE; + } else { + if (!lookupConvertedUUIDTable(uuid.getBaseUUID(), &nordicUUID.type)) { + nordicUUID.type = custom_add_uuid_base(uuid.getBaseUUID()); + addToConvertedUUIDTable(uuid.getBaseUUID(), nordicUUID.type); + } + } + + return nordicUUID; +} + +/**************************************************************************/ +/*! + @brief Adds the base UUID to the custom service. All UUIDs used + by this service are based on this 128-bit UUID. + + @note This UUID needs to be added to the SoftDevice stack before + adding the service's primary service via + 'sd_ble_gatts_service_add' + + @param[in] p_uuid_base A pointer to the 128-bit UUID array (8*16) + + @returns The UUID type. + A return value of 0 should be considered an error. + + @retval 0x00 BLE_UUID_TYPE_UNKNOWN + @retval 0x01 BLE_UUID_TYPE_BLE + @retval 0x02 BLE_UUID_TYPE_VENDOR_BEGIN + + @section EXAMPLE + @code + + // Take note that bytes 2/3 are blank since these are used to identify + // the primary service and individual characteristics + #define CFG_CUSTOM_UUID_BASE "\x6E\x40\x00\x00\xB5\xA3\xF3\x93\xE0\xA9\xE5\x0E\x24\xDC\xCA\x9E" + + uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); + ASSERT(uuid_type > 0, ERROR_NOT_FOUND); + + // We can now safely add the primary service and any characteristics + // for our custom service ... + + @endcode +*/ +/**************************************************************************/ +uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base) +{ + ble_uuid128_t base_uuid; + uint8_t uuid_type = 0; + + for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { + base_uuid.uuid128[i] = p_uuid_base[i]; + } + + ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0); + + return uuid_type; +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base, + ble_uuid_t *p_uuid) +{ + UUID::LongUUIDBytes_t uuid_base_le; + + for (uint8_t i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { + uuid_base_le[i] = p_uuid_base[i]; + } + + ASSERT_STATUS( sd_ble_uuid_decode(UUID::LENGTH_OF_LONG_UUID, uuid_base_le, p_uuid)); + + return ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Adds a new characteristic to the custom service, assigning + properties, a UUID add-on value, etc. + + @param[in] service_handle + @param[in] p_uuid The 16-bit value to add to the base UUID + for this characteristic (normally >1 + since 1 is typically used by the primary + service). + @param[in] char_props The characteristic properties, as + defined by ble_gatt_char_props_t + @param[in] max_length The maximum length of this characeristic + @param[in] has_variable_len Whether the characteristic data has + variable length. + @param[out] p_char_handle + + @returns + @retval ERROR_NONE Everything executed normally +*/ +/**************************************************************************/ +error_t custom_add_in_characteristic(uint16_t service_handle, + ble_uuid_t *p_uuid, + uint8_t properties, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security, + GattAttribute::Security_t update_security, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + const uint8_t *userDescriptionDescriptorValuePtr, + uint16_t userDescriptionDescriptorValueLen, + const uint8_t *presentationFormatDescriptorValuePtr, + uint16_t presentationFormatDescriptorValueLen, + bool readAuthorization, + bool writeAuthorization, + ble_gatts_char_handles_t *p_char_handle) +{ + /* Characteristic metadata */ + ble_gatts_attr_md_t cccd_md; + ble_gatt_char_props_t char_props; + + memcpy(&char_props, &properties, 1); + + if (char_props.notify || char_props.indicate) { + /* Notification requires cccd */ + memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); + cccd_md.vloc = BLE_GATTS_VLOC_STACK; + set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE); + set_perm(cccd_md.write_perm, update_security); + } + + ble_gatts_char_md_t char_md = {0}; + + char_md.char_props = char_props; + char_md.p_cccd_md = + (char_props.notify || char_props.indicate) ? &cccd_md : NULL; + if ((userDescriptionDescriptorValueLen > 0) && (userDescriptionDescriptorValuePtr != NULL)) { + char_md.p_char_user_desc = const_cast(userDescriptionDescriptorValuePtr); + char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen; + char_md.char_user_desc_size = userDescriptionDescriptorValueLen; + } + if ((presentationFormatDescriptorValueLen > 0) && (presentationFormatDescriptorValuePtr != NULL)) { + ASSERT_TRUE( sizeof(ble_gatts_char_pf_t) == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM ); + ASSERT_TRUE( presentationFormatDescriptorValueLen == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM ); + char_md.p_char_pf = const_cast(reinterpret_cast(presentationFormatDescriptorValuePtr)); + } + + /* Attribute declaration */ + ble_gatts_attr_md_t attr_md = {0}; + + attr_md.rd_auth = readAuthorization; + attr_md.wr_auth = writeAuthorization; + + attr_md.vloc = BLE_GATTS_VLOC_STACK; + /* Always set variable size */ + attr_md.vlen = has_variable_len; + + set_perm(attr_md.read_perm, read_security); + set_perm(attr_md.write_perm, write_security); + + ble_gatts_attr_t attr_char_value = {0}; + + attr_char_value.p_uuid = p_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = length; + attr_char_value.max_len = max_length; + attr_char_value.p_value = p_data; + + ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, + &char_md, + &attr_char_value, + p_char_handle)); + + return ERROR_NONE; +} + + + +/**************************************************************************/ +/*! + @brief Adds a new descriptor to the custom service, assigning + value, a UUID add-on value, etc. + + @param[in] char_handle + @param[in] p_uuid The 16-bit value to add to the base UUID + for this descriptor (normally >1 + since 1 is typically used by the primary + service). + @param[in] max_length The maximum length of this descriptor + @param[in] has_variable_len Whether the characteristic data has + variable length. + + @returns + @retval ERROR_NONE Everything executed normally +*/ +/**************************************************************************/ +error_t custom_add_in_descriptor(uint16_t char_handle, + ble_uuid_t *p_uuid, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + uint16_t *p_desc_handle, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security) +{ + /* Descriptor metadata */ + ble_gatts_attr_md_t desc_md = {0}; + + desc_md.vloc = BLE_GATTS_VLOC_STACK; + /* Always set variable size */ + desc_md.vlen = has_variable_len; + + /* Make it readable and writable */ + set_perm(desc_md.read_perm, read_security); + set_perm(desc_md.write_perm, write_security); + + ble_gatts_attr_t attr_desc = {0}; + + attr_desc.p_uuid = p_uuid; + attr_desc.p_attr_md = &desc_md; + attr_desc.init_len = length; + attr_desc.max_len = max_length; + attr_desc.p_value = p_data; + + ASSERT_STATUS ( sd_ble_gatts_descriptor_add(char_handle, + &attr_desc, + p_desc_handle)); + + return ERROR_NONE; +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.h new file mode 100644 index 0000000000..47a3969e96 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/btle/custom/custom_helper.h @@ -0,0 +1,82 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CUSTOM_HELPER_H_ +#define _CUSTOM_HELPER_H_ + +#include "common/common.h" +#include "headers/nrf_ble.h" +#include "ble/UUID.h" +#include "ble/GattCharacteristic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the maximum number of 128-bit UUIDs with distinct bases that * + * we expect to be in use; increase this limit if needed. */ +#ifdef NRF_SDH_BLE_VS_UUID_COUNT + #define UUID_TABLE_MAX_ENTRIES NRF_SDH_BLE_VS_UUID_COUNT +#else + #define UUID_TABLE_MAX_ENTRIES (4) +#endif + +/** + * Reset the table of 128bits uuids. + * This table is used to keep track of vendors uuids added to the softdevice. + * It is important to reset it before disabling the softdevice otherwise the + * next time the softdevice will be enabled, this table will not be synchronmized + * with the softdevice table. + */ +void custom_reset_128bits_uuid_table(); +uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base); +error_t custom_decode_uuid(uint8_t const *const p_uuid_base, + ble_uuid_t *p_uuid); +ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid); + +error_t custom_add_in_characteristic(uint16_t service_handle, + ble_uuid_t *p_uuid, + uint8_t properties, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security, + GattAttribute::Security_t update_security, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + const uint8_t *userDescriptionDescriptorValuePtr, + uint16_t userDescriptionDescriptorValueLen, + const uint8_t *presentationFormatDescriptorValuePtr, + uint16_t presentationFormatDescriptorValueLen, + bool readAuthorization, + bool writeAuthorization, + ble_gatts_char_handles_t *p_char_handle); + +error_t custom_add_in_descriptor(uint16_t char_handle, + ble_uuid_t *p_uuid, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + uint16_t *p_desc_handle, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security); + +#ifdef __cplusplus +} +#endif + +#endif // ifndef _CUSTOM_HELPER_H_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ansi_escape.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ansi_escape.h new file mode 100644 index 0000000000..392dedb44f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ansi_escape.h @@ -0,0 +1,103 @@ +/**************************************************************************/ +/*! + @file ansi_esc_code.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. + + This file is part of the tinyusb stack. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _ANSI_ESC_CODE_H_ +#define _ANSI_ESC_CODE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSI_CODE(seq) "\33[" seq +#define CSI_SGR(x) CSI_CODE(#x) "m" + +//------------- Cursor movement -------------// +#define ANSI_CURSOR_UP(n) CSI_CODE(#n "A") +#define ANSI_CURSOR_DOWN(n) CSI_CODE(#n "B") +#define ANSI_CURSOR_FORWARD(n) CSI_CODE(#n "C") +#define ANSI_CURSOR_BACKWARD(n) CSI_CODE(#n "D") +#define ANSI_CURSOR_LINE_DOWN(n) CSI_CODE(#n "E") +#define ANSI_CURSOR_LINE_UP(n) CSI_CODE(#n "F") +#define ANSI_CURSOR_POSITION(n, m) CSI_CODE(#n ";" #m "H") + +#define ANSI_ERASE_SCREEN(n) CSI_CODE(#n "J") +#define ANSI_ERASE_LINE(n) CSI_CODE(#n "K") + +/** text color */ +#define ANSI_TEXT_BLACK CSI_SGR(30) +#define ANSI_TEXT_RED CSI_SGR(31) +#define ANSI_TEXT_GREEN CSI_SGR(32) +#define ANSI_TEXT_YELLOW CSI_SGR(33) +#define ANSI_TEXT_BLUE CSI_SGR(34) +#define ANSI_TEXT_MAGENTA CSI_SGR(35) +#define ANSI_TEXT_CYAN CSI_SGR(36) +#define ANSI_TEXT_WHITE CSI_SGR(37) +#define ANSI_TEXT_DEFAULT CSI_SGR(39) + +/** background color */ +#define ANSI_BG_BLACK CSI_SGR(40) +#define ANSI_BG_RED CSI_SGR(41) +#define ANSI_BG_GREEN CSI_SGR(42) +#define ANSI_BG_YELLOW CSI_SGR(43) +#define ANSI_BG_BLUE CSI_SGR(44) +#define ANSI_BG_MAGENTA CSI_SGR(45) +#define ANSI_BG_CYAN CSI_SGR(46) +#define ANSI_BG_WHITE CSI_SGR(47) +#define ANSI_BG_DEFAULT CSI_SGR(49) + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_ANSI_ESC_CODE_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/assertion.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/assertion.h new file mode 100644 index 0000000000..71bacb3e81 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/assertion.h @@ -0,0 +1,197 @@ +/**************************************************************************/ +/*! + @file assertion.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _ASSERTION_H_ +#define _ASSERTION_H_ + +#include "projectconfig.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +static inline void debugger_breakpoint(void) ATTR_ALWAYS_INLINE; +static inline void debugger_breakpoint(void) +{ +#ifndef _TEST_ + __asm("BKPT #0\n"); +#endif +} + +//--------------------------------------------------------------------+ +// Compile-time Assert +//--------------------------------------------------------------------+ +#if defined __COUNTER__ && __COUNTER__ != __COUNTER__ + #define _ASSERT_COUNTER __COUNTER__ +#else + #define _ASSERT_COUNTER __LINE__ +#endif + +#define ASSERT_STATIC(const_expr, message) enum { XSTRING_CONCAT_(static_assert_, _ASSERT_COUNTER) = 1/(!!(const_expr)) } + +//--------------------------------------------------------------------+ +// Assert Helper +//--------------------------------------------------------------------+ +//#ifndef _TEST_ +// #define ASSERT_MESSAGE(format, ...) _PRINTF("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) +//#else +// #define ASSERT_MESSAGE(format, ...) _PRINTF("%d:note: Assert " format "\n", __LINE__, __VA_ARGS__) +//#endif + +#if CFG_DEBUG == 3 + #define ASSERT_MESSAGE(format, ...) debugger_breakpoint() +#elif CFG_DEBUG == 2 + #define ASSERT_MESSAGE(format, ...) printf("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) +#else + #define ASSERT_MESSAGE(format, ...) +#endif + +#define ASSERT_ERROR_HANDLER(x, para) \ + return (x) + +#define ASSERT_DEFINE_WITH_HANDLER(error_handler, handler_para, setup_statement, condition, error, format, ...) \ + do{\ + setup_statement;\ + if (!(condition)) {\ + ASSERT_MESSAGE(format, __VA_ARGS__);\ + error_handler(error, handler_para);\ + }\ + }while(0) + +#define ASSERT_DEFINE(...) ASSERT_DEFINE_WITH_HANDLER(ASSERT_ERROR_HANDLER, NULL, __VA_ARGS__) + +//--------------------------------------------------------------------+ +// error_t Status Assert TODO use ASSERT_DEFINE +//--------------------------------------------------------------------+ +#define ASSERT_STATUS_MESSAGE(sts, message) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, status, "%s: %s", ErrorStr[status], message) + +#define ASSERT_STATUS(sts) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, status, "error = %d", status) + +#define ASSERT_STATUS_RET_VOID(sts) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, (void) 0, "error = %d", status) + +//--------------------------------------------------------------------+ +// Logical Assert +//--------------------------------------------------------------------+ +#define ASSERT_TRUE(condition , error) ASSERT_DEFINE( , (condition), error, "%s", "evaluated to false") +#define ASSERT_FALSE(condition , error) ASSERT_DEFINE( ,!(condition), error, "%s", "evaluated to true") + +//--------------------------------------------------------------------+ +// Pointer Assert +//--------------------------------------------------------------------+ +#define ASSERT_PTR(...) ASSERT_PTR_NOT_NULL(__VA_ARGS__) +#define ASSERT_PTR_NOT_NULL(pointer, error) ASSERT_DEFINE( , NULL != (pointer), error, "%s", "pointer is NULL") +#define ASSERT_PTR_NULL(pointer, error) ASSERT_DEFINE( , NULL == (pointer), error, "%s", "pointer is not NULL") + +//--------------------------------------------------------------------+ +// Integral Assert +//--------------------------------------------------------------------+ +#define ASSERT_XXX_EQUAL(type_format, expected, actual, error) \ + ASSERT_DEFINE(\ + uint32_t exp = (expected); uint32_t act = (actual),\ + exp==act,\ + error,\ + "expected " type_format ", actual " type_format, exp, act) + +#define ASSERT_XXX_WITHIN(type_format, lower, upper, actual, error) \ + ASSERT_DEFINE(\ + uint32_t low = (lower); uint32_t up = (upper); uint32_t act = (actual),\ + (low <= act) && (act <= up),\ + error,\ + "expected within " type_format " - " type_format ", actual " type_format, low, up, act) + +//--------------------------------------------------------------------+ +// Integer Assert +//--------------------------------------------------------------------+ +#define ASSERT_INT(...) ASSERT_INT_EQUAL(__VA_ARGS__) +#define ASSERT_INT_EQUAL(...) ASSERT_XXX_EQUAL("%d", __VA_ARGS__) +#define ASSERT_INT_WITHIN(...) ASSERT_XXX_WITHIN("%d", __VA_ARGS__) + +//--------------------------------------------------------------------+ +// Hex Assert +//--------------------------------------------------------------------+ +#define ASSERT_HEX(...) ASSERT_HEX_EQUAL(__VA_ARGS__) +#define ASSERT_HEX_EQUAL(...) ASSERT_XXX_EQUAL("0x%x", __VA_ARGS__) +#define ASSERT_HEX_WITHIN(...) ASSERT_XXX_WITHIN("0x%x", __VA_ARGS__) + +//--------------------------------------------------------------------+ +// Bin Assert +//--------------------------------------------------------------------+ +#define BIN8_PRINTF_PATTERN "%d%d%d%d%d%d%d%d" +#define BIN8_PRINTF_CONVERT(byte) \ + ((byte) & 0x80 ? 1 : 0), \ + ((byte) & 0x40 ? 1 : 0), \ + ((byte) & 0x20 ? 1 : 0), \ + ((byte) & 0x10 ? 1 : 0), \ + ((byte) & 0x08 ? 1 : 0), \ + ((byte) & 0x04 ? 1 : 0), \ + ((byte) & 0x02 ? 1 : 0), \ + ((byte) & 0x01 ? 1 : 0) + +#define ASSERT_BIN8(...) ASSERT_BIN8_EQUAL(__VA_ARGS__) +#define ASSERT_BIN8_EQUAL(expected, actual, error)\ + ASSERT_DEFINE(\ + uint8_t exp = (expected); uint8_t act = (actual),\ + exp==act,\ + error,\ + "expected " BIN8_PRINTF_PATTERN ", actual " BIN8_PRINTF_PATTERN, BIN8_PRINTF_CONVERT(exp), BIN8_PRINTF_CONVERT(act) ) + +#ifdef __cplusplus +} +#endif + +#endif /* _ASSERTION_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/binary.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/binary.h new file mode 100644 index 0000000000..585787eb2f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/binary.h @@ -0,0 +1,96 @@ +/**************************************************************************/ +/*! + @file binary.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _BINARY_H_ +#define _BINARY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/// n-th Bit +#define BIT(n) (1 << (n)) + +/// set n-th bit of x to 1 +#define BIT_SET(x, n) ( (x) | BIT(n) ) + +/// clear n-th bit of x +#define BIT_CLR(x, n) ( (x) & (~BIT(n)) ) + +/// test n-th bit of x +#define BIT_TEST(x, n) ( (x) & BIT(n) ) + +#if defined(__GNUC__) && !defined(__CC_ARM) // keil does not support binary format + +#define BIN8(x) ((uint8_t) (0b##x)) +#define BIN16(b1, b2) ((uint16_t) (0b##b1##b2)) +#define BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4)) + +#else + +// internal macro of B8, B16, B32 +#define _B8__(x) (((x&0x0000000FUL)?1:0) \ + +((x&0x000000F0UL)?2:0) \ + +((x&0x00000F00UL)?4:0) \ + +((x&0x0000F000UL)?8:0) \ + +((x&0x000F0000UL)?16:0) \ + +((x&0x00F00000UL)?32:0) \ + +((x&0x0F000000UL)?64:0) \ + +((x&0xF0000000UL)?128:0)) + +#define BIN8(d) ((uint8_t) _B8__(0x##d##UL)) +#define BIN16(dmsb,dlsb) (((uint16_t)BIN8(dmsb)<<8) + BIN8(dlsb)) +#define BIN32(dmsb,db2,db3,dlsb) \ + (((uint32_t)BIN8(dmsb)<<24) \ + + ((uint32_t)BIN8(db2)<<16) \ + + ((uint32_t)BIN8(db3)<<8) \ + + BIN8(dlsb)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BINARY_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ble_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ble_error.h new file mode 100644 index 0000000000..36deb33080 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/ble_error.h @@ -0,0 +1,151 @@ +/**************************************************************************/ +/*! + @file ble_error.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief Error Header + * + * \note TBD + */ + +/** \ingroup Group_Common + * \defgroup Group_Error Error Codes + * @{ + */ + +#ifndef _BLE_ERROR_H_ +#define _BLE_ERROR_H_ + +#include "projectconfig.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef enum +{ + /*======================================================================= + NORDIC GLOBAL ERRORS 0x0000 .. 0x00FF + ----------------------------------------------------------------------- + Errors mapped from nrf_error.h + -----------------------------------------------------------------------*/ + ERROR_NONE = 0x0000 , ///< Successful command + ERROR_SVC_HANDLER_MISSING = 0x0001 , ///< SVC handler is missing + ERROR_SOFTDEVICE_NOT_ENABLED = 0x0002 , ///< SoftDevice has not been enabled + ERROR_INTERNAL = 0x0003 , ///< Internal Error + ERROR_NO_MEM = 0x0004 , ///< No Memory for operation + ERROR_NOT_FOUND = 0x0005 , ///< Not found + ERROR_NOT_SUPPORTED = 0x0006 , ///< Not supported + ERROR_INVALID_PARAM = 0x0007 , ///< Invalid Parameter + ERROR_INVALID_STATE = 0x0008 , ///< Invalid state, operation disallowed in this state + ERROR_INVALID_LENGTH = 0x0009 , ///< Invalid Length + ERROR_INVALID_FLAGS = 0x000A , ///< Invalid Flags + ERROR_INVALID_DATA = 0x000B , ///< Invalid Data + ERROR_DATA_SIZE = 0x000C , ///< Data size exceeds limit + ERROR_TIMEOUT = 0x000D , ///< Operation timed out + ERROR_NULL = 0x000E , ///< Null Pointer + ERROR_FORBIDDEN = 0x000F , ///< Forbidden Operation + ERROR_INVALID_ADDR = 0x0010 , ///< Bad Memory Address + ERROR_BUSY = 0x0011 , ///< Busy + /*=======================================================================*/ + + ERROR_INVALIDPARAMETER = 0x0100 , /**< An invalid parameter value was provided */ + ERROR_I2C_XFER_FAILED = 0x0101 , /**< an failed attempt to make I2C transfer */ + + /*======================================================================= + SIMPLE BINARY PROTOCOL ERRORS 0x0120 .. 0x013F + ----------------------------------------------------------------------- + Errors relating to the simple binary protocol (/src//protocol) + -----------------------------------------------------------------------*/ + ERROR_PROT_INVALIDMSGTYPE = 0x121, /**< Unexpected msg type encountered */ + ERROR_PROT_INVALIDCOMMANDID = 0x122, /**< Unknown or out of range command ID */ + ERROR_PROT_INVALIDPAYLOAD = 0x123, /**< Message payload has a problem (invalid len, etc.) */ + /*=======================================================================*/ + + //------------- based on Nordic SDM nrf_error_sdm.h -------------// + ERROR_SDM_LFCLK_SOURCE_UNKNOWN = 0x1000 , ///< Unknown lfclk source + ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION = 0x1001 , ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having enabled SoftDevice interrupts) + ERROR_SDM_INCORRECT_CLENR0 = 0x1002 , ///< Incorrect CLENR0 (can be caused by erronous SoftDevice flashing) + + //------------- based on Nordic SOC nrf_error_soc.h -------------// + /* Mutex Errors */ + ERROR_SOC_MUTEX_ALREADY_TAKEN = 0x2000 , ///< Mutex already taken + + /* NVIC errors */ + ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE = 0x2001 , ///< NVIC interrupt not available + ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED = 0x2002 , ///< NVIC interrupt priority not allowed + ERROR_SOC_NVIC_SHOULD_NOT_RETURN = 0x2003 , ///< NVIC should not return + + /* Power errors */ + ERROR_SOC_POWER_MODE_UNKNOWN = 0x2004 , ///< Power mode unknown + ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN = 0x2005 , ///< Power POF threshold unknown + ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN = 0x2006 , ///< Power off should not return + + /* Rand errors */ + ERROR_SOC_RAND_NOT_ENOUGH_VALUES = 0x2007 , ///< RAND not enough values + + /* PPI errors */ + ERROR_SOC_PPI_INVALID_CHANNEL = 0x2008 , ///< Invalid PPI Channel + ERROR_SOC_PPI_INVALID_GROUP = 0x2009 , ///< Invalid PPI Group + + //------------- based on Nordic STK (ble) ble_err.h -------------// + ERROR_BLE_INVALID_CONN_HANDLE = 0x3001 , /**< Invalid connection handle. */ + ERROR_BLE_INVALID_ATTR_HANDLE = 0x3002 , /**< Invalid attribute handle. */ + ERROR_BLE_NO_TX_BUFFERS = 0x3003 , /**< Buffer capacity exceeded. */ + + // L2CAP + ERROR_BLE_L2CAP_CID_IN_USE = 0x3100 , /**< CID already in use. */ + + // GAP + ERROR_BLE_GAP_UUID_LIST_MISMATCH = 0x3200 , /**< UUID list does not contain an integral number of UUIDs. */ + ERROR_BLE_GAP_DISCOVERABLE_WITH_WHITELIST = 0x3201 , /**< Use of Whitelist not permitted with discoverable advertising. */ + ERROR_BLE_GAP_INVALID_BLE_ADDR = 0x3202 , /**< The upper two bits of the address do not correspond to the specified address type. */ + + // GATTC + ERROR_BLE_GATTC_PROC_NOT_PERMITTED = 0x3300 , + + // GATTS + ERROR_BLEGATTS_INVALID_ATTR_TYPE = 0x3400 , /**< Invalid attribute type. */ + ERROR_BLEGATTS_SYS_ATTR_MISSING = 0x3401 , /**< System Attributes missing. */ + +}error_t; + +#ifdef __cplusplus + } +#endif + +#endif /* _BLE_ERROR_H_ */ + + /** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/common.h new file mode 100644 index 0000000000..6002c6dfb7 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/common.h @@ -0,0 +1,236 @@ +/**************************************************************************/ +/*! + @file common.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \defgroup Group_Common Common Files + * @{ + * + * \defgroup Group_CommonH common.h + * + * @{ + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// INCLUDES +//--------------------------------------------------------------------+ + +//------------- Standard Header -------------// +#include +#include +#include +#include +#include + +//------------- General Header -------------// +#include "projectconfig.h" +#include "compiler.h" +#include "assertion.h" +#include "binary.h" +#include "ble_error.h" + +//------------- MCU header -------------// +//#include "nrf.h" + +//--------------------------------------------------------------------+ +// TYPEDEFS +//--------------------------------------------------------------------+ +typedef unsigned char byte_t; +typedef float float32_t; +typedef double float64_t; + +//--------------------------------------------------------------------+ +// MACROS +//--------------------------------------------------------------------+ +#define STRING_(x) #x // stringify without expand +#define XSTRING_(x) STRING_(x) // expand then stringify +#define STRING_CONCAT_(a, b) a##b // concat without expand +#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) // expand then concat + +#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) +#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff)) +#define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16) +#define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16) + +#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB +#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff)) +#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff)) +#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB + +#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32) +#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32) + +//--------------------------------------------------------------------+ +// INLINE FUNCTION +//--------------------------------------------------------------------+ +#define memclr_(buffer, size) memset(buffer, 0, size) + +//------------- Conversion -------------// +/// form an uint32_t from 4 x uint8_t +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) +{ + return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; +} + +static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_high_u8(uint16_t u16) +{ + return (uint8_t) ((u16 >> 8) & 0x00ff); +} + +static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_low_u8(uint16_t u16) +{ + return (uint8_t) (u16 & 0x00ff); +} + +//------------- Min -------------// +static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t min8_of(uint8_t x, uint8_t y) +{ + return (x < y) ? x : y; +} + +static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint16_t min16_of(uint16_t x, uint16_t y) +{ + return (x < y) ? x : y; +} + +static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t min32_of(uint32_t x, uint32_t y) +{ + return (x < y) ? x : y; +} + +//------------- Max -------------// +static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t max32_of(uint32_t x, uint32_t y) +{ + return (x > y) ? x : y; +} + +//------------- Align -------------// +static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align32 (uint32_t value) +{ + return (value & 0xFFFFFFE0UL); +} + +static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align16 (uint32_t value) +{ + return (value & 0xFFFFFFF0UL); +} + +static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align_n (uint32_t alignment, uint32_t value) +{ + return value & (~(alignment-1)); +} + +static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align4k (uint32_t value) +{ + return (value & 0xFFFFF000UL); +} + +static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t offset4k(uint32_t value) +{ + return (value & 0xFFFUL); +} + +//------------- Mathematics -------------// +/// inclusive range checking +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower <= value) && (value <= upper); +} + +/// exclusive range checking +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower < value) && (value < upper); +} + +static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t log2_of(uint32_t value) +{ + uint8_t result = 0; // log2 of a value is its MSB's position + + while (value >>= 1) + { + result++; + } + return result; +} + +// return the number of set bits in value +static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t cardinality_of(uint32_t value) +{ + // Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only + // the high bit set, then it will only go once through the loop + // Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) + // mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method + // "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and + // published in 1964 in a book edited by Beckenbach.)" + uint8_t count; + for (count = 0; value; count++) + { + value &= value - 1; // clear the least significant bit set + } + + return count; +} + +#ifdef __cplusplus + } +#endif + +#endif /* _COMMON_H_ */ + +/** @} */ +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/compiler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/compiler.h new file mode 100644 index 0000000000..5b04ac05d0 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/common/compiler.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/*! + @file compiler.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief GCC Header + */ + +/** \ingroup Group_Compiler + * \defgroup Group_GCC GNU GCC + * @{ + */ + +#ifndef _COMPILER_GCC_H_ +#define _COMPILER_GCC_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "projectconfig.h" + +//#ifndef __GNUC__ +// #define ATTR_ALWAYS_INLINE +// #define ATTR_CONST +//#else + +#ifdef _TEST_ + #define ATTR_ALWAYS_INLINE + #define STATIC_ + #define INLINE_ +#else + #define STATIC_ static + #define INLINE_ inline + + #if CFG_DEBUG == 3 + #define ATTR_ALWAYS_INLINE // no inline for debug = 3 + #endif +#endif + + +#ifdef __GNUC__ + +#define ALIGN_OF(x) __alignof__(x) + +/// Normally, the compiler places the objects it generates in sections like data or bss & function in text. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section +#define ATTR_SECTION(section) __attribute__ ((#section)) + +/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, an error that includes message is diagnosed. This is useful for compile-time checking +#define ATTR_ERROR(Message) __attribute__ ((error(Message))) + +/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning that includes message is diagnosed. This is useful for compile-time checking +#define ATTR_WARNING(Message) __attribute__ ((warning(Message))) + +/** + * \defgroup Group_VariableAttr Variable Attributes + * @{ + */ + +/// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes +#define ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + +/// The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute +#define ATTR_PACKED __attribute__ ((packed)) + +#define ATTR_PREPACKED + +#define ATTR_PACKED_STRUCT(x) x __attribute__ ((packed)) +/** @} */ + +/** + * \defgroup Group_FuncAttr Function Attributes + * @{ + */ + +#ifndef ATTR_ALWAYS_INLINE +/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified +#define ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) +#endif + +/// The nonnull attribute specifies that some function parameters should be non-null pointers. f the compiler determines that a null pointer is passed in an argument slot marked as non-null, and the -Wnonnull option is enabled, a warning is issued. All pointer arguments are marked as non-null +#define ATTR_NON_NULL __attribute__ ((nonull)) + +/// Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure +#define ATTR_PURE __attribute__ ((pure)) + +/// Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory. +/// Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void +#define ATTR_CONST __attribute__ ((const)) + +/// The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses +#define ATTR_DEPRECATED __attribute__ ((deprecated)) + +/// Same as the deprecated attribute with optional message in the warning +#define ATTR_DEPRECATED_MESS(mess) __attribute__ ((deprecated(mess))) + +/// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code +#define ATTR_WEAK __attribute__ ((weak)) + +/// The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified +#define ATTR_ALIAS(func) __attribute__ ((alias(#func))) + +/// The weakref attribute marks a declaration as a weak reference. It is equivalent with weak + alias attribute, but require function is static +#define ATTR_WEAKREF(func) __attribute__ ((weakref(#func))) + +/// The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug +#define ATTR_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) + +/// This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly. +#define ATTR_USED __attribute__ ((used)) + +/// This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function. +#define ATTR_UNUSED __attribute__ ((unused)) + +#elif defined (__ICCARM__) //IAR + #define ATTR_ALWAYS_INLINE // IAR dosn't provide such a syntax extension in function's prototypes. + #define ATTR_CONST // IAR dosn't provide such a syntax extension in function's prototypes. +#endif + +/** @} */ + +#ifdef __cplusplus + } +#endif + +#endif /* _COMPILER_GCC_H_ */ + +/// @} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.cpp new file mode 100644 index 0000000000..e6ff14a21b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.cpp @@ -0,0 +1,194 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include +#include + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/platform.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/memory_buffer_alloc.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ecp.h" + +#endif + +#include "platform/NonCopyable.h" +#include "platform/CriticalSectionLock.h" +#include "ble/BLETypes.h" +#include "cmsis.h" +#include "nRF5xCrypto.h" +#include "platform/mbed_assert.h" +#include "nrf_soc.h" + + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +#if defined(MBEDTLS_ECDH_C) + +CryptoToolbox::CryptoToolbox() : _initialized(false) { + mbedtls_entropy_init(&_entropy_context); + mbedtls_ecp_group_init(&_group); + int err = mbedtls_ecp_group_load( + &_group, + MBEDTLS_ECP_DP_SECP256R1 + ); + _initialized = err ? false : true; +} + +CryptoToolbox::~CryptoToolbox() { + mbedtls_ecp_group_free(&_group); + mbedtls_entropy_free(&_entropy_context); +} + +bool CryptoToolbox::generate_keys( + ArrayView X, + ArrayView Y, + ArrayView secret +) { + mbedtls_mpi secret_key; + mbedtls_ecp_point public_keys; + + mbedtls_mpi_init(&secret_key); + mbedtls_ecp_point_init(&public_keys); + + int err = mbedtls_ecp_gen_keypair( + &_group, + &secret_key, + &public_keys, + mbedtls_entropy_func, + &_entropy_context + ); + + if (!err) { + store_mpi(secret, secret_key); + store_mpi(X, public_keys.X); + store_mpi(Y, public_keys.Y); + } + + mbedtls_ecp_point_free(&public_keys); + mbedtls_mpi_free(&secret_key); + + return err ? false : true; +} + +bool CryptoToolbox::generate_shared_secret( + const ArrayView& peer_X, + const ArrayView& peer_Y, + const ArrayView& own_secret, + ArrayView shared_secret +) { + mbedtls_mpi result; + mbedtls_mpi secret_key; + mbedtls_ecp_point public_keys; + + mbedtls_mpi_init(&result); + mbedtls_mpi_init(&secret_key); + mbedtls_ecp_point_init(&public_keys); + + load_mpi(secret_key, own_secret); + load_mpi(public_keys.X, peer_X); + load_mpi(public_keys.Y, peer_Y); + mbedtls_mpi_lset( &public_keys.Z, 1 ); + + int err = mbedtls_ecdh_compute_shared( + &_group, + &result, + &public_keys, + &secret_key, + /* rng function; optional */ NULL, + /* rng param */ NULL + ); + + if (!err) { + store_mpi(shared_secret, result); + } + + mbedtls_ecp_point_free(&public_keys); + mbedtls_mpi_free(&secret_key); + mbedtls_mpi_free(&result); + + return err ? false : true; +} + +#endif + +bool CryptoToolbox::ah( + const ArrayView& irk, + const ArrayView& prand, + ArrayView hash +) { + // Note copy then swap operation can be optimized. + + // Note: the encryption block works in big endian; go figure. + nrf_ecb_hal_data_t ecb_hal_data; + + memcpy(ecb_hal_data.key, irk.data(), irk.size()); + swap_endian(ecb_hal_data.key, sizeof(ecb_hal_data.key)); + + memcpy(ecb_hal_data.cleartext, prand.data(), prand.size()); + memset(ecb_hal_data.cleartext + prand.size(), 0, sizeof(ecb_hal_data.cleartext) - prand.size()); + swap_endian(ecb_hal_data.cleartext, sizeof(ecb_hal_data.cleartext)); + + uint32_t err = sd_ecb_block_encrypt(&ecb_hal_data); + + if (err) { + return false; + } + + swap_endian(ecb_hal_data.ciphertext, sizeof(ecb_hal_data.ciphertext)); + + memcpy(hash.data(), ecb_hal_data.ciphertext, hash.size()); + + return true; +} + +#if defined(MBEDTLS_ECDH_C) + +void CryptoToolbox::load_mpi(mbedtls_mpi& dest, const ArrayView& src) { + ble::public_key_coord_t src_be = src.data(); + swap_endian(src_be.data(), src_be.size()); + mbedtls_mpi_read_binary(&dest, src_be.data(), src_be.size()); +} + +void CryptoToolbox::store_mpi(ArrayView& dest, const mbedtls_mpi& src) { + mbedtls_mpi_write_binary(&src, dest.data(), dest.size()); + swap_endian(dest.data(), dest.size()); +} + +#endif + +void CryptoToolbox::swap_endian(uint8_t* buf, size_t len) { + for(size_t low = 0, high = (len - 1); high > low; --high, ++low) { + std::swap(buf[low], buf[high]); + } +} + +} // nordic +} // vendor +} // pal +} // ble diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.h new file mode 100644 index 0000000000..123fac3564 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xCrypto.h @@ -0,0 +1,156 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NRF5X_CRYPTO_ +#define NRF5X_CRYPTO_ + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/platform.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ecp.h" + +#endif + +#include "platform/NonCopyable.h" +#include "ble/BLETypes.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +/** + * Toolbox of cryptographic functions used in BLE. + */ +class CryptoToolbox : mbed::NonCopyable { + +public: + /** + * Size of the Key used in lesc crypto operations. + */ + static const ptrdiff_t lesc_key_size_ = public_key_coord_t::size_; + + /** + * Size of an IRK. + */ + static const ptrdiff_t irk_size_ = irk_t::size_; + + /** + * Size of the hash generated by ah. + */ + static const ptrdiff_t hash_size_ = 3; + + /** + * Size of prand. + */ + static const ptrdiff_t prand_size_ = 3; + +#if defined(MBEDTLS_ECDH_C) + + /** + * Create a new CryptoToolbox. + */ + CryptoToolbox(); + + /** + * Destroy a CryptoTioolbox object. + */ + ~CryptoToolbox(); + + /** + * Generate lesc public and private keys. + * @param[out] X The component X of the public key. + * @param[out] Y The component Y of the public key. + * @param[out] secret The secret key. + * @return true if the shared secret has been successfully generated and + * false otherwise. + */ + bool generate_keys( + ArrayView X, + ArrayView Y, + ArrayView secret + ); + + /** + * Generate a shared secret from a peer public key and a local secret key. + * @param[in] peer_X The component X of the peer public key. + * @param[in] peer_Y The component Y of the peer public key. + * @param[in] own_secret The local secret key. + * @param[out] shared_secret The shared secret generated. + * @return true if the shared secret has been successfully generated and + * false otherwise. + */ + bool generate_shared_secret( + const ArrayView& peer_X, + const ArrayView& peer_Y, + const ArrayView& own_secret, + ArrayView shared_secret + ); + +#endif + + /** + * Execute the function ah. This function can be used to generate private + * resolvable addresses and resolve them. + * + * @note all parameters passed and return by this fucntion are in little + * endian. + * + * @param[in] irk The key used to create hash. + * @param[in] prand The random part from which the hash will be generated. + * @param[out] hash The hash generated. + * + * @return true in case of success and false otherwise. + */ + static bool ah( + const ArrayView& irk, + const ArrayView& prand, + ArrayView hash + ); + +private: + +#if defined(MBEDTLS_ECDH_C) + void load_mpi(mbedtls_mpi& dest, const ArrayView& src); + + void store_mpi(ArrayView& dest, const mbedtls_mpi& src); +#endif + + static void swap_endian(uint8_t* buf, size_t len); + +#if defined(MBEDTLS_ECDH_C) + bool _initialized; + mbedtls_entropy_context _entropy_context; + mbedtls_ecp_group _group; +#endif + +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif // NRF5X_CRYPTO_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.cpp new file mode 100644 index 0000000000..f4b0d393b2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.cpp @@ -0,0 +1,1427 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nRF5xn.h" +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#include "ble/BLE.h" + +#include "common/common.h" +#include "ble_advdata.h" +#include "headers/nrf_ble_hci.h" +#include "ble/pal/ConnectionEventMonitor.h" +#include "nRF5xPalSecurityManager.h" + +using ble::pal::vendor::nordic::nRF5xSecurityManager; +typedef nRF5xSecurityManager::resolving_list_entry_t resolving_list_entry_t; +using ble::ArrayView; +using ble::pal::advertising_peer_address_type_t; +using ble::peer_address_type_t; + +typedef BLEProtocol::AddressType LegacyAddressType; +typedef BLEProtocol::AddressType_t LegacyAddressType_t; + +namespace { + +nRF5xSecurityManager& get_sm() { + return nRF5xSecurityManager::get_security_manager(); +} + +ble_error_t set_private_resolvable_address() { + ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE }; + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); + return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; +} + +ble_error_t set_private_non_resolvable_address() { + ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE }; + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); + return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; +} + +bool is_advertising_non_connectable(const GapAdvertisingParams ¶ms) { + switch (params.getAdvertisingType()) { + case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED: + case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED: + return true; + default: + return false; + } +} + +bool is_identity_address(peer_address_type_t address_type) { + return address_type == peer_address_type_t::PUBLIC_IDENTITY || + address_type == peer_address_type_t::RANDOM_STATIC_IDENTITY; +} + +peer_address_type_t convert_nordic_address(uint8_t address) { + if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { + return peer_address_type_t::PUBLIC; + } else { + return peer_address_type_t::RANDOM; + } +} + +peer_address_type_t convert_identity_address(advertising_peer_address_type_t address) { + if (address == advertising_peer_address_type_t::PUBLIC) { + return peer_address_type_t::PUBLIC_IDENTITY; + } else { + return peer_address_type_t::RANDOM_STATIC_IDENTITY; + } +} + +} // namespace + +void radioNotificationStaticCallback(bool param) { + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + gap.processRadioNotificationEvent(param); +} + +nRF5xGap::nRF5xGap() : Gap(), + advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), + whitelistAddressesSize(0), + whitelistAddresses(), + radioNotificationCallbackParam(false), + radioNotificationTimeout(), + _connection_event_handler(NULL), + _privacy_enabled(false), + _peripheral_privacy_configuration(default_peripheral_privacy_configuration), + _central_privacy_configuration(default_central_privacy_configuration), + _non_private_address_type(LegacyAddressType::RANDOM_STATIC), + _connections_role() +{ + m_connectionHandle = BLE_CONN_HANDLE_INVALID; +} + +/**************************************************************************/ +/*! + @brief Sets the advertising parameters and payload for the device + + @param[in] params + Basic advertising details, including the advertising + delay, timeout and how the device should be advertised + @params[in] advData + The primary advertising data payload + @params[in] scanResponse + The optional Scan Response payload if the advertising + type is set to \ref GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED + in \ref GapAdveritinngParams + + @returns \ref ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @retval BLE_ERROR_BUFFER_OVERFLOW + The proposed action would cause a buffer overflow. All + advertising payloads must be <= 31 bytes, for example. + + @retval BLE_ERROR_NOT_IMPLEMENTED + A feature was requested that is not yet supported in the + nRF51 firmware or hardware. + + @retval BLE_ERROR_PARAM_OUT_OF_RANGE + One of the proposed values is outside the valid range. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) +{ + /* Make sure we don't exceed the advertising payload length */ + if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { + return BLE_ERROR_BUFFER_OVERFLOW; + } + + /* Make sure we have a payload! */ + if (advData.getPayloadLen() == 0) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Check the scan response payload limits */ + //if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED)) + //{ + // /* Check if we're within the upper limit */ + // if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) + // { + // return BLE_ERROR_BUFFER_OVERFLOW; + // } + // /* Make sure we have a payload! */ + // if (advData.getPayloadLen() == 0) + // { + // return BLE_ERROR_PARAM_OUT_OF_RANGE; + // } + //} + + /* Send advertising data! */ + ASSERT_TRUE(ERROR_NONE == + sd_ble_gap_adv_data_set(advData.getPayload(), + advData.getPayloadLen(), + scanResponse.getPayload(), + scanResponse.getPayloadLen()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + /* Make sure the GAP Service appearance value is aligned with the + *appearance from GapAdvertisingData */ + ASSERT_TRUE(ERROR_NONE == sd_ble_gap_appearance_set(advData.getAppearance()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + /* ToDo: Perform some checks on the payload, for example the Scan Response can't */ + /* contains a flags AD type, etc. */ + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Starts the BLE HW, initialising any services that were + added before this function was called. + + @note All services must be added before calling this function! + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) +{ + uint32_t err; + ble_gap_adv_params_t adv_para = {0}; + + /* Make sure we support the advertising type */ + if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) { + /* ToDo: This requires a propery security implementation, etc. */ + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /* Check interval range */ + if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) { + /* Min delay is slightly longer for unconnectable devices */ + if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) || + (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } else { + if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) || + (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } + + /* Check timeout is zero for Connectable Directed */ + if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) { + /* Timeout must be 0 with this type, although we'll never get here */ + /* since this isn't implemented yet anyway */ + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Check timeout for other advertising types */ + if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && + (params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + whitelist.addr_count = whitelistAddressesSize; + + for (uint32_t i = 0; i < whitelistAddressesSize; ++i) { + whitelistAddressPtrs[i] = &whitelistAddresses[i]; + } + + if (_privacy_enabled) { + if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) { + ArrayView entries = get_sm().get_resolving_list(); + + size_t limit = std::min( + entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE + ); + + for (size_t i = 0; i < limit; ++i) { + whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); + } + whitelist.irk_count = limit; + } + + if (_peripheral_privacy_configuration.use_non_resolvable_random_address && + is_advertising_non_connectable(params) + ) { + set_private_non_resolvable_address(); + } else { + set_private_resolvable_address(); + } + } + + adv_para.p_whitelist = &whitelist; +#endif + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + /* Start Advertising */ + adv_para.type = params.getAdvertisingType(); + adv_para.p_peer_addr = NULL; // Undirected advertisement + adv_para.fp = advertisingPolicyMode; + adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms) + adv_para.timeout = params.getTimeout(); + + err = sd_ble_gap_adv_start(&adv_para); + switch(err) { + case ERROR_NONE: + return BLE_ERROR_NONE; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) +ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams) +{ + ble_gap_scan_params_t scanParams; + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + whitelist.addr_count = whitelistAddressesSize; + + for (uint32_t i = 0; i < whitelistAddressesSize; ++i) { + whitelistAddressPtrs[i] = &whitelistAddresses[i]; + } + + if (_privacy_enabled) { + if (_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE) { + ArrayView entries = get_sm().get_resolving_list(); + + size_t limit = std::min( + entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE + ); + + for (size_t i = 0; i < limit; ++i) { + whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); + } + whitelist.irk_count = limit; + } + } + + scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ + scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ +#else + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + scanParams.use_whitelist = scanningPolicyMode; + scanParams.adv_dir_report = 0; +#endif + + scanParams.active = scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + + scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + + if (_privacy_enabled) { + if (_central_privacy_configuration.use_non_resolvable_random_address) { + set_private_non_resolvable_address(); + } else { + set_private_resolvable_address(); + } + } + + if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::stopScan(void) { + if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + return BLE_STACK_BUSY; +} +#endif + +/**************************************************************************/ +/*! + @brief Stops the BLE HW and disconnects from any devices + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::stopAdvertising(void) +{ + /* Stop Advertising */ + ASSERT_TRUE(ERROR_NONE == sd_ble_gap_adv_stop(), BLE_ERROR_PARAM_OUT_OF_RANGE); + + state.advertising = 0; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + peer_address_type_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn +) { + // NOTE: Nordic address type is an closer to LegacyAddressType: resolved + // address are treaded either as PUBLIC or RANDOM STATIC adresses. + // The idea is to get the conversion done here and call the legacy function. + + LegacyAddressType_t legacy_address; + + switch (peerAddrType.value()) { + case peer_address_type_t::PUBLIC: + case peer_address_type_t::PUBLIC_IDENTITY: + legacy_address = LegacyAddressType::PUBLIC; + break; + case peer_address_type_t::RANDOM_STATIC_IDENTITY: + legacy_address = LegacyAddressType::RANDOM_STATIC; + break; + case peer_address_type_t::RANDOM: { + RandomAddressType_t random_address_type(RandomAddressType_t::STATIC); + ble_error_t err = getRandomAddressType(peerAddr, &random_address_type); + if (err) { + return err; + } + switch (random_address_type.value()) { + case RandomAddressType_t::STATIC: + legacy_address = LegacyAddressType::RANDOM_STATIC; + break; + case RandomAddressType_t::NON_RESOLVABLE_PRIVATE: + legacy_address = LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE; + break; + case RandomAddressType_t::RESOLVABLE_PRIVATE: + legacy_address = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; + break; + default: + return BLE_ERROR_UNSPECIFIED; + } + } break; + default: + return BLE_ERROR_INVALID_PARAM; + } + + bool identity = + peerAddrType == peer_address_type_t::PUBLIC_IDENTITY || + peerAddrType == peer_address_type_t::RANDOM_STATIC_IDENTITY; + + return connect(peerAddr, legacy_address, connectionParams, scanParamsIn, identity); +} + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + LegacyAddressType_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn +) { + return connect(peerAddr, peerAddrType, connectionParams, scanParamsIn, /* identity */ false); +} + + + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + LegacyAddressType_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn, + bool identity +) { + ble_gap_addr_t addr; + ble_gap_addr_t* addr_ptr = &addr; + addr.addr_type = peerAddrType; + memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); + + ble_gap_conn_params_t connParams; + if (connectionParams != NULL) { + connParams.min_conn_interval = connectionParams->minConnectionInterval; + connParams.max_conn_interval = connectionParams->maxConnectionInterval; + connParams.slave_latency = connectionParams->slaveLatency; + connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; + } else { + connParams.min_conn_interval = 50; + connParams.max_conn_interval = 100; + connParams.slave_latency = 0; + connParams.conn_sup_timeout = 600; + } + + ble_gap_scan_params_t scanParams = { 0 }; + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ + scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ + + if (_privacy_enabled) { + if (_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE) { + ArrayView entries = get_sm().get_resolving_list(); + + size_t limit = std::min( + entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE + ); + + for (size_t i = 0; i < limit; ++i) { + whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); + } + whitelist.irk_count = limit; + + if (identity) { + scanParams.selective = true; + addr_ptr = NULL; + } + } + + set_private_resolvable_address(); + } +#else + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + scanParams.use_whitelist = (whitelistAddressesSize) ? 1 : 0; + + if ((addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) + || (addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)) { + /* If a device is using Resolvable Private Addresses Section 1.3.2.2 (Core spec v4.2 volume 6 part B), + it shall also have an Identity Address that is either a Public or Random Static address type. + To establish a connection, a static address must be provided by the application to the SoftDevice. + The SoftDevice resolves the address and connects to the right device if it is available. */ + addr.addr_id_peer = 1; + addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + } else { + addr.addr_id_peer = 0; + } + +#endif + + if (scanParamsIn != NULL) { + scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + } else { + scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + } + + uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams); + if (rc == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + switch (rc) { + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case BLE_ERROR_GAP_INVALID_BLE_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + case BLE_ERROR_GAP_WHITELIST_IN_USE: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t nRF5xGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) +{ + uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; + switch (reason) { + case REMOTE_USER_TERMINATED_CONNECTION: + code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; + break; + case CONN_INTERVAL_UNACCEPTABLE: + code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE; + break; + default: + break; + } + + /* Disconnect if we are connected to a central device */ + ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +/*! + @brief Disconnects if we are connected to a central device + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +ble_error_t nRF5xGap::disconnect(DisconnectionReason_t reason) +{ + return disconnect(m_connectionHandle, reason); +} + +ble_error_t nRF5xGap::getPreferredConnectionParams(ConnectionParams_t *params) +{ + ASSERT_INT(NRF_SUCCESS, + sd_ble_gap_ppcp_get(reinterpret_cast(params)), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setPreferredConnectionParams(const ConnectionParams_t *params) +{ + ASSERT_INT(NRF_SUCCESS, + sd_ble_gap_ppcp_set(reinterpret_cast(params)), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams) +{ + uint32_t rc; + + rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast(const_cast(newParams))); + if (rc == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/**************************************************************************/ +/*! + @brief Clear nRF5xGap's state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::reset(void) +{ + /* Clear all state that is from the parent, including private members */ + if (Gap::reset() != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_STATE; + } + + /* Clear derived class members */ + m_connectionHandle = BLE_CONN_HANDLE_INVALID; + + /* Set the whitelist policy filter modes to IGNORE_WHITELIST */ + advertisingPolicyMode = Gap::ADV_POLICY_IGNORE_WHITELIST; + scanningPolicyMode = Gap::SCAN_POLICY_IGNORE_WHITELIST; + + /* Clear the internal whitelist */ + whitelistAddressesSize = 0; + + /* Reset existing mapping between a connection and its role */ + release_all_connections_role(); + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Sets the 16-bit connection handle +*/ +/**************************************************************************/ +void nRF5xGap::setConnectionHandle(uint16_t con_handle) +{ + m_connectionHandle = con_handle; +} + +/**************************************************************************/ +/*! + @brief Gets the 16-bit connection handle +*/ +/**************************************************************************/ +uint16_t nRF5xGap::getConnectionHandle(void) +{ + return m_connectionHandle; +} + +/**************************************************************************/ +/*! + @brief Sets the BLE device address + + @returns ble_error_t + + @section EXAMPLE + + @code + + uint8_t device_address[6] = { 0xca, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0 }; + nrf.getGap().setAddress(Gap::BLEProtocol::AddressType::RANDOM_STATIC, device_address); + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAddress(LegacyAddressType_t type, const Address_t address) +{ + if (type != LegacyAddressType::PUBLIC && + type != LegacyAddressType::RANDOM_STATIC + ) { + return BLE_ERROR_INVALID_PARAM; + } + + if (_privacy_enabled) { + return BLE_ERROR_INVALID_STATE; + } + + ble_gap_addr_t dev_addr; + memcpy(dev_addr.addr, address, ADDR_LEN); + if (type == LegacyAddressType::PUBLIC) { + dev_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + } else { + dev_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; + } + +#if (NRF_SD_BLE_API_VERSION <= 2) + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr); +#else + uint32_t err = sd_ble_gap_addr_set(&dev_addr); +#endif + + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case BLE_ERROR_GAP_INVALID_BLE_ADDR: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address) +{ + if (typeP == NULL || address == NULL) { + return BLE_ERROR_INVALID_PARAM; + } + + ble_gap_addr_t dev_addr; +#if (NRF_SD_BLE_API_VERSION <= 2) + if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) { +#else + if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) { +#endif + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + switch (dev_addr.addr_type) { + case BLE_GAP_ADDR_TYPE_PUBLIC: + *typeP = LegacyAddressType::PUBLIC; + break; + + case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: + *typeP = LegacyAddressType::RANDOM_STATIC; + break; + + default: + return BLE_ERROR_INVALID_STATE; + } + + memcpy(address, dev_addr.addr, ADDR_LEN); + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setDeviceName(const uint8_t *deviceName) +{ + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed + + if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP) +{ + if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::setAppearance(GapAdvertisingData::Appearance appearance) +{ + if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::getAppearance(GapAdvertisingData::Appearance *appearanceP) +{ + if ((sd_ble_gap_appearance_get(reinterpret_cast(appearanceP)) == NRF_SUCCESS)) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ +ble_error_t nRF5xGap::setTxPower(int8_t txPower) +{ + unsigned rc; + if ((rc = sd_ble_gap_tx_power_set(txPower)) != NRF_SUCCESS) { + switch (rc) { + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_INVALID_PARAM: + default: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } + + return BLE_ERROR_NONE; +} + +void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) +{ +#if defined(NRF51) + static const int8_t permittedTxValues[] = { + -30, -20, -16, -12, -8, -4, 0, 4 + }; +#elif defined(NRF52) + static const int8_t permittedTxValues[] = { + -40, -20, -16, -12, -8, -4, 0, 4 + }; +#elif defined(NRF52840_XXAA) + static const int8_t permittedTxValues[] = { + -40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8, 9 + }; +#else +#error permitted TX power values unknown for this SOC +#endif + + *valueArrayPP = permittedTxValues; + *countP = sizeof(permittedTxValues) / sizeof(int8_t); +} + +/**************************************************************************/ +/*! + @brief Get the capacity of the internal whitelist maintained by this + implementation. + + @returns The capacity of the internal whitelist. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +uint8_t nRF5xGap::getMaxWhitelistSize(void) const +{ + return YOTTA_CFG_WHITELIST_MAX_SIZE; +} + +/**************************************************************************/ +/*! + @brief Get a copy of the implementation's internal whitelist. + + @param[out] whitelistOut + A \ref Gap::Whitelist_t structure containing a copy of the + addresses in the implemenetation's internal whitelist. + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const +{ + uint32_t i; + for (i = 0; i < whitelistAddressesSize && i < whitelistOut.capacity; ++i) { + memcpy( &whitelistOut.addresses[i].address, &whitelistAddresses[i].addr, sizeof(whitelistOut.addresses[0].address)); + whitelistOut.addresses[i].type = static_cast (whitelistAddresses[i].addr_type); + } + whitelistOut.size = i; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the whitelist that will be used in the next call to + startAdvertising(). + + @param[in] whitelistIn + A reference to a \ref Gap::Whitelist_t structure + representing a whitelist containing all the white listed + BLE addresses. + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_INVALID_PARAM + The supplied whitelist contains a private non-resolvable + address + + BLE_ERROR_PARAM_OUT_OF_RANGE + The size of the supplied whitelist exceeds the maximum + capacity of the implementation's internal whitelist. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) +{ + if (whitelistIn.size > getMaxWhitelistSize()) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Test for invalid parameters before we change the internal state */ + for (uint32_t i = 0; i < whitelistIn.size; ++i) { + if (whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE || + whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE + ) { + /* This is not allowed because it is completely meaningless */ + return BLE_ERROR_INVALID_PARAM; + } + } + + whitelistAddressesSize = whitelistIn.size; + + for (uint32_t i = 0; i < whitelistIn.size; ++i) { + memcpy(&whitelistAddresses[i].addr , &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr)); + whitelistAddresses[i].addr_type = static_cast (whitelistIn.addresses[i].type); + } + +#if (NRF_SD_BLE_API_VERSION >= 3) + updateWhiteAndIdentityListInStack(); +#endif + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the advertising policy filter mode that will be used in + the next call to startAdvertising(). + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) +{ + advertisingPolicyMode = mode; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the scanning policy filter mode that will be used in + the next call to startAdvertising(). + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) +{ + scanningPolicyMode = mode; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the initiator policy filter mode that will be used in + the next call to startAdvertising() + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) +{ + return BLE_ERROR_NOT_IMPLEMENTED; +} + +/**************************************************************************/ +/*! + @brief Get the current advertising policy filter mode. + + @returns The advertising policy filter mode. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const +{ + return advertisingPolicyMode; +} + +/**************************************************************************/ +/*! + @brief Get the current scanning policy filter mode. + + @returns The scanning policy filter mode. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const +{ + return scanningPolicyMode; +} + +/**************************************************************************/ +/*! + @brief Get the current initiator policy filter mode. + + @returns The initiator policy filter mode. + + @note Currently initiator filtering using the whitelist is not + implemented in this module. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const +{ + return Gap::INIT_POLICY_IGNORE_WHITELIST; +} + +ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy) +{ + if (enable_privacy == _privacy_enabled) { + return BLE_ERROR_NONE; + } + + ble_error_t err = BLE_ERROR_UNSPECIFIED; + if (enable_privacy == false) { + err = setAddress(_non_private_address_type, _non_private_address); + } else { + err = getAddress(&_non_private_address_type, _non_private_address); + } + + if (err) { + return err; + } + +#if (NRF_SD_BLE_API_VERSION > 2) + ble_gap_privacy_params_t privacy_config = { 0 }; + if (sd_ble_gap_privacy_get(&privacy_config)) { + return BLE_ERROR_UNSPECIFIED; + } + + privacy_config.privacy_mode = enable_privacy ? + BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY : + BLE_GAP_PRIVACY_MODE_OFF; + if (sd_ble_gap_privacy_set(&privacy_config)) { + return BLE_ERROR_UNSPECIFIED; + } +#endif + + _privacy_enabled = enable_privacy; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setPeripheralPrivacyConfiguration( + const PeripheralPrivacyConfiguration_t *configuration +) { + _peripheral_privacy_configuration = *configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::getPeripheralPrivacyConfiguration( + PeripheralPrivacyConfiguration_t *configuration +) { + *configuration = _peripheral_privacy_configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setCentralPrivacyConfiguration( + const CentralPrivacyConfiguration_t *configuration +) { + _central_privacy_configuration = *configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::getCentralPrivacyConfiguration( + CentralPrivacyConfiguration_t *configuration +) { + *configuration = _central_privacy_configuration; + return BLE_ERROR_NONE; +} + +void nRF5xGap::set_connection_event_handler( + ConnectionEventMonitor::EventHandler* connection_event_handler +) { + _connection_event_handler = connection_event_handler; +} + +void nRF5xGap::processDisconnectionEvent( + Handle_t handle, + DisconnectionReason_t reason +) { + release_connection_role(handle); + + if (_connection_event_handler) { + _connection_event_handler->on_disconnected( + handle, + reason + ); + } + + ::Gap::processDisconnectionEvent( + handle, + reason + ); +} + +void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t& evt) { + using BLEProtocol::AddressType; + + // set the new connection handle as the _default_ handle in gap + setConnectionHandle(handle); + + // add the connection and the role of the device in the local table + allocate_connection_role(handle, static_cast(evt.role)); + + // deal with own address + LegacyAddressType_t own_addr_type; + Address_t own_address; + const uint8_t* own_resolvable_address = NULL; + +#if (NRF_SD_BLE_API_VERSION <= 2) + if (_privacy_enabled) { + own_addr_type = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; + } else { + if (evt.own_addr.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) { + own_addr_type = LegacyAddressType::PUBLIC; + } else { + own_addr_type = LegacyAddressType::RANDOM_STATIC; + } + } + + // FIXME: is it the resolvable address or the identity address ? + memcpy(own_address, evt.own_addr.addr, sizeof(own_address)); +#else + gap.getAddress(&addr_type, own_address); +#endif + + // deal with the peer address: If privacy is enabled then the softdevice + // indicates if the address has been resolved or not. If the address has + // been resolved then the identity address should be passed to the application. + // Depending on the privacy chosen by the application, connection request + // from privacy enabled peers may trigger a disconnection, the pairing procedure + // or the authentication procedure. + peer_address_type_t peer_addr_type(peer_address_type_t::PUBLIC); + const uint8_t* peer_address; + const uint8_t* peer_resolvable_address; + +#if (NRF_SD_BLE_API_VERSION <= 2) + bool private_peer_known = evt.irk_match; + + // thanks to softdevice consistencies; addresses are not resolved on the + // peripheral side ... + if (_privacy_enabled && + evt.role == BLE_GAP_ROLE_PERIPH && + _peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE && + get_sm().resolve_address(evt.peer_addr.addr) != NULL + ) { + private_peer_known = true; + } +#else + bool private_peer_known = evt.peer_addr.addr_id_peer; +#endif + + if (private_peer_known) { + const resolving_list_entry_t* entry = get_sm().resolve_address( + evt.peer_addr.addr + ); + MBED_ASSERT(entry != NULL); + + peer_addr_type = convert_identity_address(entry->peer_identity_address_type); + peer_address = entry->peer_identity_address.data(); + peer_resolvable_address = evt.peer_addr.addr; + } else { + if (_privacy_enabled && + evt.role == BLE_GAP_ROLE_PERIPH && + _peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && + get_sm().get_resolving_list().size() > 0 + ) { + // FIXME: should use BLE_HCI_AUTHENTICATION_FAILURE; not possible + // with the softdevice ... + sd_ble_gap_disconnect(handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + return; + } + + peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); + peer_address = evt.peer_addr.addr; + peer_resolvable_address = NULL; + } + + // notify internal event handler before applying the resolution strategy + if (_connection_event_handler) { + _connection_event_handler->on_connected( + handle, + static_cast(evt.role), + peer_addr_type, + peer_address, + own_addr_type, + own_address, + reinterpret_cast(&(evt.conn_params)) + ); + } + + // Apply authentication strategy before application notification + if (!private_peer_known && + _privacy_enabled && + evt.role == BLE_GAP_ROLE_PERIPH && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + ) { + switch (_peripheral_privacy_configuration.resolution_strategy) { + case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE: + nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getSecurityManager().requestAuthentication(handle); + break; + + case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE: + // FIXME: lookup secure DB to know what to do. + break; + + default: + break; + } + } + + processConnectionEvent( + handle, + static_cast(evt.role), + peer_addr_type, + peer_address, + own_addr_type, + own_address, + reinterpret_cast(&(evt.conn_params)), + peer_resolvable_address, + own_resolvable_address + ); +} + +void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { + peer_address_type_t peer_addr_type(peer_address_type_t::PUBLIC); + const uint8_t* peer_address = evt.peer_addr.addr; + + if (_privacy_enabled && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && + _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE + ) { + using ble::pal::vendor::nordic::nRF5xSecurityManager; + + const resolving_list_entry_t* entry = get_sm().resolve_address( + peer_address + ); + + if (entry) { + peer_address = entry->peer_identity_address.data(); + peer_addr_type = convert_identity_address(entry->peer_identity_address_type); + } else if (_central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD || + get_sm().get_resolving_list().size() == 0 + ) { + peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); + } else { + // filter out the packet. + return; + } + } else { + peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); + } + + processAdvertisementReport( + peer_address, + evt.rssi, + evt.scan_rsp, + static_cast(evt.type), + evt.dlen, + evt.data, + peer_addr_type + ); +} + +ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + role = c.is_peripheral ? PERIPHERAL : CENTRAL; + return BLE_ERROR_NONE; + } + } + + return BLE_ERROR_INVALID_PARAM; +} + +void nRF5xGap::allocate_connection_role( + ble::connection_handle_t connection, + Role_t role +) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated == false) { + c.connection = connection; + c.is_peripheral = (role == Gap::PERIPHERAL); + c.is_allocated = true; + return; + } + } +} +void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + c.is_allocated = false; + return; + } + } +} + +void nRF5xGap::release_all_connections_role() { + for (size_t i = 0; i < max_connections_count; ++i) { + _connections_role[i].is_allocated = false; + } +} + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.h new file mode 100644 index 0000000000..ecdf770fe2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGap.h @@ -0,0 +1,318 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF5x_GAP_H__ +#define __NRF5x_GAP_H__ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#ifndef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT + #undef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#endif +#ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #if (NRF_SD_BLE_API_VERSION >= 3) + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT + #else + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT + #endif +#elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT + #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#endif +#include "ble/blecommon.h" +#include "headers/nrf_ble.h" +#include "ble/GapAdvertisingParams.h" +#include "ble/GapAdvertisingData.h" +#include "ble/Gap.h" +#include "ble/GapScanningParams.h" +#include "ble/pal/ConnectionEventMonitor.h" + +#include "nrf_soc.h" + +extern "C" { +#include "ble_radio_notification.h" +#include "app_util_platform.h" +} + +void radioNotificationStaticCallback(bool param); + +/**************************************************************************/ +/*! + \brief + +*/ +/**************************************************************************/ +class nRF5xGap : public ::Gap, public ble::pal::ConnectionEventMonitor { +public: + nRF5xGap(); + + virtual ~nRF5xGap() { } + + /* Functions that must be implemented from Gap */ + virtual ble_error_t setAddress(AddressType_t type, const Address_t address); + virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); + virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); + + virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} + virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN);} + virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} + + virtual ble_error_t startAdvertising(const GapAdvertisingParams &); + virtual ble_error_t stopAdvertising(void); + virtual ble_error_t connect(const Address_t, ble::peer_address_type_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); + virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); + ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams, bool identity); + virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); + virtual ble_error_t disconnect(DisconnectionReason_t reason); + + virtual ble_error_t setDeviceName(const uint8_t *deviceName); + virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); + virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); + virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); + + virtual ble_error_t setTxPower(int8_t txPower); + virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); + + void setConnectionHandle(uint16_t con_handle); + uint16_t getConnectionHandle(void); + + virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); + virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); + virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); + + virtual ble_error_t reset(void); + + /* + * The following functions are part of the whitelisting experimental API. + * Therefore, this functionality can change in the near future. + */ + virtual uint8_t getMaxWhitelistSize(void) const; + virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; + virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); + + virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); + virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); + virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); + virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; + virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; + virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; + + virtual ble_error_t initRadioNotification(void) { + if (ble_radio_notification_init(APP_IRQ_PRIORITY_HIGH /*MID*/, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + return BLE_ERROR_UNSPECIFIED; + } + + virtual ble_error_t enablePrivacy(bool enable); + + virtual ble_error_t setPeripheralPrivacyConfiguration( + const PeripheralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t getPeripheralPrivacyConfiguration( + PeripheralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t setCentralPrivacyConfiguration( + const CentralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t getCentralPrivacyConfiguration( + CentralPrivacyConfiguration_t *configuration + ); + +/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); + virtual ble_error_t stopScan(void); +#endif + +private: + /* + * Whitelisting API related structures and helper functions. + */ + + /* Policy modes set by the user. By default these are set to ignore the whitelist */ + Gap::AdvertisingPolicyMode_t advertisingPolicyMode; + Gap::ScanningPolicyMode_t scanningPolicyMode; + + /* Internal representation of a whitelist */ + uint8_t whitelistAddressesSize; + ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; + +private: + bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ + Timeout radioNotificationTimeout; + + /* + * A helper function to post radio notification callbacks with low interrupt priority. + */ + void postRadioNotificationCallback(void) { +#ifdef YOTTA_CFG_MBED_OS + /* + * In mbed OS, all user-facing BLE events (interrupts) are posted to the + * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards + * its critical sections from interrupts by acquiring CriticalSectionLock, + * which results in a call to sd_nvic_critical_region_enter(). Thus, it is + * safe to invoke MINAR APIs from interrupt context as long as those + * interrupts are blocked by sd_nvic_critical_region_enter(). + * + * Radio notifications are a special case for the above. The Radio + * Notification IRQ is handled at a very high priority--higher than the + * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification + * events can preempt MINAR's critical sections. Using MINAR APIs (such as + * posting an event) directly in processRadioNotification() may result in a + * race condition ending in a hard-fault. + * + * The solution is to *not* call MINAR APIs directly from the Radio + * Notification handling; i.e. to do the bulk of RadioNotification + * processing at a reduced priority which respects MINAR's critical + * sections. Unfortunately, on a cortex-M0, there is no clean way to demote + * priority for the currently executing interrupt--we wouldn't want to + * demote the radio notification handling anyway because it is sensitive to + * timing, and the system expects to finish this handling very quickly. The + * workaround is to employ a Timeout to trigger + * postRadioNotificationCallback() after a very short delay (~0 us) and post + * the MINAR callback that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + minar::Scheduler::postCallback( + mbed::util::FunctionPointer1(&radioNotificationCallback, &FunctionPointerWithContext::call).bind(radioNotificationCallbackParam) + ); +#else + /* + * In mbed classic, all user-facing BLE events execute callbacks in interrupt + * mode. Radio Notifications are a special case because its IRQ is handled at + * a very high priority. Thus Radio Notification events can preempt other + * operations that require interaction with the SoftDevice such as advertising + * payload updates and changing the Gap state. Therefore, executing a Radio + * Notification callback directly from processRadioNotification() may result + * in a race condition ending in a hard-fault. + * + * The solution is to *not* execute the Radio Notification callback directly + * from the Radio Notification handling; i.e. to do the bulk of the + * Radio Notification processing at a reduced priority. Unfortunately, on a + * cortex-M0, there is no clean way to demote priority for the currently + * executing interrupt--we wouldn't want to demote the radio notification + * handling anyway because it is sensitive to timing, and the system expects + * to finish this handling very quickly. The workaround is to employ a Timeout + * to trigger postRadioNotificationCallback() after a very short delay (~0 us) + * and execute the callback in that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + radioNotificationCallback.call(radioNotificationCallbackParam); +#endif /* #ifdef YOTTA_CFG_MBED_OS */ + } + + /** + * A helper function to process radio-notification events; to be called internally. + * @param param [description] + */ + void processRadioNotificationEvent(bool param) { + radioNotificationCallbackParam = param; + radioNotificationTimeout.attach_us(mbed::callback(this, &nRF5xGap::postRadioNotificationCallback), 0); + } + friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ + +public: + /** @note Implements ConnectionEventMonitor. + * @copydoc ConnectionEventMonitor::set_connection_event_handler + */ + virtual void set_connection_event_handler( + ConnectionEventMonitor::EventHandler* connection_event_handler + ); + + /** + * @copydoc ::Gap::processDisconnectionEvent + */ + void processDisconnectionEvent( + Handle_t handle, + DisconnectionReason_t reason + ); + + /** + * Return the role of the local peripheral for a given connection. + * + * @param[in] connection The connection queried. + * @param[out] role The role of the local device in the connection. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + ble_error_t get_role(ble::connection_handle_t connection, Role_t& role); + +private: + friend void btle_handler(ble_evt_t *p_ble_evt); + + void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt); + void on_advertising_packet(const ble_gap_evt_adv_report_t &evt); + + void allocate_connection_role(ble::connection_handle_t, Role_t); + void release_connection_role(ble::connection_handle_t); + void release_all_connections_role(); + + uint16_t m_connectionHandle; + + ConnectionEventMonitor::EventHandler* _connection_event_handler; + + bool _privacy_enabled; + PeripheralPrivacyConfiguration_t _peripheral_privacy_configuration; + CentralPrivacyConfiguration_t _central_privacy_configuration; + AddressType_t _non_private_address_type; + Address_t _non_private_address; + + struct connection_role_t { + connection_role_t() : + connection(), + is_peripheral(false), + is_allocated(false) + { } + + ble::connection_handle_t connection; + uint8_t is_peripheral:1; + uint8_t is_allocated:1; + }; + + static const size_t max_connections_count = + NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT; + + connection_role_t _connections_role[max_connections_count]; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGap(nRF5xGap const &); + void operator=(nRF5xGap const &); +}; + +#endif // ifndef __NRF5x_GAP_H__ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.cpp new file mode 100644 index 0000000000..4963145059 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.cpp @@ -0,0 +1,856 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nRF5xGattServer.h" +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif + +#include "common/common.h" +#include "btle/custom/custom_helper.h" + +#include "nRF5xn.h" +#include "nrf_ble_gap.h" + +namespace { + +static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID_OFFSET + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS, + /* .update = */ 0 + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID + } + } +}; + +static ble_error_t set_attribute_value( + Gap::Handle_t connectionHandle, + GattAttribute::Handle_t attributeHandle, + ble_gatts_value_t *value +) { + uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, value); + switch(err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_NOT_FOUND: + case NRF_ERROR_DATA_SIZE: + case BLE_ERROR_INVALID_CONN_HANDLE: + case BLE_ERROR_GATTS_INVALID_ATTR_TYPE: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case NRF_ERROR_FORBIDDEN: + return BLE_ERROR_OPERATION_NOT_PERMITTED; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +} // end of anonymous namespace + +/**************************************************************************/ +/*! + @brief Adds a new service to the GATT table on the peripheral + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::addService(GattService &service) +{ + /* ToDo: Make sure this service UUID doesn't already exist (?) */ + /* ToDo: Basic validation */ + + /* Add the service to the nRF51 */ + ble_uuid_t nordicUUID; + nordicUUID = custom_convert_to_nordic_uuid(service.getUUID()); + + uint16_t serviceHandle; + ASSERT_TRUE( ERROR_NONE == + sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, + &nordicUUID, + &serviceHandle), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + service.setHandle(serviceHandle); + + /* Add characteristics to the service */ + for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) { + if (characteristicCount >= BLE_TOTAL_CHARACTERISTICS) { + return BLE_ERROR_NO_MEM; + } + GattCharacteristic *p_char = service.getCharacteristic(i); + GattAttribute *p_description_descriptor = NULL; + GattAttribute *p_presentation_format_descriptor = NULL; + + /* Skip any incompletely defined, read-only characteristics. */ + if ((p_char->getValueAttribute().getValuePtr() == NULL) && + (p_char->getValueAttribute().getLength() == 0) && + (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) { + continue; + } + + nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID()); + + /* The user-description and presentation-format descriptors are special cases + * that need to be handled at the time of adding each characteristic. The + * following block is meant to discover their presence. */ + const uint8_t *userDescriptionDescriptorValuePtr = NULL; + uint16_t userDescriptionDescriptorValueLen = 0; + const uint8_t *presentationFormatDescriptorValuePtr = NULL; + uint16_t presentationFormatDescriptorValueLen = 0; + for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) { + GattAttribute *p_desc = p_char->getDescriptor(j); + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) { + p_description_descriptor = p_desc; + userDescriptionDescriptorValuePtr = p_desc->getValuePtr(); + userDescriptionDescriptorValueLen = p_desc->getLength(); + } + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) { + p_presentation_format_descriptor = p_desc; + presentationFormatDescriptorValuePtr = p_desc->getValuePtr(); + presentationFormatDescriptorValueLen = p_desc->getLength(); + } + } + + ASSERT_TRUE ( ERROR_NONE == + custom_add_in_characteristic( + BLE_GATT_HANDLE_INVALID, + &nordicUUID, + p_char->getProperties(), + p_char->getReadSecurityRequirement(), + p_char->getWriteSecurityRequirement(), + p_char->getUpdateSecurityRequirement(), + p_char->getValueAttribute().getValuePtr(), + p_char->getValueAttribute().getLength(), + p_char->getValueAttribute().getMaxLength(), + p_char->getValueAttribute().hasVariableLength(), + userDescriptionDescriptorValuePtr, + userDescriptionDescriptorValueLen, + presentationFormatDescriptorValuePtr, + presentationFormatDescriptorValueLen, + p_char->isReadAuthorizationEnabled(), + p_char->isWriteAuthorizationEnabled(), + &nrfCharacteristicHandles[characteristicCount] + ), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + + /* Update the characteristic handle */ + p_characteristics[characteristicCount] = p_char; + p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle); + if (p_description_descriptor) { + p_description_descriptor->setHandle( + nrfCharacteristicHandles[characteristicCount].user_desc_handle + ); + } + if (p_presentation_format_descriptor) { + // The handle is not available from the SoftDevice + p_presentation_format_descriptor->setHandle(GattAttribute::INVALID_HANDLE); + } + characteristicCount++; + + /* Add optional descriptors if any */ + for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) { + if (descriptorCount >= BLE_TOTAL_DESCRIPTORS) { + return BLE_ERROR_NO_MEM; + } + + GattAttribute *p_desc = p_char->getDescriptor(j); + /* skip the user-description or presentation-format descriptor here; + * they have already been handled when adding the characteristic (above). */ + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC + || p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) { + continue; + } + + nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID()); + + ASSERT_TRUE(ERROR_NONE == + custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID, + &nordicUUID, + p_desc->getValuePtr(), + p_desc->getLength(), + p_desc->getMaxLength(), + p_desc->hasVariableLength(), + &nrfDescriptorHandles[descriptorCount], + p_desc->getReadSecurityRequirement(), + p_desc->getWriteSecurityRequirement()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + p_descriptors[descriptorCount] = p_desc; + p_desc->setHandle(nrfDescriptorHandles[descriptorCount]); + descriptorCount++; + } + } + + serviceCount++; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Reads the value of a characteristic, based on the service + and characteristic index fields + + @param[in] attributeHandle + The handle of the GattCharacteristic to read from + @param[in] buffer + Buffer to hold the the characteristic's value + (raw byte array in LSB format) + @param[in/out] len + input: Length in bytes to be read. + output: Total length of attribute value upon successful return. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) +{ + return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP); +} + +ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) +{ + ble_gatts_value_t value = { + /* .len = */ *lengthP, + /* .offset = */ 0, + /* .p_value = */ buffer, + }; + + ASSERT_TRUE( ERROR_NONE == + sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE); + *lengthP = value.len; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Updates the value of a characteristic, based on the service + and characteristic index fields + + @param[in] charHandle + The handle of the GattCharacteristic to write to + @param[in] buffer + Data to use when updating the characteristic's value + (raw byte array in LSB format) + @param[in] len + The number of bytes in buffer + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) +{ + return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly); +} + +ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) +{ + ble_error_t returnValue = BLE_ERROR_NONE; + + ble_gatts_value_t value = { + /* .len = */ len, + /* .offset = */ 0, + /* .p_value = */ const_cast(buffer), + }; + + if (localOnly) { + /* Only update locally regardless of notify/indicate */ + ASSERT_INT( ERROR_NONE, + sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + return BLE_ERROR_NONE; + } + + int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); + if ((characteristicIndex != -1) && + (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { + /* HVX update for the characteristic value */ + ble_gatts_hvx_params_t hvx_params; + + hvx_params.handle = attributeHandle; + hvx_params.type = + (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; + hvx_params.offset = 0; + hvx_params.p_data = const_cast(buffer); + hvx_params.p_len = &len; + + if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */ + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + connectionHandle = gap.getConnectionHandle(); + } + + bool updatesEnabled = false; + if (connectionHandle != BLE_CONN_HANDLE_INVALID) { + ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled); + + // FIXME: The softdevice allocates and populates CCCD when the client + // interract with them. Checking for updates may return an out of + // range error in such case. + if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) { + return err; + } + } + + bool updates_permitted = false; + ble_gap_conn_sec_t connection_security; + uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security); + if (!err && + (connection_security.sec_mode.sm == 1) && + (connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) { + updates_permitted = true; + } + + if (updatesEnabled && updates_permitted) { + error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); + if (error != ERROR_NONE) { + switch (error) { + case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */ + case ERROR_BUSY: + returnValue = BLE_STACK_BUSY; + break; + + case ERROR_INVALID_STATE: + case ERROR_BLEGATTS_SYS_ATTR_MISSING: + returnValue = BLE_ERROR_INVALID_STATE; + break; + + default : + ASSERT_INT( ERROR_NONE, + sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + + /* Notifications consume application buffers. The return value can + * be used for resending notifications. */ + returnValue = BLE_STACK_BUSY; + break; + } + } + } else { + returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); + } + } else { + returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); + } + + return returnValue; +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) +{ + /* Forward the call with the default connection handle. */ + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + return areUpdatesEnabled(gap.getConnectionHandle(), characteristic, enabledP); +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) +{ + return areUpdatesEnabled(connectionHandle, characteristic.getValueHandle(), enabledP); +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, bool *enabledP) +{ + int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); + if (characteristicIndex == -1) { + return BLE_ERROR_INVALID_PARAM; + } + + /* Read the cccd value from the GATT server. */ + GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle; + uint16_t cccdValue; + uint16_t length = sizeof(cccdValue); + ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast(&cccdValue), &length); + if (rc != BLE_ERROR_NONE) { + return rc; + } + if (length != sizeof(cccdValue)) { + return BLE_ERROR_INVALID_STATE; + } + + /* Check for NOTFICATION or INDICATION in CCCD. */ + if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) { + *enabledP = true; + } + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Clear nRF5xGattServer's state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::reset(void) +{ + /* Clear all state that is from the parent, including private members */ + if (GattServer::reset() != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_STATE; + } + + /* Clear derived class members */ + memset(p_characteristics, 0, sizeof(p_characteristics)); + memset(p_descriptors, 0, sizeof(p_descriptors)); + memset(nrfCharacteristicHandles, 0, sizeof(ble_gatts_char_handles_t)); + memset(nrfDescriptorHandles, 0, sizeof(nrfDescriptorHandles)); + descriptorCount = 0; + + releaseAllWriteRequests(); + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Callback handler for events getting pushed up from the SD +*/ +/**************************************************************************/ +void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt) +{ + GattAttribute::Handle_t handle_value; + GattServerEvents::gattEvent_t eventType; + const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; + + switch (p_ble_evt->header.evt_id) { + case BLE_GATTS_EVT_WRITE: { + /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ + + /* 1.) Handle CCCD changes */ + handle_value = gattsEventP->params.write.handle; + int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); + if ((characteristicIndex != -1) && + (p_characteristics[characteristicIndex]->getProperties() & + (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { + + uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ + + if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || + ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { + eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; + } else { + eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; + } + + handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); + return; + } + + /* 2.) Changes to the characteristic value will be handled with other events below */ + eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; + } + break; + + case BLE_GATTS_EVT_HVC: + /* Indication confirmation received */ + eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; + handle_value = gattsEventP->params.hvc.handle; + break; + + case BLE_EVT_TX_COMPLETE: { + handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); + return; + } + + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); + return; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + switch (gattsEventP->params.authorize_request.type) { + case BLE_GATTS_AUTHORIZE_TYPE_READ: + eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; + handle_value = gattsEventP->params.authorize_request.request.read.handle; + break; + case BLE_GATTS_AUTHORIZE_TYPE_WRITE: + eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; + handle_value = gattsEventP->params.authorize_request.request.write.handle; + break; + default: + return; + } + break; + + case BLE_EVT_USER_MEM_REQUEST: { + uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle; + + // allocate a new long request for this connection + // NOTE: we don't care about the result at this stage, + // it is not possible to cancel the operation anyway. + // If the request was not allocated then it will gracefully failled + // at subsequent stages. + allocateLongWriteRequest(conn_handle); + sd_ble_user_mem_reply(conn_handle, NULL); + return; + } + + default: + return; + } + + int characteristicIndex = resolveValueHandleToCharIndex(handle_value); + if (characteristicIndex == -1) { + // filter out the case were the request is a long one, + // and there is no attribute handle provided + uint8_t write_op = gattsEventP->params.authorize_request.request.write.op; + if (eventType != GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ || + (write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW && + write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { + return; + } + } + + /* Find index (charHandle) in the pool */ + switch (eventType) { + case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { + GattWriteCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .writeOp = */ static_cast(gattsEventP->params.write.op), + /* .offset = */ gattsEventP->params.write.offset, + /* .len = */ gattsEventP->params.write.len, + /* .data = */ gattsEventP->params.write.data + }; + handleDataWrittenEvent(&cbParams); + break; + } + case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { + uint16_t conn_handle = gattsEventP->conn_handle; + const ble_gatts_evt_write_t& input_req = gattsEventP->params.authorize_request.request.write; + const uint16_t max_size = getBiggestCharacteristicSize(); + + // this is a long write request, handle it here. + switch (input_req.op) { + case BLE_GATTS_OP_PREP_WRITE_REQ: { + // verify that the request is not outside of the possible range + if ((input_req.offset + input_req.len) > max_size) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // find the write request + long_write_request_t* req = findLongWriteRequest(conn_handle); + if (!req) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + return; + } + + // initialize the first request by setting the offset + if (req->length == 0) { + req->attr_handle = input_req.handle; + req->offset = input_req.offset; + } else { + // it should be the subsequent write + if ((req->offset + req->length) != input_req.offset) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // it is not allowed to write multiple characteristic with the same request + if (input_req.handle != req->attr_handle) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + } + + // start the copy of what is in input + memcpy(req->data + req->length, input_req.data, input_req.len); + + // update the lenght of the data written + req->length = req->length + input_req.len; + + // success, signal it to the softdevice + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS, + /* .update = */ 1, + /* .offset = */ input_req.offset, + /* .len = */ input_req.len, + /* .p_data = */ input_req.data + } + } + }; + + sd_ble_gatts_rw_authorize_reply(conn_handle, &reply); + } return; + + case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: { + releaseLongWriteRequest(conn_handle); + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); + } return; + + case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: { + long_write_request_t* req = findLongWriteRequest(conn_handle); + if (!req) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + return; + } + + GattWriteAuthCallbackParams cbParams = { + /* .connHandle = */ conn_handle, + /* .handle = */ req->attr_handle, + /* .offset = */ req->offset, + /* .len = */ req->length, + /* .data = */ req->data, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams); + + // the user code didn't provide the write authorization, + // just leave here. + if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) { + // report the status of the operation in any cases + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // FIXME can't use ::write here, this function doesn't take the offset into account ... + ble_gatts_value_t value = { + /* .len = */ req->length, + /* .offset = */ req->offset, + /* .p_value = */ req->data + }; + uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value); + if (update_err) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); + + GattWriteCallbackParams writeParams = { + /* .connHandle = */ conn_handle, + /* .handle = */ req->attr_handle, + /* .writeOp = */ static_cast(input_req.op), + /* .offset = */ req->offset, + /* .len = */ req->length, + /* .data = */ req->data, + }; + handleDataWrittenEvent(&writeParams); + releaseLongWriteRequest(conn_handle); + } return; + } + + GattWriteAuthCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, + /* .len = */ gattsEventP->params.authorize_request.request.write.len, + /* .data = */ gattsEventP->params.authorize_request.request.write.data, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams), + /* .update = */ 1, + /* .offset = */ cbParams.offset, + /* .len = */ cbParams.len, + /* .p_data = */ cbParams.data + } + } + }; + + if (reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) + { + reply.params.write.update = 0; + } + + sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); + + /* + * If write-authorization is enabled for a characteristic, + * AUTHORIZATION_REQ event (if replied with true) is *not* + * followed by another DATA_WRITTEN event; so we still need + * to invoke handleDataWritten(), much the same as we would + * have done if write-authorization had not been enabled. + */ + if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { + GattWriteCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .writeOp = */ static_cast(gattsEventP->params.authorize_request.request.write.op), + /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, + /* .len = */ gattsEventP->params.authorize_request.request.write.len, + /* .data = */ gattsEventP->params.authorize_request.request.write.data, + }; + handleDataWrittenEvent(&cbParams); + } + break; + } + case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { + GattReadAuthCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .offset = */ gattsEventP->params.authorize_request.request.read.offset, + /* .len = */ 0, + /* .data = */ NULL, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ, + /* .params = */ { + /* .read = */ { + /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams) + } + } + }; + + if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { + if (cbParams.data != NULL) { + reply.params.read.update = 1; + reply.params.read.offset = cbParams.offset; + reply.params.read.len = cbParams.len; + reply.params.read.p_data = cbParams.data; + } + } + + sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); + break; + } + + default: + handleEvent(eventType, handle_value); + break; + } +} + +uint16_t nRF5xGattServer::getBiggestCharacteristicSize() const { + uint16_t result = 0; + for (size_t i = 0; i < characteristicCount; ++i) { + uint16_t current_size = p_characteristics[i]->getValueAttribute().getMaxLength(); + if (current_size > result) { + result = current_size; + } + } + return result; +} + +nRF5xGattServer::long_write_request_t* nRF5xGattServer::allocateLongWriteRequest(uint16_t connection_handle) { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data == NULL) { + uint16_t block_size = getBiggestCharacteristicSize(); + req.data = static_cast(malloc(block_size)); + req.offset = 0; + req.length = 0; + req.conn_handle = connection_handle; + return &req; + } + } + // if nothing has been found then return null + return NULL; +} + +bool nRF5xGattServer::releaseLongWriteRequest(uint16_t connection_handle) { + long_write_request_t* req = findLongWriteRequest(connection_handle); + if (!req) { + return false; + } + + free(req->data); + req->data = NULL; + + // the other fields are not relevant, return now + return true; +} + +nRF5xGattServer::long_write_request_t* nRF5xGattServer::findLongWriteRequest(uint16_t connection_handle) { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data != NULL && req.conn_handle == connection_handle) { + return &req; + } + } + // if nothing has been found then return null + return NULL; +} + +void nRF5xGattServer::releaseAllWriteRequests() { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data != NULL) { + free(req.data); + req.data = NULL; + } + } +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.h new file mode 100644 index 0000000000..6be90ff733 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xGattServer.h @@ -0,0 +1,167 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF51822_GATT_SERVER_H__ +#define __NRF51822_GATT_SERVER_H__ + +#include + +#include "ble/blecommon.h" +#include "headers/nrf_ble.h" /* nordic ble */ +#include "ble/Gap.h" +#include "ble/GattServer.h" + +class nRF5xGattServer : public GattServer +{ +public: + /* Functions that must be implemented from GattServer */ + virtual ble_error_t addService(GattService &); + virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t reset(void); + + /* nRF51 Functions */ + void eventCallback(void); + void hwCallback(const ble_evt_t *p_ble_evt); + + +private: + const static unsigned BLE_TOTAL_CHARACTERISTICS = 20; + const static unsigned BLE_TOTAL_DESCRIPTORS = 8; + const static unsigned TOTAL_CONCURRENT_LONG_WRITE_REQUESTS = 3; + +private: + struct long_write_request_t { + // the connection handle for a long write request + uint16_t conn_handle; + + // the attribute handle for the long write request + // This implementation folow the bluetooth route + // where a write request target a single characteristic + // (see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] - 4.9.4) + uint16_t attr_handle; + + // offset of the transaction + uint16_t offset; + + // length of the data + uint16_t length; + + // current data + uint8_t* data; + }; + + +private: + /** + * resolve a value attribute to its owning characteristic. + * @param valueHandle the value handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveValueHandleToCharIndex(GattAttribute::Handle_t valueHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].value_handle == valueHandle) { + return charIndex; + } + } + + return -1; + } + + /** + * resolve a CCCD attribute handle to its owning characteristic. + * @param cccdHandle the CCCD handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveCCCDHandleToCharIndex(GattAttribute::Handle_t cccdHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].cccd_handle == cccdHandle) { + return charIndex; + } + } + + return -1; + } + + /** + * Return the biggest size used by a characteristic in the server + */ + uint16_t getBiggestCharacteristicSize() const; + + /** + * Allocate a new write long request. return null if no requests are available. + * @param connection_handle The connection handle to be associated with the request. + * @return the allocated request or NULL if no requests are available. + */ + long_write_request_t* allocateLongWriteRequest(uint16_t connection_handle); + + /** + * Release a long write request and free a slot for subsequent write long requests. + * @param connection_handle The connection handle associated with the request + * @return true if the request where allocated and was release, false otherwise. + */ + bool releaseLongWriteRequest(uint16_t connection_handle); + + /** + * Find a long write request from a characteristic handle + * @param connection_handle The connection handle associated with the request. + * @return a pointer to the request if found otherwise NULL. + */ + long_write_request_t* findLongWriteRequest(uint16_t connection_handle); + + /** + * Release all pending write requests. + */ + void releaseAllWriteRequests(); + + /** + * Query if updates of a characteristics are enabled for a given connection. + */ + ble_error_t areUpdatesEnabled( + Gap::Handle_t connectionHandle, + GattAttribute::Handle_t valueHandle, + bool *enabledP + ); + +private: + GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; + ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; + GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS]; + uint8_t descriptorCount; + uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS]; + long_write_request_t long_write_requests[TOTAL_CONCURRENT_LONG_WRITE_REQUESTS]; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGattServer() : GattServer(), p_characteristics(), nrfCharacteristicHandles(), p_descriptors(), descriptorCount(0), nrfDescriptorHandles(), long_write_requests() { + /* empty */ + } + +private: + nRF5xGattServer(const nRF5xGattServer &); + const nRF5xGattServer& operator=(const nRF5xGattServer &); +}; + +#endif // ifndef __NRF51822_GATT_SERVER_H__ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.cpp new file mode 100644 index 0000000000..404b3bdc96 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.cpp @@ -0,0 +1,1679 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "nRF5xPalGattClient.h" + +#include "ble/pal/PalGattClient.h" +#include "ble/pal/SimpleAttServerMessage.h" + +#include "nrf_ble_gatt.h" +#include "nrf_ble.h" +#include "nrf_ble_types.h" +#include "nrf_ble_err.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +namespace { + +/** + * Extract an uint16_t value from a memory location. + */ +static uint16_t bytes_to_u16(const void* b) +{ + uint16_t res; + memcpy(&res, b, sizeof(uint16_t)); + return res; +} + +/** + * Push an uint16_t value into a byte stream. + * + * @note it is incremented. + */ +static void u16_to_stream(uint8_t *&it, uint16_t v) +{ + memcpy(it, &v, sizeof(uint16_t)); + it += 2; +} + +/** + * Convert a pal::attribute_handle_range_t into a ble_gattc_handle_range_t. + */ +static ble_gattc_handle_range_t to_nordic_handle_range(const attribute_handle_range_t &range) +{ + ble_gattc_handle_range_t result = { + range.begin, + range.end + }; + return result; +} + +/** + * Convert a ble_gattc_handle_range_t into a pal::attribute_handle_range_t. + */ +static attribute_handle_range_t to_ble_handle_range(const ble_gattc_handle_range_t &range) +{ + attribute_handle_range_t result = { + range.start_handle, + range.end_handle + }; + return result; +} + +/** + * Convert an error from the softdevice into a ble_error_t + */ +static ble_error_t convert_sd_error(uint32_t err) +{ + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_PARAM: + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_DATA_SIZE: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case BLE_ERROR_NO_TX_PACKETS: + return BLE_ERROR_NO_MEM; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +/** + * Convert a UUID into a ble_uuid_t . + * If the UUID is a 128 bit one then it is registered into the softdevice. + */ +static ble_error_t to_nordic_uuid(const UUID &uuid, ble_uuid_t &nordic_uuid) +{ + if (uuid.getLen() == UUID::LENGTH_OF_LONG_UUID) { + // first try to get the long UUID in the table of UUIDs + uint32_t err = sd_ble_uuid_decode( + uuid.getLen(), + uuid.getBaseUUID(), + &nordic_uuid + ); + + // UUID found and filed, return. + if (err == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + ble_uuid128_t uuid128; + memcpy(uuid128.uuid128, uuid.getBaseUUID(), sizeof(uuid128.uuid128)); + + // UUID not found, try to register it + err = sd_ble_uuid_vs_add(&uuid128, &nordic_uuid.type); + if (err == NRF_SUCCESS) { + nordic_uuid.uuid = bytes_to_u16(uuid.getBaseUUID() + 12); + } + + return convert_sd_error(err); + } else { + nordic_uuid.type = BLE_UUID_TYPE_BLE; + nordic_uuid.uuid = uuid.getShortUUID(); + return BLE_ERROR_NONE; + } +} + +/** + * Convert an attribute error code from the softdevice into a valid ATT error. + */ +static uint8_t convert_sd_att_error_code(uint16_t err) +{ + if (err < 0x101 || err > 0x1FF) { + return AttErrorResponse::UNLIKELY_ERROR; + } else { + return err & 0xFF; + } +} + +static const size_t long_uuid_length = 16; +static const size_t read_by_group_type_long_uuid_index = 4; +static const size_t characteristic_declaration_length = 1 + 2 + 16; + +} // end of anonymous namespace + +nRF5xGattClient::nRF5xGattClient() : + ble::pal::GattClient(), + _procedures() +{ +} + +nRF5xGattClient::~nRF5xGattClient() +{ + terminate(); +} + +ble_error_t nRF5xGattClient::initialize() +{ + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGattClient::exchange_mtu(connection_handle_t connection) +{ + // FIXME: implement when SD 140 5.x.x is present + // (see sd_ble_gatts_exchange_mtu_reply) + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xGattClient::get_mtu_size( + connection_handle_t connection_handle, uint16_t& mtu_size +) { +#if (NRF_SD_BLE_API_VERSION >= 3) + // FIXME: implement when MTU size can be configured; the mtu size must be + // stored locally when BLE_GATTC_EVT_EXCHANGE_MTU_RSP has been received + mtu_size = BLE_GATT_MTU_SIZE_DEFAULT; +#else + mtu_size = GATT_RX_MTU; +#endif + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGattClient::discover_primary_service( + connection_handle_t connection, + attribute_handle_t discovery_range_begining +) { + return launch_procedure( + connection, discovery_range_begining + ); +} + +ble_error_t nRF5xGattClient::discover_primary_service_by_service_uuid( + connection_handle_t connection_handle, + attribute_handle_t discovery_range_beginning, + const UUID& uuid +) { + return launch_procedure( + connection_handle, discovery_range_beginning, uuid + ); +} + +ble_error_t nRF5xGattClient::find_included_service( + connection_handle_t connection_handle, + attribute_handle_range_t service_range +) { + return launch_procedure( + connection_handle, service_range + ); +} + +ble_error_t nRF5xGattClient::discover_characteristics_of_a_service( + connection_handle_t connection_handle, + attribute_handle_range_t discovery_range +) { + return launch_procedure( + connection_handle, discovery_range + ); +} + +ble_error_t nRF5xGattClient::discover_characteristics_descriptors( + connection_handle_t connection_handle, + attribute_handle_range_t descriptors_discovery_range +) { + return launch_procedure( + connection_handle, descriptors_discovery_range + ); +} + +ble_error_t nRF5xGattClient::read_attribute_value( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle +) { + return launch_procedure( + connection_handle, attribute_handle + ); +} + +ble_error_t nRF5xGattClient::read_using_characteristic_uuid( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& uuid +) { + return launch_procedure( + connection_handle, read_range, uuid + ); +} + +ble_error_t nRF5xGattClient::read_attribute_blob( + connection_handle_t connection, + attribute_handle_t attribute_handle, + uint16_t offset +) { + return launch_procedure( + connection, attribute_handle, offset + ); +} + +ble_error_t nRF5xGattClient::read_multiple_characteristic_values( + connection_handle_t connection, + const ArrayView& characteristic_handles +) { + return launch_procedure( + connection, characteristic_handles + ); +} + +ble_error_t nRF5xGattClient::write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value +) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_WRITE_CMD, + /* exec flags */ 0, + characteristic_value_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); +} + +ble_error_t nRF5xGattClient::signed_write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value +) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_SIGN_WRITE_CMD, + /* exec flags */ 0, + characteristic_value_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); +} + +ble_error_t nRF5xGattClient::write_attribute( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView& value +) { + return launch_procedure( + connection_handle, attribute_handle, value + ); +} + +ble_error_t nRF5xGattClient::queue_prepare_write( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset +) { + return launch_procedure( + connection_handle, characteristic_value_handle, value, offset + ); +} + +ble_error_t nRF5xGattClient::execute_write_queue( + connection_handle_t connection_handle, + bool execute +) { + return launch_procedure( + connection_handle, execute + ); +} + + +/** + * Base definition of a GATT procedure. + * + * Nordic implementation of discovery procedures requires more than a single + * request to the BLE peer when it involves 128bit UUID. As a consequence it is + * necessary to reserve the connection slot, maintain state between requests and + * interpret responses depending on the context. + * + * The concept of procedures for Gatt operations formalize the process. A + * procedure lifecycle is defined by three function: + * - start: Launch of the procedure. It initiate the first request to send to + * the peer. It must be implemented by Procedure derived classes. + * - handle: Event handler that process ble events comming from the softdevice. + * This function drive the procedure flow and must be implemented by + * Procedure derived classes. + * - terminate: end the procedure and forward the result to the GattClient + * event handle. + * + * @note Commands such as write without response or signed write without response + * are not procedures. + */ +struct nRF5xGattClient::GattProcedure { + /** + * Initialize the procedure. + * + * @param connection Handle representing the connection used by the procedure. + * @param op Opcode of the procedure. + */ + GattProcedure(connection_handle_t connection, AttributeOpcode op) : + connection_handle(connection), procedure_opcode(op) { } + + /** + * To overide in child if necessary. + */ + virtual ~GattProcedure() { } + + /** + * Handle events targeting the connection. + */ + virtual void handle(const ble_evt_t &evt) = 0; + + /** + * Terminate the execution of the procedure and forward msg to the handler + * registered in the client. + * + * @note delete this. + */ + void terminate(const AttServerMessage &msg) + { + get_client().remove_procedure(this); + get_client().on_server_event(connection_handle, msg); + delete this; + } + + /** + * Terminate the procedure with an unlikely error. + */ + void abort() + { + terminate(AttErrorResponse( + procedure_opcode, AttErrorResponse::UNLIKELY_ERROR + )); + } + + const connection_handle_t connection_handle; + const AttributeOpcode procedure_opcode; +}; + + +/** + * A regular procedure is a procedure that follows Gatt specification. + * + * It initiate a single request to the peer and excepts a single response. This + * kind of procedure doesn't requires extra processing step. + * + * Given that such procedure expects a single event type from the soft device, + * error handling can be generalized. + */ +struct nRF5xGattClient::RegularGattProcedure : GattProcedure { + + /** + * Construct a RegularGattProcedure. + * + * @param connection Handle of the connection used by the procedure. + * @param op Attribute operation code + * @param event_type Type of event expected by the stack. + */ + RegularGattProcedure( + connection_handle_t connection, AttributeOpcode op, BLE_GATTC_EVTS event_type + ) : GattProcedure(connection, op), _event_type(event_type) { } + + /** + * Handle events from the BLE stack; do not overide in child. + * + * @note This function offload error handling from user error handler. If + * the event in input match the expected event type and does not carry error + * then it is forwarded to the do_handle function. Otherwise the procedure + * is terminated and an error is forwarded to the client event handler. + */ + virtual void handle(const ble_evt_t &evt) + { + if (evt.header.evt_id == _event_type) { + const ble_gattc_evt_t &gattc_evt = evt.evt.gattc_evt; + if (gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + procedure_opcode, + gattc_evt.error_handle, + convert_sd_att_error_code(gattc_evt.gatt_status) + )); + return; + } else { + do_handle(gattc_evt); + } + } else { + abort(); + } + } + + /** + * Handle gatt event received from the stack. + * + * @note The event passed in parameter is valid. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) = 0; + +protected: + BLE_GATTC_EVTS _event_type; +}; + + +/** + * Procedure that handle discovery of primary services. + * + * The softdevice doesn't forward to user UUID of services that are 128 bit long. + * In such case a read request is issued for each service attribute handle + * to extract that information. + */ +struct nRF5xGattClient::DiscoverPrimaryServiceProcedure : GattProcedure { + + typedef ArrayView services_array_t; + + DiscoverPrimaryServiceProcedure(connection_handle_t connection) : + GattProcedure(connection, AttributeOpcode::READ_BY_GROUP_TYPE_REQUEST), + response(NULL), count(0), idx(0) { } + + virtual ~DiscoverPrimaryServiceProcedure() + { + if (response) { + delete[] response; + } + } + + ble_error_t start(attribute_handle_t begining) + { + uint32_t err = sd_ble_gattc_primary_services_discover( + connection_handle, begining, /* p_srvc_uuid */ NULL + ); + return convert_sd_error(err); + } + + /** + * Dispatch responses either to service discovery handler or attribute read + * handler. + */ + virtual void handle(const ble_evt_t &evt) + { + switch (evt.header.evt_id) { + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + handle_service_discovered(evt.evt.gattc_evt); + return; + case BLE_GATTC_EVT_READ_RSP: + handle_uuid_read(evt.evt.gattc_evt); + return; + default: + abort(); + return; + } + } + + /** + * Dispatch service discovery response either to the short UUID handler or + * the long UUID handler. + */ + void handle_service_discovered(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_BY_GROUP_TYPE_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + services_array_t services( + evt.params.prim_srvc_disc_rsp.services, + evt.params.prim_srvc_disc_rsp.count + ); + + // note 128 bit and 16 bits UUID cannot be mixed up + if (services[0].uuid.type == BLE_UUID_TYPE_BLE) { + handle_16bit_services_discovered(services); + } else { + handle_128bit_services_discovered(services); + } + } + + /** + * Handle discovery of services with a 16 bit UUID. + * + * The procedure ends here. + */ + void handle_16bit_services_discovered(const services_array_t &services) + { + /** + * Custom implementation of AttReadByGroupTypeResponse that can be used + * with data returned by the nordic stack. + */ + struct CustomAttReadByGroupTypeResponse : AttReadByGroupTypeResponse { + CustomAttReadByGroupTypeResponse(const services_array_t &s) : + AttReadByGroupTypeResponse(), services(s) { + } + + virtual size_t size() const + { + return services.size(); + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + to_ble_handle_range(services[i].handle_range), + make_const_ArrayView( + reinterpret_cast(&services[i].uuid.uuid), + sizeof(uint16_t) + ) + }; + return result; + } + + const services_array_t &services; + }; + + terminate(CustomAttReadByGroupTypeResponse(services)); + } + + /** + * Handle discovery of services with a 128 UUID. + * + * Handle of the services discovered will be stored locally then the + * procedure sequentially initiate a read request of each of these attribute + * handle to acquire the value of the UUID of the service. + * + * The procedure ends once all the informations initially sent by the peer + * has been reconstructed and forwarded to the registered client handler. + */ + void handle_128bit_services_discovered(const services_array_t &services) + { + response = new(std::nothrow) packed_discovery_response_t[services.size()]; + if (!response) { + abort(); + return; + } + + count = services.size(); + idx = 0; + for (size_t i = 0; i < count; ++i) { + uint8_t *it = &response[i][0]; + u16_to_stream(it, services[i].handle_range.start_handle); + u16_to_stream(it, services[i].handle_range.end_handle); + } + + read_service_uuid(); + } + + /** + * Initiate the read request of the next service attribute handle. + */ + void read_service_uuid(void) + { + // note: use read multiple once different mtu size are supported ? + uint16_t attribute_handle = bytes_to_u16(&response[idx][0]); + + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + if (err) { + abort(); + } + } + + /** + * Handle reception of a service (long) UUID. + */ + void handle_uuid_read(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + const ble_gattc_evt_read_rsp_t &rsp = evt.params.read_rsp; + + uint16_t expected_handle = bytes_to_u16(&response[idx][0]); + + if (rsp.handle != expected_handle || rsp.offset != 0 || + rsp.len != long_uuid_length) { + abort(); + return; + } + + memcpy(&response[idx][read_by_group_type_long_uuid_index], rsp.data, rsp.len); + + ++idx; + + if (idx == count) { + terminate(SimpleAttReadByGroupTypeResponse( + sizeof(packed_discovery_response_t), + make_const_ArrayView( + reinterpret_cast(response), + count * sizeof(packed_discovery_response_t) + )) + ); + } else { + read_service_uuid(); + } + } + + // Hold read by group type response of services with 128 bit UUID. + // The response is composed of the service attribute handle (2 bytes), the + // end group handle (2 bytes) and the service UUID (16 bytes). + typedef uint8_t packed_discovery_response_t[20]; + + packed_discovery_response_t* response; + uint16_t count; + uint16_t idx; +}; + + +/** + * Procedure that manage Discover Primary Service by Service UUID transactions. + * + * @note Even if the softdevice doesn't forward the complete content of the peer + * response it is possible to reconstruct it by keeping a copy of the UUID to + * find. + */ +struct nRF5xGattClient::DiscoverPrimaryServiceByUUIDProcedure : RegularGattProcedure { + + typedef ArrayView services_array_t; + + DiscoverPrimaryServiceByUUIDProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::FIND_BY_TYPE_VALUE_REQUEST, + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP + ), + _service_uuid() { } + + ble_error_t start(attribute_handle_t begining, const UUID &uuid) + { + ble_uuid_t nordic_uuid; + ble_error_t ble_err = to_nordic_uuid(uuid, nordic_uuid); + if (ble_err) { + return ble_err; + } + + uint32_t err = sd_ble_gattc_primary_services_discover( + connection_handle, begining, &nordic_uuid + ); + if (!err) { + _service_uuid = uuid; + } + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + services_array_t services( + evt.params.prim_srvc_disc_rsp.services, + evt.params.prim_srvc_disc_rsp.count + ); + + /** + * Implementation of AttReadByGroupTypeResponse that addapt Nordic data + * structure. + */ + struct CustomAttReadByGroupTypeResponse : AttReadByGroupTypeResponse { + CustomAttReadByGroupTypeResponse(const services_array_t &s, const UUID &u) : + AttReadByGroupTypeResponse(), services(s), uuid(u) { + } + + virtual size_t size() const + { + return services.size(); + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + to_ble_handle_range(services[i].handle_range), + make_ArrayView(uuid.getBaseUUID(), uuid.getLen()) + }; + return result; + } + + const services_array_t &services; + const UUID &uuid; + }; + + terminate(CustomAttReadByGroupTypeResponse(services, _service_uuid)); + } + + UUID _service_uuid; +}; + + +/** + * Procedure that manage Find Included Services transactions. + */ +struct nRF5xGattClient::FindIncludedServicesProcedure : RegularGattProcedure { + + typedef ArrayView services_array_t; + + FindIncludedServicesProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_BY_TYPE_REQUEST, + BLE_GATTC_EVT_REL_DISC_RSP + ) { } + + ble_error_t start(attribute_handle_range_t service_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(service_range); + uint32_t err = sd_ble_gattc_relationships_discover( + connection_handle, &range + ); + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + // recompose the message into a raw att read by type response. + const ble_gattc_evt_rel_disc_rsp_t &resp = evt.params.rel_disc_rsp; + + bool contain_short_uuid = + (resp.includes[0].included_srvc.uuid.type == BLE_UUID_TYPE_BLE); + + uint8_t element_size = 6; + if (contain_short_uuid) { + element_size += 2; + } + + // It would be more efficient to use an API like alloca but it is + // unavailable and unsafe. Another alternative would be to have a fixed + // size stack buffer since the size of the MTU is fixed however once new + // softdevices lands could would have to be rewritten because they support + // variable MTU size. + size_t buffer_size = element_size * resp.count; + uint8_t* buffer = new(std::nothrow) uint8_t[buffer_size]; + if (!buffer) { + abort(); + return; + } + + uint8_t *it = buffer; + for(size_t i = 0; i < resp.count; ++i) { + u16_to_stream(it, resp.includes[i].handle); + u16_to_stream(it, resp.includes[i].included_srvc.handle_range.start_handle); + u16_to_stream(it, resp.includes[i].included_srvc.handle_range.end_handle); + if (contain_short_uuid) { + u16_to_stream(it, resp.includes[i].included_srvc.uuid.uuid); + } + } + + terminate(SimpleAttReadByTypeResponse( + element_size, + make_const_ArrayView(buffer, buffer_size) + )); + + delete[] buffer; + } + + UUID _service_uuid; +}; + + +/** + * Procedure that handle Discover All Characteristics of a Service transactions. + * + * The softdevice doesn't forward to user UUID of services that are 128 bit long. + * In such case a read request is issued for each attribute handle of + * characteristics that exposes a long UUID. + */ +struct nRF5xGattClient::DiscoverCharacteristicsProcedure : GattProcedure { + /** + * Data structure returned by the function flatten_response. + */ + struct read_by_type_response_t { + uint16_t count; + uint16_t element_size; + uint8_t* buffer; + }; + + DiscoverCharacteristicsProcedure(connection_handle_t connection) : + GattProcedure(connection, AttributeOpcode::READ_BY_TYPE_REQUEST), + _response(), _idx(0) { } + + virtual ~DiscoverCharacteristicsProcedure() + { + if (_response.buffer) { + delete[] _response.buffer; + } + } + + ble_error_t start(attribute_handle_range_t discovery_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(discovery_range); + uint32_t err = sd_ble_gattc_characteristics_discover( + connection_handle, + &range + ); + + return convert_sd_error(err); + } + + /** + * Dispatch ble events to the appropriate handler: + * - handle_characteristic_discovered: For a discovery response. + * - handle_uuid_read: For a read response. + */ + virtual void handle(const ble_evt_t &evt) + { + switch (evt.header.evt_id) { + case BLE_GATTC_EVT_CHAR_DISC_RSP: + handle_characteristic_discovered(evt.evt.gattc_evt); + return; + case BLE_GATTC_EVT_READ_RSP: + handle_uuid_read(evt.evt.gattc_evt); + return; + default: + abort(); + return; + } + } + + void handle_characteristic_discovered(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_BY_TYPE_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + // layout the data structure into a flat byte array. + _response = flatten_response(evt.params.char_disc_rsp); + if (!_response.buffer) { + abort(); + return; + } + + // If element size is equal to 7 then the characteristic discovered + // have 16 bit UUID. It is not necessary to read their characteristic + // declaration attribute. + if (_response.element_size == 7) { + forward_response_and_terminate(); + } else { + // 128 bit UUID. + // read sequentially each characteristic declaration attribute + // discovered. + _idx = 0; + read_characteristic_uuid(); + } + } + + /** + * Initiate read of the next characteristic declaration attribute. + */ + void read_characteristic_uuid(void) + { + // note: use read multiple once different mtu size are supported ? + uint16_t attribute_handle = + bytes_to_u16(&_response.buffer[_idx * _response.element_size]); + + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + if (err) { + abort(); + } + } + + /** + * Handle read response of a characteristic declaration attribute. + * It add the data in the response then initiate the read of the next + * attribute or terminate the procedure if all characteristic declaration + * attributes have been read. + */ + void handle_uuid_read(const ble_gattc_evt_t &evt) + { + // should never happen + if (!_response.buffer) { + abort(); + return; + } + + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + const ble_gattc_evt_read_rsp_t &rsp = evt.params.read_rsp; + uint8_t* current_element = &_response.buffer[_idx * _response.element_size]; + uint16_t expected_handle = bytes_to_u16(current_element); + + if (rsp.handle != expected_handle || rsp.offset != 0 || + rsp.len != characteristic_declaration_length) { + abort(); + return; + } + + // note: elements are the pair characteristic declaration handle followed + // by the attribute value. + memcpy(current_element + 2, rsp.data, rsp.len); + + ++_idx; + + if (_idx == _response.count) { + forward_response_and_terminate(); + } else { + read_characteristic_uuid(); + } + } + + /** + * Terminate the procedure by forwarding the AttReadByTypeResponse built. + */ + void forward_response_and_terminate() { + terminate(SimpleAttReadByTypeResponse( + _response.element_size, + make_const_ArrayView( + _response.buffer, + _response.element_size * _response.count + ) + )); + } + + /** + * Convert a ble_gattc_evt_char_disc_rsp_t into a raw response. + * + * If UUIDs present are 16 bits long then the output contain the whole + * response. Otherwise only the handle declaration of each characteristic + * discovered is present and properties, handle value and UUID are populated + * by reading the attribute handle. + */ + static read_by_type_response_t flatten_response(const ble_gattc_evt_char_disc_rsp_t& resp) + { + read_by_type_response_t result = { resp.count, 0 }; + + bool short_uuid = (resp.chars[0].uuid.type == BLE_UUID_TYPE_BLE); + + // att handle + prop + value handle + uuid size + result.element_size = 5 + (short_uuid ? 2 : 16) ; + + size_t buffer_size = resp.count * result.element_size; + result.buffer = new(std::nothrow) uint8_t[buffer_size]; + if(!result.buffer) { + return result; + } + + uint8_t *it = result.buffer; + for(size_t i = 0; i < resp.count; ++i) { + u16_to_stream(it, resp.chars[i].handle_decl); + if (short_uuid) { + *it++ = get_properties(resp.chars[i]); + u16_to_stream(it, resp.chars[i].handle_value); + u16_to_stream(it, resp.chars[i].uuid.uuid); + } else { + // leave the characteristic value declaration empty; it will be + // fullfiled by a read of the attribute. + it += (1 + 2 + 16); + } + } + + return result; + } + + /** + * Compute characteristic properties from ble_gattc_char_t. + */ + static uint8_t get_properties(const ble_gattc_char_t& char_desc) + { + return + (char_desc.char_props.broadcast << 0) | + (char_desc.char_props.read << 1) | + (char_desc.char_props.write_wo_resp << 2) | + (char_desc.char_props.write << 3) | + (char_desc.char_props.notify << 4) | + (char_desc.char_props.indicate << 5) | + (char_desc.char_props.auth_signed_wr << 6) | + (char_desc.char_ext_props << 7); + } + + read_by_type_response_t _response; + uint16_t _idx; +}; + +/** + * Procedure that handle discovery of characteristic descriptors. + */ +struct nRF5xGattClient::DiscoverDescriptorsProcedure : RegularGattProcedure { + DiscoverDescriptorsProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::FIND_INFORMATION_REQUEST, + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP + ) { + } + + ble_error_t start(attribute_handle_range_t discovery_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(discovery_range); + uint32_t err = sd_ble_gattc_attr_info_discover( + connection_handle, + &range + ); + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + /** + * Adapt ble_gattc_evt_attr_info_disc_rsp_t into + * pal::AttFindInformationResponse + */ + struct CustomFindInformationResponse : AttFindInformationResponse { + CustomFindInformationResponse(const ble_gattc_evt_attr_info_disc_rsp_t &resp) : + AttFindInformationResponse(), response(resp) {} + + virtual size_t size() const + { + return response.count; + } + +#if (NRF_SD_BLE_API_VERSION < 3) + virtual information_data_t operator[](size_t i) const + { + information_data_t result = { + response.attr_info[i].handle + }; + + if (response.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT) { + result.uuid = UUID(response.attr_info[i].info.uuid16.uuid); + } else { + result.uuid = UUID( + response.attr_info[i].info.uuid128.uuid128, + UUID::LSB + ); + } + + return result; + } +#else + virtual information_data_t operator[](size_t i) const + { + if (response.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT) { + information_data_t result = { + response.info.attr_info16[i].handle, + UUID(response.info.attr_info16[i].uuid.uuid) + }; + + return result; + } else { + information_data_t result = { + response.info.attr_info128[i].handle, + UUID( + response.info.attr_info128[i].uuid.uuid128, + UUID::LSB + ) + }; + + return result; + } + } + + +#endif + + + const ble_gattc_evt_attr_info_disc_rsp_t &response; + }; + + terminate(CustomFindInformationResponse(evt.params.attr_info_disc_rsp)); + } +}; + + +/** + * Procedure that handle read of attribute handles. + */ +struct nRF5xGattClient::ReadAttributeProcedure : RegularGattProcedure { + ReadAttributeProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::READ_REQUEST, BLE_GATTC_EVT_READ_RSP + ) { } + + ble_error_t start(attribute_handle_t attribute_handle) + { + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_read_rsp_t& rsp = evt.params.read_rsp; + if (rsp.offset != 0 ) { + abort(); + return; + } + + terminate(AttReadResponse(make_const_ArrayView(rsp.data, rsp.len))); + } +}; + +/** + * Procedure that handle read of characteristic using characteristic UUID. + */ +struct nRF5xGattClient::ReadUsingCharacteristicUUIDProcedure : RegularGattProcedure { + ReadUsingCharacteristicUUIDProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_BY_TYPE_REQUEST, + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP + ) { } + + ble_error_t start(attribute_handle_range_t read_range, const UUID& uuid) + { + ble_uuid_t nordic_uuid = { 0 }; + ble_error_t ble_err = to_nordic_uuid(uuid, nordic_uuid); + if (ble_err) { + return ble_err; + } + + ble_gattc_handle_range_t range = { + read_range.begin, + read_range.end + }; + + uint32_t err = sd_ble_gattc_char_value_by_uuid_read( + connection_handle, + &nordic_uuid, + &range + ); + return convert_sd_error(err); + } + +#if (NRF_SD_BLE_API_VERSION >= 3) + /** + * Adapt ble_gattc_evt_char_val_by_uuid_read_rsp_t into AttReadByTypeResponse. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_char_val_by_uuid_read_rsp_t &rsp = + evt.params.char_val_by_uuid_read_rsp; + + uint8_t element_size = sizeof(uint16_t) + rsp.value_len; + + terminate(SimpleAttReadByTypeResponse( + element_size, + make_const_ArrayView( + rsp.handle_value, + rsp.count * element_size + ) + )); + } + +#else + /** + * Adapt ble_gattc_evt_char_val_by_uuid_read_rsp_t into AttReadByTypeResponse. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) + { + struct CustomReadByTypeResponse : AttReadByTypeResponse { + CustomReadByTypeResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t& rsp) : + AttReadByTypeResponse(), response(rsp) { } + + virtual size_t size() const + { + return response.count; + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + response.handle_value[i].handle, + make_const_ArrayView( + response.handle_value[i].p_value, + response.value_len + ) + }; + return result; + } + + const ble_gattc_evt_char_val_by_uuid_read_rsp_t& response; + } + + terminate(CustomReadByTypeResponse(evt.params.char_val_by_uuid_read_rsp)); + } +#endif +}; + +/** + * Procedure that handles read blob transactions. + */ +struct nRF5xGattClient::ReadAttributeBlobProcedure : RegularGattProcedure { + ReadAttributeBlobProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::READ_BLOB_REQUEST, BLE_GATTC_EVT_READ_RSP + ) { } + + ble_error_t start(attribute_handle_t attribute_handle, uint16_t offset) + { + uint32_t err = sd_ble_gattc_read( + connection_handle, attribute_handle, offset + ); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttReadBlobResponse(make_const_ArrayView( + evt.params.read_rsp.data, + evt.params.read_rsp.len + ))); + } +}; + +/** + * Procedure that handles Read Multiple Characteristic Values transactions. + */ +struct nRF5xGattClient::ReadMultipleCharacteristicsProcedure : RegularGattProcedure { + ReadMultipleCharacteristicsProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_MULTIPLE_REQUEST, + BLE_GATTC_EVT_CHAR_VALS_READ_RSP + ) { } + + ble_error_t start(const ArrayView& characteristic_handles) + { + uint32_t err = sd_ble_gattc_char_values_read( + connection_handle, + characteristic_handles.data(), + characteristic_handles.size() + ); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttReadMultipleResponse(make_const_ArrayView( + evt.params.char_vals_read_rsp.values, + evt.params.char_vals_read_rsp.len + ))); + } +}; + +/** + * Procedure that handles Write transactions. + */ +struct nRF5xGattClient::WriteAttributeProcedure : RegularGattProcedure { + WriteAttributeProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::WRITE_REQUEST, BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start( + attribute_handle_t attribute_handle, const ArrayView& value + ) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_WRITE_REQ, + /* exec flags */ 0, + attribute_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttWriteResponse()); + } +}; + +/** + * Procedure that handles Prepare Write transactions. + */ +struct nRF5xGattClient::QueuePrepareWriteProcedure : RegularGattProcedure { + QueuePrepareWriteProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::PREPARE_WRITE_REQUEST, + BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start( + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset + ) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_PREP_WRITE_REQ, + /* exec flags */ 0, + characteristic_value_handle, + offset, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_write_rsp_t &response = evt.params.write_rsp; + + if (response.write_op != BLE_GATT_OP_PREP_WRITE_REQ) { + abort(); + return; + } + + terminate(AttPrepareWriteResponse( + response.handle, + response.offset, + make_const_ArrayView(response.data, response.len) + )); + } +}; + +/** + * Procedure that handles Execute Write transactions. + */ +struct nRF5xGattClient::ExecuteWriteQueueProcedure : RegularGattProcedure { + ExecuteWriteQueueProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::EXECUTE_WRITE_REQUEST, + BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start(bool execute) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_EXEC_WRITE_REQ, + static_cast( + execute ? + BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL : + BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE + ), + /* attribute handle */ 0, + /* value offset */ 0, + /* buffer size*/ 0, + /* buffer data */ NULL + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_write_rsp_t &response = evt.params.write_rsp; + if (response.write_op != BLE_GATT_OP_EXEC_WRITE_REQ) { + abort(); + return; + } + + terminate(AttExecuteWriteResponse()); + } +}; + +// NOTE: position after declaration of GattProcedure on purpose. +ble_error_t nRF5xGattClient::terminate() +{ + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i]) { + _procedures[i]->abort(); + _procedures[i] = NULL; + } + } + + return BLE_ERROR_NONE; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, const A0& a0 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, const A0& a0, const A1& a1 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1, a2); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2, const A3& a3 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1, a2, a3); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +nRF5xGattClient::GattProcedure* nRF5xGattClient::get_procedure( + connection_handle_t connection +) const { + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i] && _procedures[i]->connection_handle == connection) { + return _procedures[i]; + } + } + return NULL; +} + +bool nRF5xGattClient::register_procedure(GattProcedure *p) +{ + if (get_procedure(p->connection_handle)) { + return false; + } + + for (size_t i = 0; i < max_procedures_count; ++i) { + if (!_procedures[i]) { + _procedures[i] = p; + return true; + } + } + + return false; +} + +bool nRF5xGattClient::remove_procedure(nRF5xGattClient::GattProcedure* p) +{ + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i] == p) { + _procedures[i] = NULL; + return true; + } + } + + return false; +} + +// singleton of the ARM Cordio client +nRF5xGattClient& nRF5xGattClient::get_client() +{ + static nRF5xGattClient _client; + return _client; +} + +void nRF5xGattClient::handle_events(const ble_evt_t *evt) { + switch (evt->header.evt_id) { + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + case BLE_GATTC_EVT_REL_DISC_RSP: + case BLE_GATTC_EVT_CHAR_DISC_RSP: + case BLE_GATTC_EVT_DESC_DISC_RSP: + case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP: + case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP: + case BLE_GATTC_EVT_READ_RSP: + case BLE_GATTC_EVT_CHAR_VALS_READ_RSP: + case BLE_GATTC_EVT_WRITE_RSP: + get_client().handle_procedure_event(*evt); + break; + case BLE_GATTC_EVT_HVX: + get_client().handle_hvx_event(*evt); + break; + case BLE_GATTC_EVT_TIMEOUT: + get_client().handle_timeout_event(*evt); + break; + } +} + +void nRF5xGattClient::handle_procedure_event(const ble_evt_t &evt) +{ + GattProcedure* p = get_procedure(evt.evt.gattc_evt.conn_handle); + if (p) { + p->handle(evt); + } +} + +void nRF5xGattClient::handle_hvx_event(const ble_evt_t &evt) +{ + connection_handle_t connection = evt.evt.gattc_evt.conn_handle; + const ble_gattc_evt_hvx_t &hvx_evt = evt.evt.gattc_evt.params.hvx; + + switch (hvx_evt.type) { + case BLE_GATT_HVX_NOTIFICATION: + on_server_event( + connection, + AttHandleValueNotification( + hvx_evt.handle, + make_const_ArrayView(hvx_evt.data, hvx_evt.len) + ) + ); + return; + case BLE_GATT_HVX_INDICATION: + // send confirmation first then process the event + sd_ble_gattc_hv_confirm(connection, hvx_evt.handle); + on_server_event( + connection, + AttHandleValueIndication( + hvx_evt.handle, + make_const_ArrayView(hvx_evt.data, hvx_evt.len) + ) + ); + return; + default: + return; + } +} + +void nRF5xGattClient::handle_timeout_event(const ble_evt_t &evt) +{ + connection_handle_t connection = evt.evt.gattc_evt.conn_handle; + GattProcedure* p = get_procedure(connection); + if (p) { + p->abort(); + } + + on_transaction_timeout(connection); +} + +void nRF5xGattClient::handle_connection_termination(connection_handle_t connection) +{ + GattProcedure* p = get_client().get_procedure(connection); + if (p) { + p->abort(); + } +} + +} // nordic +} // vendor +} // pal +} // ble + + + + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.h new file mode 100644 index 0000000000..986fe1b48f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalGattClient.h @@ -0,0 +1,257 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLE_NORDIC_PAL_GATT_CLIENT_H_ +#define BLE_NORDIC_PAL_GATT_CLIENT_H_ + +#include "ble/pal/PalGattClient.h" +#include "ble/blecommon.h" +#include "ble/UUID.h" + +#include "nrf_ble_gatt.h" +#include "nrf_ble.h" +#include "nrf_ble_types.h" +#include "btle.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +/** + * Implementation of pal::GattClient for the Nordic stack. + */ +class nRF5xGattClient : public ble::pal::GattClient { + +public: + nRF5xGattClient(); + + virtual ~nRF5xGattClient(); + + /** + * see pal::GattClient::initialize . + */ + virtual ble_error_t initialize(); + + /** + * see pal::GattClient::terminate . + */ + virtual ble_error_t terminate(); + + /** + * see pal::GattClient::exchange_mtu . + */ + virtual ble_error_t exchange_mtu(connection_handle_t connection); + + /** + * see pal::GattClient::get_mtu_size . + */ + virtual ble_error_t get_mtu_size( + connection_handle_t connection_handle, uint16_t& mtu_size + ); + + /** + * see pal::GattClient::discover_primary_service . + */ + virtual ble_error_t discover_primary_service( + connection_handle_t connection, + attribute_handle_t discovery_range_begining + ); + + /** + * see pal::GattClient::discover_primary_service_by_service_uuid . + */ + virtual ble_error_t discover_primary_service_by_service_uuid( + connection_handle_t connection_handle, + attribute_handle_t discovery_range_beginning, + const UUID& uuid + ); + + /** + * see pal::GattClient::find_included_service . + */ + virtual ble_error_t find_included_service( + connection_handle_t connection_handle, + attribute_handle_range_t service_range + ); + + /** + * see pal::GattClient::discover_characteristics_of_a_service . + */ + virtual ble_error_t discover_characteristics_of_a_service( + connection_handle_t connection_handle, + attribute_handle_range_t discovery_range + ); + + /** + * see pal::GattClient::discover_characteristics_descriptors . + */ + virtual ble_error_t discover_characteristics_descriptors( + connection_handle_t connection_handle, + attribute_handle_range_t descriptors_discovery_range + ); + + /** + * see pal::GattClient::read_attribute_value . + */ + virtual ble_error_t read_attribute_value( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle + ); + + /** + * see pal::GattClient::read_using_characteristic_uuid . + */ + virtual ble_error_t read_using_characteristic_uuid( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& uuid + ); + + /** + * see pal::GattClient::read_attribute_blob . + */ + virtual ble_error_t read_attribute_blob( + connection_handle_t connection, + attribute_handle_t attribute_handle, + uint16_t offset + ); + + /** + * see pal::GattClient::read_multiple_characteristic_values . + */ + virtual ble_error_t read_multiple_characteristic_values( + connection_handle_t connection, + const ArrayView& characteristic_handles + ); + + /** + * see pal::GattClient::write_without_response . + */ + virtual ble_error_t write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::signed_write_without_response . + */ + virtual ble_error_t signed_write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::write_attribute . + */ + virtual ble_error_t write_attribute( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::queue_prepare_write . + */ + virtual ble_error_t queue_prepare_write( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset + ); + + /** + * see pal::GattClient::execute_write_queue . + */ + virtual ble_error_t execute_write_queue( + connection_handle_t connection_handle, + bool execute + ); + + // singleton of the ARM Cordio client + static nRF5xGattClient& get_client(); + + /** + * Function call from btle.cpp + * + * Do not call directly. + */ + static void handle_events(const ble_evt_t *p_ble_evt); + + /** + * Called by btle.cpp when a disconnection happens. + */ + static void handle_connection_termination(connection_handle_t connection); + +private: + struct GattProcedure; + struct RegularGattProcedure; + struct DiscoverPrimaryServiceProcedure; + struct DiscoverPrimaryServiceByUUIDProcedure; + struct FindIncludedServicesProcedure; + struct DiscoverCharacteristicsProcedure; + struct DiscoverDescriptorsProcedure; + struct ReadAttributeProcedure; + struct ReadUsingCharacteristicUUIDProcedure; + struct ReadAttributeBlobProcedure; + struct ReadMultipleCharacteristicsProcedure; + struct WriteAttributeProcedure; + struct QueuePrepareWriteProcedure; + struct ExecuteWriteQueueProcedure; + + template + ble_error_t launch_procedure(connection_handle_t connection, const A0& a0); + + template + ble_error_t launch_procedure( + connection_handle_t connection, const A0& a0, const A1& a1 + ); + + template + ble_error_t launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2 + ); + + template + ble_error_t launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2, const A3& a3 + ); + + GattProcedure* get_procedure(connection_handle_t) const; + bool register_procedure(GattProcedure*); + bool remove_procedure(GattProcedure*); + + void handle_procedure_event(const ble_evt_t &evt); + void handle_hvx_event(const ble_evt_t &evt); + void handle_timeout_event(const ble_evt_t &evt); + + static const size_t max_procedures_count = + CENTRAL_LINK_COUNT + PERIPHERAL_LINK_COUNT; + + // Note: Ideally we would have used an array of variant here + GattProcedure* _procedures[max_procedures_count]; +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif /* BLE_NORDIC_PAL_GATT_CLIENT_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp new file mode 100644 index 0000000000..36c7c1e0a2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp @@ -0,0 +1,1233 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nRF5xPalSecurityManager.h" +#include "nRF5xn.h" +#include "ble/Gap.h" +#include "nRF5xGap.h" +#include "nrf_ble.h" +#include "nrf_ble_gap.h" +#include "nrf_soc.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +namespace { +static ble_error_t convert_sd_error(uint32_t err) { + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + case NRF_ERROR_INVALID_PARAM: + case BLE_ERROR_INVALID_CONN_HANDLE: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + case BLE_ERROR_INVALID_ROLE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_NOT_SUPPORTED: + return BLE_ERROR_NOT_IMPLEMENTED; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_TIMEOUT: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_UNSPECIFIED; + } +} +} + +enum pairing_role_t { + PAIRING_INITIATOR, + PAIRING_RESPONDER +}; + +struct nRF5xSecurityManager::pairing_control_block_t { + pairing_control_block_t* next; + connection_handle_t connection; + pairing_role_t role; + + // flags of the key present + KeyDistribution initiator_dist; + KeyDistribution responder_dist; + + // own keys + ble_gap_enc_key_t own_enc_key; + ble_gap_id_key_t own_id_key; + ble_gap_sign_info_t own_sign_key; + ble_gap_lesc_p256_pk_t own_pk; + + // peer keys + ble_gap_enc_key_t peer_enc_key; + ble_gap_id_key_t peer_id_key; + ble_gap_sign_info_t peer_sign_key; + ble_gap_lesc_p256_pk_t peer_pk; + + // flag required to help DHKey computation/process; should be removed with + // later versions of the softdevice + uint8_t own_oob:1; + uint8_t peer_oob:1; +}; + +nRF5xSecurityManager::nRF5xSecurityManager() + : ::ble::pal::SecurityManager(), + _sign_counter(), + _io_capability(io_capability_t::NO_INPUT_NO_OUTPUT), + _min_encryption_key_size(7), + _max_encryption_key_size(16), + _control_blocks(NULL), + resolving_list_entry_count(0) +{ + +} + +nRF5xSecurityManager::~nRF5xSecurityManager() +{ + terminate(); +} + +//////////////////////////////////////////////////////////////////////////// +// SM lifecycle management +// + +ble_error_t nRF5xSecurityManager::initialize() +{ +#if defined(MBEDTLS_ECDH_C) + if (_crypto.generate_keys( + make_ArrayView(X), + make_ArrayView(Y), + make_ArrayView(secret) + )) { + return BLE_ERROR_NONE; + } + + return BLE_ERROR_INTERNAL_STACK_FAILURE; +#endif + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::terminate() +{ + release_all_pairing_cb(); + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::reset() +{ + ble_error_t err = terminate(); + if (err) { + return err; + } + + return initialize(); +} + +//////////////////////////////////////////////////////////////////////////// +// Resolving list management +// + +// FIXME: on nordic, the irk is passed in sd_ble_gap_scan_start where whitelist +// and resolving list are all mixed up. + +uint8_t nRF5xSecurityManager::read_resolving_list_capacity() +{ + return MAX_RESOLVING_LIST_ENTRIES; +} + +ble_error_t nRF5xSecurityManager::add_device_to_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address, + const irk_t &peer_irk +) { + if (resolving_list_entry_count >= MAX_RESOLVING_LIST_ENTRIES) { + return BLE_ERROR_INVALID_STATE; + } + + resolving_list_entry_t& entry = resolving_list[resolving_list_entry_count]; + entry.peer_identity_address_type = peer_identity_address_type; + entry.peer_identity_address = peer_identity_address; + entry.peer_irk = peer_irk; + + ++resolving_list_entry_count; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::remove_device_from_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address +) { + size_t entry_index; + + // first the index needs to be found + for (entry_index = 0; entry_index < resolving_list_entry_count; ++entry_index) { + resolving_list_entry_t& entry = resolving_list[entry_index]; + if (entry.peer_identity_address_type == peer_identity_address_type && + entry.peer_identity_address == peer_identity_address + ) { + break; + } + } + + if (entry_index == resolving_list_entry_count) { + return BLE_ERROR_INVALID_PARAM; + } + + // Elements after the entry can be moved in the list + for (size_t i = entry_index; i < (resolving_list_entry_count - 1); ++i) { + resolving_list[i] = resolving_list[i + 1]; + } + + --resolving_list_entry_count; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::clear_resolving_list() +{ + resolving_list_entry_count = 0; + return BLE_ERROR_NONE; +} + +ArrayView +nRF5xSecurityManager::get_resolving_list() { + return ArrayView( + resolving_list, + resolving_list_entry_count + ); +} + +const nRF5xSecurityManager::resolving_list_entry_t* +nRF5xSecurityManager::resolve_address(const address_t& resolvable_address) { + typedef byte_array_t hash_t; + + for (size_t i = 0; i < resolving_list_entry_count; ++i) { + resolving_list_entry_t& entry = resolving_list[i]; + hash_t hash_generated; + + // Compute the hash part from the random address part when the irk of + // the entry is used + CryptoToolbox::ah( + make_const_ArrayView(entry.peer_irk), + make_const_ArrayView( + resolvable_address.data() + CryptoToolbox::hash_size_ + ), + make_ArrayView(hash_generated) + ); + + // Compare hash generated with the hash present in the address passed as + // parameter. If they are equal then the IRK of the entry has been used + // to generate the resolvable address. + if (memcmp(hash_generated.data(), resolvable_address.data(), CryptoToolbox::hash_size_) == 0) { + return &entry; + } + } + + return NULL; +} + + + +//////////////////////////////////////////////////////////////////////////// +// Pairing +// + + +ble_error_t nRF5xSecurityManager::send_pairing_request( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + // allocate the control block required for the procedure completion + pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_NO_MEM; + } + pairing_cb->role = PAIRING_INITIATOR; + + // override signing parameter + initiator_dist.set_signing(false); + responder_dist.set_signing(false); + + // override link parameter + initiator_dist.set_link(false); + responder_dist.set_link(false); + + ble_gap_sec_params_t security_params = make_security_params( + oob_data_flag, + authentication_requirements, + initiator_dist, + responder_dist + ); + + uint32_t err = sd_ble_gap_authenticate( + connection, + &security_params + ); + + if (err) { + release_pairing_cb(pairing_cb); + } + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::send_pairing_response( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); + if (!pairing_cb) { + // not enough memory; try to reject the pairing request instead of + // waiting for timeout. + cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON); + return BLE_ERROR_NO_MEM; + } + pairing_cb->role = PAIRING_RESPONDER; + + // override signing parameter + initiator_dist.set_signing(false); + responder_dist.set_signing(false); + + // override link parameter + initiator_dist.set_link(false); + responder_dist.set_link(false); + + ble_gap_sec_params_t security_params = make_security_params( + oob_data_flag, + authentication_requirements, + initiator_dist, + responder_dist + ); + + ble_gap_sec_keyset_t keyset = make_keyset( + *pairing_cb, + initiator_dist, + responder_dist + ); + + uint32_t err = sd_ble_gap_sec_params_reply( + connection, + /* status */ BLE_GAP_SEC_STATUS_SUCCESS, + /* params */ &security_params, + /* keys */ &keyset + ); + + if (err) { + release_pairing_cb(pairing_cb); + } + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::cancel_pairing( + connection_handle_t connection, pairing_failure_t reason +) { + uint32_t err = 0; + + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + + // If there is no control block yet then if the local device is a central + // then we must reject the security request otherwise it is a response to + // a pairing feature exchange from a central. + if (!pairing_cb) { + ::Gap::Role_t current_role; + if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_PARAM; + } + + if (current_role == ::Gap::PERIPHERAL) { + // response to a pairing feature request + err = sd_ble_gap_sec_params_reply( + connection, + reason.value() | 0x80, + /* sec params */ NULL, + /* keyset */ NULL + ); + } else { + // response to a peripheral security request + err = sd_ble_gap_authenticate(connection, NULL); + } + } else { + // At this point this must be a response to a key + err = sd_ble_gap_auth_key_reply( + connection, + /* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE, + /* key */ NULL + ); + } + + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Feature support +// + +ble_error_t nRF5xSecurityManager::get_secure_connections_support( + bool &enabled +) { + enabled = false; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_io_capability(io_capability_t io_capability) +{ + _io_capability = io_capability; + return BLE_ERROR_NONE; +} + +//////////////////////////////////////////////////////////////////////////// +// Security settings +// + +ble_error_t nRF5xSecurityManager::set_authentication_timeout( + connection_handle_t connection, uint16_t timeout_in_10ms +) { + // FIXME: Use sd_ble_opt_set(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, ...) when + // available + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xSecurityManager::get_authentication_timeout( + connection_handle_t connection, uint16_t &timeout_in_10ms +) { + // Return default value for now (30s) + timeout_in_10ms = 30 * 100; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_encryption_key_requirements( + uint8_t min_encryption_key_size, + uint8_t max_encryption_key_size +) { + if ((min_encryption_key_size < 7) || (min_encryption_key_size > 16) || + (min_encryption_key_size > max_encryption_key_size)) { + return BLE_ERROR_INVALID_PARAM; + } + + _min_encryption_key_size = min_encryption_key_size; + _max_encryption_key_size = max_encryption_key_size; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::slave_security_request( + connection_handle_t connection, + AuthenticationMask authentication +) { + // In the peripheral role, only the bond, mitm, lesc and keypress fields of + // this structure are used. + ble_gap_sec_params_t security_params = { + /* bond */ authentication.get_bondable(), + /* mitm */ authentication.get_mitm(), + /* lesc */ authentication.get_secure_connections(), + /* keypress */ authentication.get_keypress_notification(), + /* remainder of the data structure is ignored */ 0 + }; + + uint32_t err = sd_ble_gap_authenticate( + connection, + &security_params + ); + + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Encryption +// + +ble_error_t nRF5xSecurityManager::enable_encryption( + connection_handle_t connection, + const ltk_t <k, + const rand_t &rand, + const ediv_t &ediv, + bool mitm +) { + ble_gap_master_id_t master_id; + memcpy(master_id.rand, rand.data(), rand.size()); + memcpy(&master_id.ediv, ediv.data(), ediv.size()); + + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = false; + enc_info.auth = mitm; + + // FIXME: how to pass the lenght of the LTK ??? + enc_info.ltk_len = ltk.size(); + + uint32_t err = sd_ble_gap_encrypt( + connection, + &master_id, + &enc_info + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::enable_encryption( + connection_handle_t connection, + const ltk_t <k, + bool mitm +) { + ble_gap_master_id_t master_id = {0}; + + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = true; + enc_info.auth = mitm; + enc_info.ltk_len = ltk.size(); + + uint32_t err = sd_ble_gap_encrypt( + connection, + &master_id, + &enc_info + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::encrypt_data( + const byte_array_t<16> &key, + encryption_block_t &data +) { + // FIXME: Implement in LescCrypto ? + return BLE_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////// +// Privacy +// + +ble_error_t nRF5xSecurityManager::set_private_address_timeout( + uint16_t timeout_in_seconds +) { + // get the previous config + ble_gap_irk_t irk; + ble_opt_t privacy_config; + privacy_config.gap_opt.privacy.p_irk = &irk; + + uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, &privacy_config); + if (err) { + return convert_sd_error(err); + } + + // set the timeout and return the result + privacy_config.gap_opt.privacy.interval_s = timeout_in_seconds; + err = sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, &privacy_config); + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Keys +// + +ble_error_t nRF5xSecurityManager::set_ltk( + connection_handle_t connection, + const ltk_t& ltk, + bool mitm, + bool secure_connections +) { + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = secure_connections; + enc_info.auth = mitm; + enc_info.ltk_len = ltk.size(); + + // FIXME: provide peer irk and csrk ? + uint32_t err = sd_ble_gap_sec_info_reply( + connection, + &enc_info, + /* id info */ NULL, + /* sign info */ NULL // Not supported + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_ltk_not_found( + connection_handle_t connection +) { + uint32_t err = sd_ble_gap_sec_info_reply( + connection, + NULL, + NULL, + NULL // Not supported + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_irk(const irk_t& irk) +{ + // get the previous config + ble_gap_irk_t sd_irk; + ble_opt_t privacy_config; + privacy_config.gap_opt.privacy.p_irk = &sd_irk; + + uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, &privacy_config); + if (err) { + return convert_sd_error(err); + } + + // set the new irk + memcpy(sd_irk.irk, irk.data(), irk.size()); + err = sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, &privacy_config); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_csrk( + const csrk_t& csrk, + sign_count_t sign_counter +) { + _csrk = csrk; + _sign_counter = sign_counter; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk, + bool authenticated, + sign_count_t sign_counter +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection) +{ + return BLE_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////// +// Authentication +// + +ble_error_t nRF5xSecurityManager::get_random_data(byte_array_t<8> &random_data) +{ + uint32_t err = sd_rand_application_vector_get( + random_data.data(), random_data.size() + ); + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// MITM +// + +ble_error_t nRF5xSecurityManager::set_display_passkey(passkey_num_t passkey) +{ + PasskeyAscii passkey_ascii(passkey); + ble_opt_t sd_passkey; + sd_passkey.gap_opt.passkey.p_passkey = passkey ? passkey_ascii.value() : NULL; + uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &sd_passkey); + return convert_sd_error(err); +} + + +ble_error_t nRF5xSecurityManager::passkey_request_reply( + connection_handle_t connection, const passkey_num_t passkey +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + PasskeyAscii pkasc(passkey); + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + BLE_GAP_AUTH_KEY_TYPE_PASSKEY, + pkasc.value() + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + ble_gap_lesc_oob_data_t oob_own; + ble_gap_lesc_oob_data_t oob_peer; + + // is own address important ? + memcpy(oob_own.r, local_random.data(), local_random.size()); + // FIXME: What to do with local confirm ??? + + // is peer address important ? + memcpy(oob_peer.r, peer_random.data(), peer_random.size()); + memcpy(oob_peer.c, peer_confirm.data(), peer_confirm.size()); + + uint32_t err = sd_ble_gap_lesc_oob_data_set( + connection, + pairing_cb->own_oob ? &oob_own : NULL, + pairing_cb->peer_oob ? &oob_peer : NULL + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::legacy_pairing_oob_request_reply( + connection_handle_t connection, + const oob_tk_t& oob_data +) { + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + BLE_GAP_AUTH_KEY_TYPE_OOB, + oob_data.data() + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::confirmation_entered( + connection_handle_t connection, bool confirmation +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + confirmation ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, + NULL + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::send_keypress_notification( + connection_handle_t connection, Keypress_t keypress +) { + uint32_t err = sd_ble_gap_keypress_notify( + connection, + static_cast(keypress) + ); + return convert_sd_error(err); +} + + +ble_error_t nRF5xSecurityManager::generate_secure_connections_oob() +{ +#if defined(MBEDTLS_ECDH_C) + ble_gap_lesc_p256_pk_t own_secret; + ble_gap_lesc_oob_data_t oob_data; + + memcpy(own_secret.pk, secret.data(), secret.size()); + + uint32_t err = sd_ble_gap_lesc_oob_data_get( + BLE_CONN_HANDLE_INVALID, + &own_secret, + &oob_data + ); + + if (!err) { + get_event_handler()->on_secure_connections_oob_generated( + oob_data.r, + oob_data.c + ); + } + + return convert_sd_error(err); +#endif + return BLE_ERROR_NOT_IMPLEMENTED; +} + +nRF5xSecurityManager& nRF5xSecurityManager::get_security_manager() +{ + static nRF5xSecurityManager _security_manager; + return _security_manager; +} + +bool nRF5xSecurityManager::sm_handler(const ble_evt_t *evt) +{ + nRF5xSecurityManager& self = nRF5xSecurityManager::get_security_manager(); + SecurityManager::EventHandler* handler = self.get_event_handler(); + + if ((evt == NULL) || (handler == NULL)) { + return false; + } + + const ble_gap_evt_t& gap_evt = evt->evt.gap_evt; + uint16_t connection = gap_evt.conn_handle; + pairing_control_block_t* pairing_cb = self.get_pairing_cb(connection); + + switch (evt->header.evt_id) { + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { + const ble_gap_sec_params_t& params = + gap_evt.params.sec_params_request.peer_params; + + KeyDistribution initiator_dist( + params.kdist_peer.enc, + params.kdist_peer.id, + params.kdist_peer.sign, + params.kdist_peer.link + ); + + KeyDistribution responder_dist( + params.kdist_own.enc, + params.kdist_own.id, + params.kdist_own.sign, + params.kdist_own.link + ); + + if (pairing_cb && pairing_cb->role == PAIRING_INITIATOR) { + // when this event is received by an initiator, it should not be + // forwarded via the handler; this is not a behaviour expected + // by the bluetooth standard ... + ble_gap_sec_keyset_t keyset = make_keyset( + *pairing_cb, + initiator_dist, + responder_dist + ); + uint32_t err = sd_ble_gap_sec_params_reply( + connection, + /* status */ BLE_GAP_SEC_STATUS_SUCCESS, + /* params */ NULL, + /* keys ... */ &keyset + ); + + // in case of error; release the pairing control block and signal + // it to the event handler + if (err) { + release_pairing_cb(pairing_cb); + handler->on_pairing_error( + connection, + pairing_failure_t::UNSPECIFIED_REASON + ); + } + } else { + handler->on_pairing_request( + connection, + params.oob, + AuthenticationMask( + params.bond, + params.mitm, + params.lesc, + params.keypress + ), + initiator_dist, + responder_dist + ); + } + return true; + } + + case BLE_GAP_EVT_SEC_INFO_REQUEST: { + const ble_gap_evt_sec_info_request_t& req = + gap_evt.params.sec_info_request; + + handler->on_ltk_request( + connection, + ediv_t((uint8_t*)(&req.master_id.ediv)), + rand_t(req.master_id.rand) + ); + + return true; + } + + case BLE_GAP_EVT_PASSKEY_DISPLAY: { + const ble_gap_evt_passkey_display_t& req = + gap_evt.params.passkey_display; + + if (req.match_request == 0) { + handler->on_passkey_display( + connection, + PasskeyAscii::to_num(req.passkey) + ); + } else { + handler->on_passkey_display( + connection, + PasskeyAscii::to_num(req.passkey) + ); + handler->on_confirmation_request(connection); + } + + return true; + } + + case BLE_GAP_EVT_KEY_PRESSED: { + handler->on_keypress_notification( + connection, + (Keypress_t)gap_evt.params.key_pressed.kp_not + ); + return true; + } + + case BLE_GAP_EVT_AUTH_KEY_REQUEST: { + uint8_t key_type = gap_evt.params.auth_key_request.key_type; + + switch (key_type) { + case BLE_GAP_AUTH_KEY_TYPE_NONE: // Illegal + break; + + case BLE_GAP_AUTH_KEY_TYPE_PASSKEY: + handler->on_passkey_request(connection); + break; + + case BLE_GAP_AUTH_KEY_TYPE_OOB: + handler->on_legacy_pairing_oob_request(connection); + break; + } + + return true; + } + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { +#if defined(MBEDTLS_ECDH_C) + const ble_gap_evt_lesc_dhkey_request_t& dhkey_request = + gap_evt.params.lesc_dhkey_request; + + static const size_t key_size = public_key_coord_t::size_; + ble_gap_lesc_dhkey_t shared_secret; + + _crypto.generate_shared_secret( + make_const_ArrayView(dhkey_request.p_pk_peer->pk), + make_const_ArrayView(dhkey_request.p_pk_peer->pk + key_size), + make_const_ArrayView(secret), + shared_secret.key + ); + + sd_ble_gap_lesc_dhkey_reply(connection, &shared_secret); + + if (dhkey_request.oobd_req) { + handler->on_secure_connections_oob_request(connection); + } +#endif + return true; + } + + case BLE_GAP_EVT_AUTH_STATUS: { + const ble_gap_evt_auth_status_t& status = gap_evt.params.auth_status; + + switch (status.auth_status) { + // NOTE: pairing_cb must be valid if this event has been + // received as it is being allocated earlier and release + // in this block + // The memory is released before the last call to the event handler + // to free the heap a bit before subsequent allocation with user + // code. + case BLE_GAP_SEC_STATUS_SUCCESS: { + KeyDistribution own_dist; + KeyDistribution peer_dist; + + if (pairing_cb->role == PAIRING_INITIATOR) { + own_dist = pairing_cb->initiator_dist; + peer_dist = pairing_cb->responder_dist; + } else { + own_dist = pairing_cb->responder_dist; + peer_dist = pairing_cb->initiator_dist; + } + + if (own_dist.get_encryption()) { + handler->on_keys_distributed_local_ltk( + connection, + ltk_t(pairing_cb->own_enc_key.enc_info.ltk) + ); + + handler->on_keys_distributed_local_ediv_rand( + connection, + ediv_t(reinterpret_cast( + &pairing_cb->own_enc_key.master_id.ediv + )), + pairing_cb->own_enc_key.master_id.rand + ); + } + + if (peer_dist.get_encryption()) { + handler->on_keys_distributed_ltk( + connection, + ltk_t(pairing_cb->peer_enc_key.enc_info.ltk) + ); + + handler->on_keys_distributed_ediv_rand( + connection, + ediv_t(reinterpret_cast( + &pairing_cb->peer_enc_key.master_id.ediv + )), + pairing_cb->peer_enc_key.master_id.rand + ); + } + + if (peer_dist.get_identity()) { + handler->on_keys_distributed_irk( + connection, + irk_t(pairing_cb->peer_id_key.id_info.irk) + ); + + advertising_peer_address_type_t + address_type(advertising_peer_address_type_t::PUBLIC); + + if (pairing_cb->peer_id_key.id_addr_info.addr_type) { + address_type = advertising_peer_address_type_t::RANDOM; + } + + handler->on_keys_distributed_bdaddr( + connection, + address_type, + ble::address_t(pairing_cb->peer_id_key.id_addr_info.addr) + ); + } + + if (peer_dist.get_signing()) { + handler->on_keys_distributed_csrk( + connection, + pairing_cb->peer_sign_key.csrk + ); + } + + self.release_pairing_cb(pairing_cb); + handler->on_pairing_completed(connection); + break; + } + + case BLE_GAP_SEC_STATUS_TIMEOUT: + self.release_pairing_cb(pairing_cb); + handler->on_pairing_timed_out(connection); + break; + + case BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED: + case BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE: + case BLE_GAP_SEC_STATUS_AUTH_REQ: + case BLE_GAP_SEC_STATUS_CONFIRM_VALUE: + case BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP: + case BLE_GAP_SEC_STATUS_ENC_KEY_SIZE: + case BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED: + case BLE_GAP_SEC_STATUS_UNSPECIFIED: + case BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS: + case BLE_GAP_SEC_STATUS_INVALID_PARAMS: + case BLE_GAP_SEC_STATUS_DHKEY_FAILURE: + case BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE: + case BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG: + case BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED: + self.release_pairing_cb(pairing_cb); + handler->on_pairing_error( + connection, + (pairing_failure_t::type) (status.auth_status & 0xF) + ); + break; + + default: + self.release_pairing_cb(pairing_cb); + break; + } + + return true; + } + + case BLE_GAP_EVT_CONN_SEC_UPDATE: { + const ble_gap_evt_conn_sec_update_t& req = + gap_evt.params.conn_sec_update; + + if((req.conn_sec.sec_mode.sm == 1) && (req.conn_sec.sec_mode.lv >= 2)) { + handler->on_link_encryption_result( + connection, link_encryption_t::ENCRYPTED + ); + } else { + handler->on_link_encryption_result( + connection, link_encryption_t::NOT_ENCRYPTED + ); + } + return true; + } + + case BLE_GAP_EVT_TIMEOUT: { + switch (gap_evt.params.timeout.src) { + case BLE_GAP_TIMEOUT_SRC_SECURITY_REQUEST: + // Note: pairing_cb does not exist at this point; it is + // created when the module receive the pairing request. + handler->on_link_encryption_request_timed_out(connection); + return true; + + // FIXME: enable with latest SDK +#if 0 + case BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD: + handler->on_valid_mic_timeout(connection); + return true; +#endif + default: + return false; + } + return false; + } + + case BLE_GAP_EVT_SEC_REQUEST: { + const ble_gap_evt_sec_request_t& req = gap_evt.params.sec_request; + handler->on_slave_security_request( + connection, + AuthenticationMask(req.bond, req.mitm, req.lesc, req.keypress) + ); + return true; + } + + default: + return false; + } +} + +ble_gap_sec_params_t nRF5xSecurityManager::make_security_params( + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + ble_gap_sec_params_t security_params = { + /* bond */ authentication_requirements.get_bondable(), + /* mitm */ authentication_requirements.get_mitm(), + /* lesc */ authentication_requirements.get_secure_connections(), + /* keypress */ authentication_requirements.get_keypress_notification(), + /* io_caps */ _io_capability.value(), + /* oob */ oob_data_flag, + /* min_key_size */ _min_encryption_key_size, + /* max_key_size */ _max_encryption_key_size, + /* kdist_periph */ { + /* enc */ responder_dist.get_encryption(), + /* id */ responder_dist.get_identity(), + /* sign */ responder_dist.get_signing(), + /* link */ responder_dist.get_link() + }, + /* kdist_central */ { + /* enc */ initiator_dist.get_encryption(), + /* id */ initiator_dist.get_identity(), + /* sign */ initiator_dist.get_signing(), + /* link */ initiator_dist.get_link() + } + }; + return security_params; +} + +ble_gap_sec_keyset_t nRF5xSecurityManager::make_keyset( + pairing_control_block_t& pairing_cb, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + pairing_cb.initiator_dist = initiator_dist; + pairing_cb.responder_dist = responder_dist; + + KeyDistribution* own_dist = NULL; + KeyDistribution* peer_dist = NULL; + + if (pairing_cb.role == PAIRING_INITIATOR) { + own_dist = &initiator_dist; + peer_dist = &responder_dist; + } else { + own_dist = &responder_dist; + peer_dist = &initiator_dist; + } + + ble_gap_sec_keyset_t keyset = { + /* keys_own */ { + own_dist->get_encryption() ? &pairing_cb.own_enc_key : NULL, + own_dist->get_identity() ? &pairing_cb.own_id_key : NULL, + own_dist->get_signing() ? &pairing_cb.own_sign_key : NULL, + &pairing_cb.own_pk + }, + /* keys_peer */ { + peer_dist->get_encryption() ? &pairing_cb.peer_enc_key : NULL, + peer_dist->get_identity() ? &pairing_cb.peer_id_key : NULL, + peer_dist->get_signing() ? &pairing_cb.peer_sign_key : NULL, + &pairing_cb.peer_pk + } + }; + + // copy csrk if necessary + if (keyset.keys_own.p_sign_key) { + memcpy(keyset.keys_own.p_sign_key->csrk, _csrk.data(), _csrk.size()); + } + + // copy public keys used +#if defined(MBEDTLS_ECDH_C) + memcpy(pairing_cb.own_pk.pk, X.data(), X.size()); + memcpy(pairing_cb.own_pk.pk + X.size(), Y.data(), Y.size()); +#endif + return keyset; +} + +nRF5xSecurityManager::pairing_control_block_t* +nRF5xSecurityManager::allocate_pairing_cb(connection_handle_t connection) +{ + pairing_control_block_t* pairing_cb = + new (std::nothrow) pairing_control_block_t(); + if (pairing_cb) { + pairing_cb->next = _control_blocks; + _control_blocks = pairing_cb; + } + return pairing_cb; +} + +void nRF5xSecurityManager::release_pairing_cb(pairing_control_block_t* pairing_cb) +{ + if (pairing_cb == _control_blocks) { + _control_blocks = _control_blocks->next; + delete pairing_cb; + } else { + pairing_control_block_t* it = _control_blocks; + while (it->next) { + if (it->next == pairing_cb) { + it->next = pairing_cb->next; + delete pairing_cb; + return; + } + it = it->next; + } + } +} + +nRF5xSecurityManager::pairing_control_block_t* +nRF5xSecurityManager::get_pairing_cb(connection_handle_t connection) +{ + pairing_control_block_t* pcb = _control_blocks; + while (pcb) { + if (pcb->connection == connection) { + return pcb; + } + pcb = pcb->next; + } + + return NULL; +} + +void nRF5xSecurityManager::release_all_pairing_cb() +{ + while(_control_blocks) { + release_pairing_cb(_control_blocks); + } +} + +} // nordic +} // vendor +} // pal +} // ble + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.h new file mode 100644 index 0000000000..46482fcee4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xPalSecurityManager.h @@ -0,0 +1,408 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NRF5X_PAL_SECURITY_MANAGER_ +#define NRF5X_PAL_SECURITY_MANAGER_ + +#include "ble/BLETypes.h" +#include "ble/pal/PalSecurityManager.h" +#include "nrf_ble.h" +#include "nRF5xCrypto.h" + + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +class nRF5xSecurityManager : public ::ble::pal::SecurityManager { +public: + nRF5xSecurityManager(); + + virtual ~nRF5xSecurityManager(); + + //////////////////////////////////////////////////////////////////////////// + // SM lifecycle management + // + + /** + * @see ::ble::pal::SecurityManager::initialize + */ + virtual ble_error_t initialize(); + + /** + * @see ::ble::pal::SecurityManager::terminate + */ + virtual ble_error_t terminate(); + + /** + * @see ::ble::pal::SecurityManager::reset + */ + virtual ble_error_t reset() ; + + //////////////////////////////////////////////////////////////////////////// + // Resolving list management + // + + /** + * @see ::ble::pal::SecurityManager::read_resolving_list_capacity + */ + virtual uint8_t read_resolving_list_capacity(); + + /** + * @see ::ble::pal::SecurityManager::add_device_to_resolving_list + */ + virtual ble_error_t add_device_to_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address, + const irk_t &peer_irk + ); + + /** + * @see ::ble::pal::SecurityManager::remove_device_from_resolving_list + */ + virtual ble_error_t remove_device_from_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address + ); + + /** + * @see ::ble::pal::SecurityManager::clear_resolving_list + */ + virtual ble_error_t clear_resolving_list(); + + /** + * An entry of the resolving list stored in the SecurityManager. + */ + struct resolving_list_entry_t { + resolving_list_entry_t() : + peer_identity_address_type( + advertising_peer_address_type_t::PUBLIC_ADDRESS + ) + { } + + irk_t peer_irk; + address_t peer_identity_address; + advertising_peer_address_type_t peer_identity_address_type; + }; + + /** + * Return the IRKs present in the resolving list + * @param count The number of entries present in the resolving list. + * @param pointer to the first entry of the resolving list. + */ + ArrayView get_resolving_list(); + + /** + * Try to resolve a private resolvable address. + * + * @param resolvable_address The address to resolve. + * + * @return Pointer to the entry found if any. + */ + const resolving_list_entry_t* resolve_address( + const address_t& resolvable_address + ); + + + //////////////////////////////////////////////////////////////////////////// + // Pairing + // + + /** + * @see ::ble::pal::SecurityManager::send_pairing_request + */ + virtual ble_error_t send_pairing_request( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + /** + * @see ::ble::pal::SecurityManager::send_pairing_response + */ + virtual ble_error_t send_pairing_response( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + /** + * @see ::ble::pal::SecurityManager::cancel_pairing + */ + virtual ble_error_t cancel_pairing( + connection_handle_t connection, pairing_failure_t reason + ); + + + //////////////////////////////////////////////////////////////////////////// + // Feature support + // + + /** + * @see ::ble::pal::SecurityManager::get_secure_connections_support + */ + virtual ble_error_t get_secure_connections_support( + bool &enabled + ); + + /** + * @see ::ble::pal::SecurityManager::set_io_capability + */ + virtual ble_error_t set_io_capability(io_capability_t io_capability); + + //////////////////////////////////////////////////////////////////////////// + // Security settings + // + + /** + * @see ::ble::pal::SecurityManager::set_authentication_timeout + */ + virtual ble_error_t set_authentication_timeout( + connection_handle_t, uint16_t timeout_in_10ms + ); + + /** + * @see ::ble::pal::SecurityManager::get_authentication_timeout + */ + virtual ble_error_t get_authentication_timeout( + connection_handle_t, uint16_t &timeout_in_10ms + ); + + /** + * @see ::ble::pal::SecurityManager::set_encryption_key_requirements + */ + virtual ble_error_t set_encryption_key_requirements( + uint8_t min_encryption_key_size, + uint8_t max_encryption_key_size + ); + + /** + * @see ::ble::pal::SecurityManager::slave_security_request + */ + virtual ble_error_t slave_security_request( + connection_handle_t connection, + AuthenticationMask authentication + ); + + //////////////////////////////////////////////////////////////////////////// + // Encryption + // + + /** + * @see ::ble::pal::SecurityManager::enable_encryption + */ + virtual ble_error_t enable_encryption( + connection_handle_t connection, + const ltk_t <k, + const rand_t &rand, + const ediv_t &ediv, + bool mitm + ); + + /** + * @see ::ble::pal::SecurityManager::enable_encryption + */ + virtual ble_error_t enable_encryption( + connection_handle_t connection, + const ltk_t <k, + bool mitm + ) ; + + /** + * @see ::ble::pal::SecurityManager::encrypt_data + */ + virtual ble_error_t encrypt_data( + const byte_array_t<16> &key, + encryption_block_t &data + ); + + //////////////////////////////////////////////////////////////////////////// + // Privacy + // + + /** + * @see ::ble::pal::SecurityManager::set_private_address_timeout + */ + virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds); + + //////////////////////////////////////////////////////////////////////////// + // Keys + // + + /** + * @see ::ble::pal::SecurityManager::set_ltk + */ + virtual ble_error_t set_ltk( + connection_handle_t connection, + const ltk_t <k, + bool mitm, + bool secure_connections + ); + + /** + * @see ::ble::pal::SecurityManager::set_ltk_not_found + */ + virtual ble_error_t set_ltk_not_found( + connection_handle_t connection + ); + + /** + * @see ::ble::pal::SecurityManager::set_irk + */ + virtual ble_error_t set_irk(const irk_t &irk); + + /** + * @see ::ble::pal::SecurityManager::set_csrk + */ + virtual ble_error_t set_csrk(const csrk_t &csrk, sign_count_t sign_counter); + + /** + * @see ::ble::pal::SecurityManager::set_peer_csrk + */ + virtual ble_error_t set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk, + bool authenticated, + sign_count_t sign_counter + ); + + /** + * @see ::ble::pal::SecurityManager::remove_peer_csrk + */ + virtual ble_error_t remove_peer_csrk(connection_handle_t connection); + + + //////////////////////////////////////////////////////////////////////////// + // Authentication + // + + /** + * @see ::ble::pal::SecurityManager::get_random_data + */ + virtual ble_error_t get_random_data(byte_array_t<8> &random_data); + + //////////////////////////////////////////////////////////////////////////// + // MITM + // + + /** + * @see ::ble::pal::SecurityManager::set_display_passkey + */ + virtual ble_error_t set_display_passkey(passkey_num_t passkey); + + /** + * @see ::ble::pal::SecurityManager::passkey_request_reply + */ + virtual ble_error_t passkey_request_reply( + connection_handle_t connection, + passkey_num_t passkey + ); + + /** + * @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply + */ + virtual ble_error_t secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm + ); + + /** + * @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply + */ + virtual ble_error_t legacy_pairing_oob_request_reply( + connection_handle_t connection, + const oob_tk_t &oob_data + ); + + /** + * @see ::ble::pal::SecurityManager::confirmation_entered + */ + virtual ble_error_t confirmation_entered( + connection_handle_t connection, bool confirmation + ); + + /** + * @see ::ble::pal::SecurityManager::send_keypress_notification + */ + virtual ble_error_t send_keypress_notification( + connection_handle_t connection, Keypress_t keypress + ); + + /** + * @see ::ble::pal::SecurityManager::generate_secure_connections_oob + */ + virtual ble_error_t generate_secure_connections_oob(); + + // singleton of nordic Security Manager + static nRF5xSecurityManager& get_security_manager(); + + // Event handler + bool sm_handler(const ble_evt_t *evt); + +private: + csrk_t _csrk; + sign_count_t _sign_counter; + io_capability_t _io_capability; + uint8_t _min_encryption_key_size; + uint8_t _max_encryption_key_size; + + struct pairing_control_block_t; + + ble_gap_sec_params_t make_security_params( + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + ble_gap_sec_keyset_t make_keyset( + pairing_control_block_t& pairing_cb, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + pairing_control_block_t* allocate_pairing_cb(connection_handle_t connection); + void release_pairing_cb(pairing_control_block_t* pairing_cb); + pairing_control_block_t* get_pairing_cb(connection_handle_t connection); + void release_all_pairing_cb(); + + pairing_control_block_t* _control_blocks; +#if defined(MBEDTLS_ECDH_C) + CryptoToolbox _crypto; + ble::public_key_coord_t X; + ble::public_key_coord_t Y; + ble::public_key_coord_t secret; +#endif + + static const size_t MAX_RESOLVING_LIST_ENTRIES = BLE_GAP_WHITELIST_IRK_MAX_COUNT; + + size_t resolving_list_entry_count; + resolving_list_entry_t resolving_list[MAX_RESOLVING_LIST_ENTRIES]; +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif /* NRF5X_PAL_SECURITY_MANAGER_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.cpp new file mode 100644 index 0000000000..0b2eda1f80 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.cpp @@ -0,0 +1,242 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#include "nRF5xn.h" +#include "ble/blecommon.h" +#include "nrf_soc.h" + +#include "btle/btle.h" +#include "btle/custom/custom_helper.h" +#include "nrf_delay.h" + +extern "C" { +#include "softdevice_handler.h" +} + +#include "nRF5xPalGattClient.h" + +/** + * The singleton which represents the nRF51822 transport for the BLE. + */ +static nRF5xn& getDeviceInstance() { + static nRF5xn deviceInstance; + return deviceInstance; +} + + +/** + * BLE-API requires an implementation of the following function in order to + * obtain its transport handle. + */ +BLEInstanceBase * +createBLEInstance(void) +{ + return &nRF5xn::Instance(BLE::DEFAULT_INSTANCE); +} + +nRF5xn& nRF5xn::Instance(BLE::InstanceID_t instanceId) +{ + return getDeviceInstance(); +} + +nRF5xn::nRF5xn(void) : + initialized(false), + instanceID(BLE::DEFAULT_INSTANCE), + gapInstance(), + gattServerInstance(NULL), + gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client())) +{ +} + +nRF5xn::~nRF5xn(void) +{ +} + +const char *nRF5xn::getVersion(void) +{ + if (!initialized) { + return "INITIALIZATION_INCOMPLETE"; + } + + static char versionString[32]; + static bool versionFetched = false; + + if (!versionFetched) { + ble_version_t version; + if ((sd_ble_version_get(&version) == NRF_SUCCESS) && (version.company_id == 0x0059)) { + switch (version.version_number) { + case 0x07: + case 0x08: + snprintf(versionString, sizeof(versionString), "Nordic BLE4.1 ver:%u fw:%04x", version.version_number, version.subversion_number); + break; + default: + snprintf(versionString, sizeof(versionString), "Nordic (spec unknown) ver:%u fw:%04x", version.version_number, version.subversion_number); + break; + } + versionFetched = true; + } else { + strncpy(versionString, "unknown", sizeof(versionString)); + } + } + + return versionString; +} + +/**************************************************************************/ +/*! + @brief Initialize the BLE stack. + + @returns ble_error_t + + @retval BLE_ERROR_NONE if everything executed properly and + BLE_ERROR_ALREADY_INITIALIZED if the stack has already + been initialized (possibly through a call to nRF5xn::init()). + BLE_ERROR_INTERNAL_STACK_FAILURE is returned if initialization + of the internal stack (SoftDevice) failed. + +*/ +/**************************************************************************/ +ble_error_t nRF5xn::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback) +{ + if (initialized) { + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_ALREADY_INITIALIZED + }; + callback.call(&context); + return BLE_ERROR_ALREADY_INITIALIZED; + } + + this->instanceID = instanceID; + + /* ToDo: Clear memory contents, reset the SD, etc. */ + if (btle_init() != ERROR_NONE) { + return BLE_ERROR_INTERNAL_STACK_FAILURE; + } + + initialized = true; + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_NONE + }; + callback.call(&context); + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Purge the BLE stack of GATT and GAP state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @note When using S110, GattClient::shutdown() will not be called + since Gatt client features are not supported. +*/ +/**************************************************************************/ +ble_error_t nRF5xn::shutdown(void) +{ + if (!initialized) { + return BLE_ERROR_INITIALIZATION_INCOMPLETE; + } + + /* + * Shutdown the SoftDevice first. This is because we need to disable all + * interrupts. Otherwise if we clear the BLE API and glue code first there + * will be many NULL references and no config information which could lead + * to errors if the shutdown process is interrupted. + */ + if (softdevice_handler_sd_disable() != NRF_SUCCESS) { + return BLE_STACK_BUSY; + } + + /* Shutdown the BLE API and nRF51 glue code */ + ble_error_t error; + + if (gattServerInstance != NULL) { + error = gattServerInstance->reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + } + + /* S110 does not support BLE client features, nothing to reset. */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + error = getGattClient().reset(); + if (error != BLE_ERROR_NONE) { + return error; + } +#endif + + /* Gap instance is always present */ + error = gapInstance.reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + + custom_reset_128bits_uuid_table(); + + initialized = false; + return BLE_ERROR_NONE; +} + +SecurityManager& nRF5xn::getSecurityManager() +{ + const nRF5xn* self = this; + return const_cast(self->getSecurityManager()); +} + +const SecurityManager& nRF5xn::getSecurityManager() const +{ + ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = + ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager(); + static struct : ble::pal::SigningEventMonitor { + virtual void set_signing_event_handler(EventHandler *signing_event_handler) { } + } dummy_signing_event_monitor; + + static ble::generic::GenericSecurityManager m_instance( + m_pal, + const_cast(getGap()), + dummy_signing_event_monitor + ); + + return m_instance; +} + +void +nRF5xn::waitForEvent(void) +{ + processEvents(); + sd_app_evt_wait(); +} + +void nRF5xn::processEvents() { + core_util_critical_section_enter(); + if (isEventsSignaled) { + isEventsSignaled = false; + core_util_critical_section_exit(); + intern_softdevice_events_execute(); + } else { + core_util_critical_section_exit(); + } +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.h new file mode 100644 index 0000000000..74836bb255 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/nRF5xn.h @@ -0,0 +1,156 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF51822_H__ +#define __NRF51822_H__ + +#include "ble/BLE.h" +#include "ble/blecommon.h" +#include "ble/BLEInstanceBase.h" +#include "ble/generic/GenericGattClient.h" +#include "ble/generic/GenericSecurityManager.h" +#include "nRF5xPalSecurityManager.h" + +#include "nRF5xGap.h" +#include "nRF5xGattServer.h" + +#include "btle.h" + +class nRF5xn : public BLEInstanceBase +{ +public: + nRF5xn(void); + virtual ~nRF5xn(void); + + virtual ble_error_t init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback); + virtual bool hasInitialized(void) const { + return initialized; + } + virtual ble_error_t shutdown(void); + virtual const char *getVersion(void); + + /** + * Accessors to GAP. This function checks whether gapInstance points to an + * object. If if does not, then the gapInstance is updated to + * &_getInstance before returning. + * + * @return A reference to GattServer. + * + * @note Unlike the GattClient, GattServer and SecurityManager, Gap is + * always needed in a BLE application. Therefore it is allocated + * statically. + */ + virtual nRF5xGap &getGap() { + return gapInstance; + }; + + /** + * Accessors to GATT Server. This function checks whether a GattServer + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A reference to GattServer. + */ + virtual GattServer &getGattServer() { + if (gattServerInstance == NULL) { + gattServerInstance = new nRF5xGattServer(); + } + return *gattServerInstance; + }; + + /** + * Accessors to GATT Client. This function checks whether a GattClient + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A reference to GattClient. + */ + virtual GattClient &getGattClient() { + return gattClient; + } + + /** + * @see BLEInstanceBase::getSecurityManager + */ + virtual SecurityManager &getSecurityManager(); + + /** + * @see BLEInstanceBase::getSecurityManager + */ + virtual const SecurityManager &getSecurityManager() const; + + /** + * Accessors to GAP. This function checks whether gapInstance points to an + * object. If if does not, then the gapInstance is updated to + * &_getInstance before returning. + * + * @return A const reference to GattServer. + * + * @note Unlike the GattClient, GattServer and SecurityManager, Gap is + * always needed in a BLE application. Therefore it is allocated + * statically. + * + * @note The accessor is able to modify the object's state because the + * internal pointer has been declared mutable. + */ + virtual const nRF5xGap &getGap() const { + return gapInstance; + }; + + /** + * Accessors to GATT Server. This function checks whether a GattServer + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A const reference to GattServer. + * + * @note The accessor is able to modify the object's state because the + * internal pointer has been declared mutable. + */ + virtual const nRF5xGattServer &getGattServer() const { + if (gattServerInstance == NULL) { + gattServerInstance = new nRF5xGattServer(); + } + return *gattServerInstance; + }; + + virtual void waitForEvent(void); + + virtual void processEvents(); + +public: + static nRF5xn& Instance(BLE::InstanceID_t instanceId = BLE::DEFAULT_INSTANCE); + +private: + bool initialized; + BLE::InstanceID_t instanceID; + +private: + mutable nRF5xGap gapInstance; /**< Gap instance whose reference is returned from a call to + * getGap(). Unlike the GattClient, GattServer and + * SecurityManager, Gap is always needed in a BLE application. */ + +private: + mutable nRF5xGattServer *gattServerInstance; /**< Pointer to the GattServer object instance. + * If NULL, then GattServer has not been initialized. + * The pointer has been declared as 'mutable' so that + * it can be assigned inside a 'const' function. */ + ble::generic::GenericGattClient gattClient; + + +}; + +#endif diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/projectconfig.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/projectconfig.h new file mode 100644 index 0000000000..15959850c4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/projectconfig.h @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PROJECTCONFIG_H_ +#define _PROJECTCONFIG_H_ + +#include "ble/GapAdvertisingData.h" + +/*========================================================================= + MCU & BOARD SELCTION + + CFG_BOARD is one of the value defined in board.h + -----------------------------------------------------------------------*/ + #define CFG_BOARD BOARD_PCA10001 + #define CFG_MCU_STRING "nRF51822" +/*=========================================================================*/ + + +/*========================================================================= + CODE BASE VERSION SETTINGS + + Please do not modify this version number. To set a version number + for your project or firmware, change the values in your 'boards/' + config file. + -----------------------------------------------------------------------*/ + #define CFG_CODEBASE_VERSION_MAJOR 0 + #define CFG_CODEBASE_VERSION_MINOR 1 + #define CFG_CODEBASE_VERSION_REVISION 0 +/*=========================================================================*/ + + +/*========================================================================= + FIRMWARE VERSION SETTINGS + -----------------------------------------------------------------------*/ + #define CFG_FIRMWARE_VERSION_MAJOR 0 + #define CFG_FIRMWARE_VERSION_MINOR 0 + #define CFG_FIRMWARE_VERSION_REVISION 0 +/*=========================================================================*/ + + +/*========================================================================= + DEBUG LEVEL + ----------------------------------------------------------------------- + + CFG_DEBUG Level 3: Full debug output, any failed assert + will produce a breakpoint for the + debugger + Level 2: ATTR_ALWAYS_INLINE is null, ASSERT + has text + Level 1: ATTR_ALWAYS_INLINE is an attribute, + ASSERT has no text + Level 0: No debug information generated + + -----------------------------------------------------------------------*/ + #define CFG_DEBUG (1) + + #if (CFG_DEBUG > 3) || (CFG_DEBUG < 0) + #error "CFG_DEBUG must be a value between 0 (no debug) and 3" + #endif +/*=========================================================================*/ + + +/*========================================================================= + GENERAL NRF51 PERIPHERAL SETTINGS + ----------------------------------------------------------------------- + + CFG_SCHEDULER_ENABLE Set this to 'true' or 'false' depending on + if you use the event scheduler or not + + -----------------------------------------------------------------------*/ + #define CFG_SCHEDULER_ENABLE false + + /*------------------------------- GPIOTE ------------------------------*/ + #define CFG_GPIOTE_MAX_USERS 1 /**< Maximum number of users of the GPIOTE handler. */ + + /*-------------------------------- TIMER ------------------------------*/ + #define CFG_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. freq = (32768/(PRESCALER+1)) */ + #define CFG_TIMER_MAX_INSTANCE 1 /**< Maximum number of simultaneously created timers. */ + #define CFG_TIMER_OPERATION_QUEUE_SIZE 2 /**< Size of timer operation queues. */ +/*=========================================================================*/ + + +/*========================================================================= + BTLE SETTINGS + -----------------------------------------------------------------------*/ + + #define CFG_BLE_TX_POWER_LEVEL 0 /**< in dBm (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ + + /*---------------------------- BOND MANAGER ---------------------------*/ + #define CFG_BLE_BOND_FLASH_PAGE_BOND (BLE_FLASH_PAGE_END-1) /**< Flash page used for bond manager bonding information.*/ + #define CFG_BLE_BOND_FLASH_PAGE_SYS_ATTR (BLE_FLASH_PAGE_END-3) /**< Flash page used for bond manager system attribute information. TODO check if we can use BLE_FLASH_PAGE_END-2*/ + #define CFG_BLE_BOND_DELETE_BUTTON_NUM 0 /**< Button to press to delete bond details during init */ + + /*------------------------------ SECURITY -----------------------------*/ + #define CFG_BLE_SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ + #define CFG_BLE_SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ + #define CFG_BLE_SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ + #define CFG_BLE_SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ + #define CFG_BLE_SEC_PARAM_MAX_KEY_SIZE 16 + + /*--------------------------------- GAP -------------------------------*/ + #define CFG_GAP_APPEARANCE GapAdvertisingData::GENERIC_TAG + #define CFG_GAP_LOCAL_NAME "nRF5x" + + #define CFG_GAP_CONNECTION_MIN_INTERVAL_MS 50 /**< Minimum acceptable connection interval */ + #define CFG_GAP_CONNECTION_MAX_INTERVAL_MS 500 /**< Maximum acceptable connection interval */ + #define CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS 4000 /**< Connection supervisory timeout */ + #define CFG_GAP_CONNECTION_SLAVE_LATENCY 0 /**< Slave Latency in number of connection events. */ + + #define CFG_GAP_ADV_INTERVAL_MS 25 /**< The advertising interval in miliseconds, should be multiply of 0.625 */ + #define CFG_GAP_ADV_TIMEOUT_S 180 /**< The advertising timeout in units of seconds. */ +/*=========================================================================*/ + + +/*========================================================================= + VALIDATION + -----------------------------------------------------------------------*/ + #if CFG_BLE_TX_POWER_LEVEL != -40 && CFG_BLE_TX_POWER_LEVEL != -20 && CFG_BLE_TX_POWER_LEVEL != -16 && CFG_BLE_TX_POWER_LEVEL != -12 && CFG_BLE_TX_POWER_LEVEL != -8 && CFG_BLE_TX_POWER_LEVEL != -4 && CFG_BLE_TX_POWER_LEVEL != 0 && CFG_BLE_TX_POWER_LEVEL != 4 + #error "CFG_BLE_TX_POWER_LEVEL must be -40, -20, -16, -12, -8, -4, 0 or 4" + #endif +/*=========================================================================*/ + +#endif /* _PROJECTCONFIG_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/supress-warnings.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/supress-warnings.cmake new file mode 100644 index 0000000000..60061399da --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF51/source/supress-warnings.cmake @@ -0,0 +1,21 @@ +# Copyright 2015 ARM Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +message("suppressing warnings from ble-nrf51822") + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set_target_properties(ble-nrf51822 + PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers" + ) +endif() diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/CHANGELOG.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/CHANGELOG.md new file mode 100644 index 0000000000..bb4dad9a4a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/CHANGELOG.md @@ -0,0 +1,344 @@ +# Change Log + +## [v2.5.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.3) (2016-02-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.2...v2.5.3) + +**Merged pull requests:** + +- Fix for compilation errors with S110 softdevice in btle.cpp [\#109](https://github.com/ARMmbed/ble-nrf51822/pull/109) ([ddavidebor](https://github.com/ddavidebor)) + +## [v2.5.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.2) (2016-02-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.1...v2.5.2) + +**Merged pull requests:** + +- Sync develop against master [\#113](https://github.com/ARMmbed/ble-nrf51822/pull/113) ([pan-](https://github.com/pan-)) +- Fix incorrect handles of characteristics descriptors. [\#112](https://github.com/ARMmbed/ble-nrf51822/pull/112) ([pan-](https://github.com/pan-)) + +## [v2.5.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.1) (2016-01-27) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.5.0...v2.5.1) + +**Merged pull requests:** + +- Remove Gap::state updates from this module [\#108](https://github.com/ARMmbed/ble-nrf51822/pull/108) ([andresag01](https://github.com/andresag01)) +- merge version [\#106](https://github.com/ARMmbed/ble-nrf51822/pull/106) ([pan-](https://github.com/pan-)) + +## [v2.5.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.5.0) (2016-01-12) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.1...v2.5.0) + +**Merged pull requests:** + +- Fix access to enum member [\#105](https://github.com/ARMmbed/ble-nrf51822/pull/105) ([pan-](https://github.com/pan-)) +- Hotfix dependency [\#104](https://github.com/ARMmbed/ble-nrf51822/pull/104) ([pan-](https://github.com/pan-)) +- Finish implementation of getAddressesFromBondTable [\#103](https://github.com/ARMmbed/ble-nrf51822/pull/103) ([andresag01](https://github.com/andresag01)) + +## [v2.4.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.1) (2016-01-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.4.0...v2.4.1) + +**Merged pull requests:** + +- merge branch develop \(v2.4.0\) [\#100](https://github.com/ARMmbed/ble-nrf51822/pull/100) ([pan-](https://github.com/pan-)) + +## [v2.4.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.4.0) (2016-01-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.1...v2.4.0) + +**Merged pull requests:** + +- Add implementation of experimental whitelisting API [\#99](https://github.com/ARMmbed/ble-nrf51822/pull/99) ([andresag01](https://github.com/andresag01)) + +## [v2.3.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.1) (2016-01-07) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.3.0...v2.3.1) + +**Merged pull requests:** + +- Update yotta module dependencies [\#98](https://github.com/ARMmbed/ble-nrf51822/pull/98) ([pan-](https://github.com/pan-)) + +## [v2.3.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.3.0) (2015-12-23) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.10...v2.3.0) + +**Merged pull requests:** + +- Implementation of Characteristic descriptor discovery [\#74](https://github.com/ARMmbed/ble-nrf51822/pull/74) ([pan-](https://github.com/pan-)) + +## [v2.2.10](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.10) (2015-12-23) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.9...v2.2.10) + +**Fixed bugs:** + +- nRF5xn::init don't verify if errors have occurred during btle\_init [\#59](https://github.com/ARMmbed/ble-nrf51822/issues/59) + +**Closed issues:** + +- A call to shutdown does not clear the state of some components of BLE API [\#85](https://github.com/ARMmbed/ble-nrf51822/issues/85) +- Memory allocation issue on the NRF51DK board. [\#76](https://github.com/ARMmbed/ble-nrf51822/issues/76) +- Terrible handling of initLen / minLen and variable length characteristics. [\#56](https://github.com/ARMmbed/ble-nrf51822/issues/56) + +**Merged pull requests:** + +- Fix shutdown of Gap instance to avoid NULL refs [\#96](https://github.com/ARMmbed/ble-nrf51822/pull/96) ([andresag01](https://github.com/andresag01)) +- Add check for return code of ble\_init [\#95](https://github.com/ARMmbed/ble-nrf51822/pull/95) ([andresag01](https://github.com/andresag01)) + +## [v2.2.9](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.9) (2015-12-18) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.8...v2.2.9) + +**Closed issues:** + +- Cannot open source input file "system\_nrf51.h" [\#52](https://github.com/ARMmbed/ble-nrf51822/issues/52) + +**Merged pull requests:** + +- Remove occurrence of deprecated appearance enum [\#92](https://github.com/ARMmbed/ble-nrf51822/pull/92) ([andresag01](https://github.com/andresag01)) + +## [v2.2.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.8) (2015-12-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.7...v2.2.8) + +## [v2.2.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.7) (2015-12-15) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.6...v2.2.7) + +**Merged pull requests:** + +- Replace deprecated inclusions of mbed.h [\#89](https://github.com/ARMmbed/ble-nrf51822/pull/89) ([andresag01](https://github.com/andresag01)) +- Improve shutdown to clear BLE API and not just SD [\#87](https://github.com/ARMmbed/ble-nrf51822/pull/87) ([andresag01](https://github.com/andresag01)) + +## [v2.2.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.6) (2015-12-15) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.5...v2.2.6) + +**Merged pull requests:** + +- follow the extraction of address related types from Gap.h into BLEProtocol.h [\#88](https://github.com/ARMmbed/ble-nrf51822/pull/88) ([rgrover](https://github.com/rgrover)) + +## [v2.2.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.5) (2015-12-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.3...v2.2.5) + +**Merged pull requests:** + +- Added SecurityManager::setLinkSecurity call for elevating security settings on a particular connection. [\#86](https://github.com/ARMmbed/ble-nrf51822/pull/86) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.2.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.3) (2015-12-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.2...v2.2.3) + +## [v2.2.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.2) (2015-12-08) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.1...v2.2.2) + +**Merged pull requests:** + +- Add -Wno-unused-function to supress-warnings.cmake [\#83](https://github.com/ARMmbed/ble-nrf51822/pull/83) ([andresag01](https://github.com/andresag01)) + +## [v2.2.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.1) (2015-12-08) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.2.0...v2.2.1) + +**Merged pull requests:** + +- WIP: UUID endian change [\#82](https://github.com/ARMmbed/ble-nrf51822/pull/82) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.2.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.2.0) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.4...v2.2.0) + +## [v2.1.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.4) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.3...v2.1.4) + +## [v2.1.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.3) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.2...v2.1.3) + +## [v2.1.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.2) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.1...v2.1.2) + +**Merged pull requests:** + +- Allow GattAttributes to have variable length [\#81](https://github.com/ARMmbed/ble-nrf51822/pull/81) ([andresag01](https://github.com/andresag01)) + +## [v2.1.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.1) (2015-12-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.1.0...v2.1.1) + +**Merged pull requests:** + +- Fixed endianness bug in nRF5xServiceDiscovery::processDiscoverUUIDResponse so it is consistent with BLE API. [\#80](https://github.com/ARMmbed/ble-nrf51822/pull/80) ([marcuschangarm](https://github.com/marcuschangarm)) +- Fixed bug in nRF5xGap.setAddress where random adresses where not set properly. [\#79](https://github.com/ARMmbed/ble-nrf51822/pull/79) ([marcuschangarm](https://github.com/marcuschangarm)) +- Separate concept of minlen and len for BLE chars [\#78](https://github.com/ARMmbed/ble-nrf51822/pull/78) ([andresag01](https://github.com/andresag01)) +- Split nordic sdk into its own module [\#75](https://github.com/ARMmbed/ble-nrf51822/pull/75) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.1.0) (2015-11-27) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.8...v2.1.0) + +**Merged pull requests:** + +- Update to sdk 8.1 [\#77](https://github.com/ARMmbed/ble-nrf51822/pull/77) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.0.8](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.8) (2015-11-26) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.7...v2.0.8) + +## [v2.0.7](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.7) (2015-11-26) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.6...v2.0.7) + +**Closed issues:** + +- test2000 [\#72](https://github.com/ARMmbed/ble-nrf51822/issues/72) +- test1000000 [\#71](https://github.com/ARMmbed/ble-nrf51822/issues/71) +- test4 [\#70](https://github.com/ARMmbed/ble-nrf51822/issues/70) +- test3 [\#69](https://github.com/ARMmbed/ble-nrf51822/issues/69) +- test2 [\#68](https://github.com/ARMmbed/ble-nrf51822/issues/68) + +**Merged pull requests:** + +- use Extern c around \#include to use nordic sdk headers implemented in C [\#73](https://github.com/ARMmbed/ble-nrf51822/pull/73) ([LiyouZhou](https://github.com/LiyouZhou)) + +## [v2.0.6](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.6) (2015-11-17) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.5...v2.0.6) + +**Closed issues:** + +- test [\#66](https://github.com/ARMmbed/ble-nrf51822/issues/66) + +**Merged pull requests:** + +- add Nordic's license agreement. [\#67](https://github.com/ARMmbed/ble-nrf51822/pull/67) ([rgrover](https://github.com/rgrover)) + +## [v2.0.5](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.5) (2015-11-16) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.4...v2.0.5) + +**Merged pull requests:** + +- Post radio notification callback through minar [\#65](https://github.com/ARMmbed/ble-nrf51822/pull/65) ([andresag01](https://github.com/andresag01)) + +## [v2.0.4](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.4) (2015-11-13) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.3...v2.0.4) + +**Merged pull requests:** + +- Fix assembly sequence to start bootloader in GCC [\#64](https://github.com/ARMmbed/ble-nrf51822/pull/64) ([andresag01](https://github.com/andresag01)) + +## [v2.0.3](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.3) (2015-11-09) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.2...v2.0.3) + +**Merged pull requests:** + +- Added watchdog header file from Nordic SDK 8.1 [\#62](https://github.com/ARMmbed/ble-nrf51822/pull/62) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v2.0.2](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.2) (2015-11-03) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-release-15-11...v2.0.2) + +## [mbedos-release-15-11](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-release-15-11) (2015-11-03) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.1...mbedos-release-15-11) + +## [v2.0.1](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.1) (2015-11-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v2.0.0...v2.0.1) + +**Merged pull requests:** + +- Ensure that the initialization flags is set to false if the BLE stack is shutdown properly. [\#58](https://github.com/ARMmbed/ble-nrf51822/pull/58) ([pan-](https://github.com/pan-)) + +## [v2.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v2.0.0) (2015-11-02) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.1.0...v2.0.0) + +**Closed issues:** + +- Nordic SDK and SoftDevice [\#57](https://github.com/ARMmbed/ble-nrf51822/issues/57) +- shouldn't eab6631cb be merged into master? [\#54](https://github.com/ARMmbed/ble-nrf51822/issues/54) + +**Merged pull requests:** + +- Introduced changes for memory savings [\#55](https://github.com/ARMmbed/ble-nrf51822/pull/55) ([andresag01](https://github.com/andresag01)) + +## [v1.1.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.1.0) (2015-10-28) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v1.0.0...v1.1.0) + +**Closed issues:** + +- target dependencies in module.json [\#50](https://github.com/ARMmbed/ble-nrf51822/issues/50) + +**Merged pull requests:** + +- When connecting, if no scanning parameters are passed, use values from Gap parent. [\#53](https://github.com/ARMmbed/ble-nrf51822/pull/53) ([marcuschangarm](https://github.com/marcuschangarm)) + +## [v1.0.0](https://github.com/ARMmbed/ble-nrf51822/tree/v1.0.0) (2015-10-19) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/mbedos-techcon-oob2...v1.0.0) + +## [mbedos-techcon-oob2](https://github.com/ARMmbed/ble-nrf51822/tree/mbedos-techcon-oob2) (2015-10-19) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.8...mbedos-techcon-oob2) + +**Closed issues:** + +- rename the bootloader files with \_fota in the name? [\#51](https://github.com/ARMmbed/ble-nrf51822/issues/51) + +**Merged pull requests:** + +- Update S110 detection macros, again [\#49](https://github.com/ARMmbed/ble-nrf51822/pull/49) ([jpbrucker](https://github.com/jpbrucker)) +- Error check number of characteristics [\#48](https://github.com/ARMmbed/ble-nrf51822/pull/48) ([Timmmm](https://github.com/Timmmm)) + +## [v0.4.8](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.8) (2015-09-25) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.7...v0.4.8) + +**Closed issues:** + +- Error real cause loss in nRF5xGattServer.cpp [\#44](https://github.com/ARMmbed/ble-nrf51822/issues/44) + +**Merged pull requests:** + +- rgrover patch fixed [\#47](https://github.com/ARMmbed/ble-nrf51822/pull/47) ([fabiencomte](https://github.com/fabiencomte)) +- Update S110 detection macros [\#43](https://github.com/ARMmbed/ble-nrf51822/pull/43) ([jpbrucker](https://github.com/jpbrucker)) +- remove some unnecessary include paths [\#42](https://github.com/ARMmbed/ble-nrf51822/pull/42) ([autopulated](https://github.com/autopulated)) +- Add FOTA bootloader image [\#41](https://github.com/ARMmbed/ble-nrf51822/pull/41) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.7](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.7) (2015-08-13) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.6...v0.4.7) + +## [v0.4.6](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.6) (2015-08-11) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.5...v0.4.6) + +**Closed issues:** + +- remove duplication of global static variable BLE\_EVT\_BUFFER [\#39](https://github.com/ARMmbed/ble-nrf51822/issues/39) +- clearScanResponse\(\) [\#30](https://github.com/ARMmbed/ble-nrf51822/issues/30) +- Debug builds fail due to missing bsp.h [\#11](https://github.com/ARMmbed/ble-nrf51822/issues/11) + +**Merged pull requests:** + +- Disable GattClient features when using S110 SoftDevice [\#38](https://github.com/ARMmbed/ble-nrf51822/pull/38) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.5](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.5) (2015-08-10) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.4...v0.4.5) + +## [v0.4.4](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.4) (2015-08-07) +[Full Changelog](https://github.com/ARMmbed/ble-nrf51822/compare/v0.4.3...v0.4.4) + +**Closed issues:** + +- nrf51822 hangs after calling sd\_flash\_page\_erase\(\) [\#35](https://github.com/ARMmbed/ble-nrf51822/issues/35) +- nRF5xn::getVersion return \(Unknown\) with version 8 soft device [\#29](https://github.com/ARMmbed/ble-nrf51822/issues/29) + +**Merged pull requests:** + +- Changed Gap:: to GapAdvertisingParams:: because of change in BLE [\#34](https://github.com/ARMmbed/ble-nrf51822/pull/34) ([jslater8](https://github.com/jslater8)) +- Select the clock source dynamically on SoftDevice initialisation [\#32](https://github.com/ARMmbed/ble-nrf51822/pull/32) ([jpbrucker](https://github.com/jpbrucker)) +- Add S110 SoftDevice compatibility [\#28](https://github.com/ARMmbed/ble-nrf51822/pull/28) ([jpbrucker](https://github.com/jpbrucker)) + +## [v0.4.3](https://github.com/ARMmbed/ble-nrf51822/tree/v0.4.3) (2015-07-22) +**Closed issues:** + +- Target polling failed [\#24](https://github.com/ARMmbed/ble-nrf51822/issues/24) +- support handling of HVX Events \(notifications and indications\). [\#22](https://github.com/ARMmbed/ble-nrf51822/issues/22) +- provide an implementation for GattServer::areUpdatesEnabled\(\) [\#21](https://github.com/ARMmbed/ble-nrf51822/issues/21) +- getValueHandle\(\) returns characteristicIndex instead of attribute-handle [\#20](https://github.com/ARMmbed/ble-nrf51822/issues/20) +- Clash With Definition And Enum Naming [\#16](https://github.com/ARMmbed/ble-nrf51822/issues/16) +- Errors in GCC build [\#14](https://github.com/ARMmbed/ble-nrf51822/issues/14) +- bring s110 support back [\#10](https://github.com/ARMmbed/ble-nrf51822/issues/10) +- Allow adding a User Description descriptor to a GattCharacteristic. [\#9](https://github.com/ARMmbed/ble-nrf51822/issues/9) +- device\_manager\_peripheral.c includes app\_trace.h [\#7](https://github.com/ARMmbed/ble-nrf51822/issues/7) +- linking esb\_gcc.a \(nrf51822 enhanced shock burst\) with mbed [\#5](https://github.com/ARMmbed/ble-nrf51822/issues/5) +- The app\_timer usage may conflict [\#2](https://github.com/ARMmbed/ble-nrf51822/issues/2) +- Nordic License [\#1](https://github.com/ARMmbed/ble-nrf51822/issues/1) + +**Merged pull requests:** + +- Develop [\#25](https://github.com/ARMmbed/ble-nrf51822/pull/25) ([zoujixing](https://github.com/zoujixing)) +- Remove unnecessary 'compiler\_abstraction.h' to get rid of duplicate '… [\#23](https://github.com/ARMmbed/ble-nrf51822/pull/23) ([adfernandes](https://github.com/adfernandes)) +- restructure for minimal yotta compatibility [\#15](https://github.com/ARMmbed/ble-nrf51822/pull/15) ([autopulated](https://github.com/autopulated)) +- Fix various GCC compilation issues. [\#12](https://github.com/ARMmbed/ble-nrf51822/pull/12) ([adfernandes](https://github.com/adfernandes)) +- Fix for GCC lost in SDK v8.0 update [\#8](https://github.com/ARMmbed/ble-nrf51822/pull/8) ([rosterloh](https://github.com/rosterloh)) +- new target DELTA\_DFCM\_NNN40 with nrf51822 chip, config internal RC crystal. [\#6](https://github.com/ARMmbed/ble-nrf51822/pull/6) ([Marcomissyou](https://github.com/Marcomissyou)) +- Updated return value for nRF51GattServer::updateValue. Will now report w... [\#4](https://github.com/ARMmbed/ble-nrf51822/pull/4) ([marcuschangarm](https://github.com/marcuschangarm)) +- Added optional data and length fields to the return struct for authorize... [\#3](https://github.com/ARMmbed/ble-nrf51822/pull/3) ([marcuschangarm](https://github.com/marcuschangarm)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/LICENSE b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/LICENSE new file mode 100644 index 0000000000..60744edab2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/LICENSE @@ -0,0 +1,6 @@ +This module contains softdevice which comes with The Nordic Softdevice License Agreement, +a BSD-like licence for binary distributions, offered by Nordic for use in mbed. Some +other files come from the mbed SDK, and are licensed under Apache-2.0. Unless +specifically indicated otherwise in a file, files are licensed under the +Apache 2.0 license, as can be found in: apache-2.0.txt. The Nordic Semiconductor Softdevice +License Agreement can be found in softdevice_nrf51822_licence_agreement.txt. diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/apache-2.0.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/apache-2.0.txt new file mode 100644 index 0000000000..9327527edd --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/apache-2.0.txt @@ -0,0 +1,13 @@ +Copyright (c) 2015 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/module.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/module.json new file mode 100644 index 0000000000..b45b894f0e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/module.json @@ -0,0 +1,36 @@ +{ + "name": "ble-nrf51822", + "version": "2.7.1", + "description": "Nordic stack and drivers for the mbed BLE API.", + "keywords": [ + "Bluetooth", + "BLE", + "mbed", + "mbed-official" + ], + "author": "Rohit Grover", + "repository": { + "url": "git@github.com:ARMmbed/ble-nRF51822.git", + "type": "git" + }, + "homepage": "https://developer.mbed.org/teams/Nordic-Semiconductor/", + "licenses": [ + { + "url": "https://spdx.org/licenses/Apache-2.0", + "type": "Apache-2.0" + }, + { + "type": "LicenseRef-softdevice_nrf51822_licence_agreement.txt" + } + ], + "dependencies": { + "ble": "^2.6.0", + "nrf51-sdk": "^2.4.0" + }, + "extraIncludes": [ + "source/btle", + "source/btle/custom", + "source/common" + ], + "targetDependencies": {} +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt new file mode 100644 index 0000000000..8e447f4c64 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt @@ -0,0 +1,30 @@ +/* + * S110/S120/S130 License Agreement + * + * Copyright (c) 2015, Nordic Semiconductor ASA, All rights reserved. + * + * Redistribution. Redistribution and use in binary form, without modification, + * are permitted provided that the following conditions are met: + * + * • Redistributions must reproduce the above copyright notice and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * • Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * • No reverse engineering, decompilation, or disassembly of this software is + * permitted. + * + * DISCLAIMER. + * 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * / diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.cpp new file mode 100644 index 0000000000..cf7836a8ee --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.cpp @@ -0,0 +1,453 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common/common.h" +#include "nordic_common.h" + +#include "btle.h" +#include "btle_clock.h" + +#include "ble_flash.h" + +#include "custom/custom_helper.h" + +#include "ble/GapEvents.h" +#include "nRF5xn.h" + +#ifdef S110 + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 1 +#elif defined(S130) || defined(S132) + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 0 +#endif + +extern "C" { +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + #include "pstorage.h" + #include "device_manager.h" +#else + #include "nrf_fstorage.h" + #include "fds.h" +#endif + +#include "nrf_sdh.h" +#include "nrf_sdh_ble.h" +} + +#include "headers/ble_hci.h" + +#include "nRF5xPalGattClient.h" + +// This is a C++ file, so C11 _Static_assert (works with -std=gnu99 on GCC) won't work +#undef STATIC_ASSERT_SIMPLE +#undef STATIC_ASSERT_MSG + +// FIXME : We can't use mbed_assert.h because we're using these macros within functions +#define STATIC_ASSERT_MSG(EXPR, MSG) +#define STATIC_ASSERT_SIMPLE(EXPR) + +#warning FIXME : We can't use mbed_assert.h because we're using these within functions + + +// Make this volatile at it will be set in interrupt context +volatile bool isEventsSignaled = false; + +extern "C" void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name); +void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name); + +// Before SDK 14, the softdevice handler is implemented within the SDK +// In SDK 14+, we have to implement it as we're using the "polling" mode for the SD +extern "C" void SD_EVT_IRQHandler(void); // export the softdevice event handler for registration by nvic-set-vector. + +#if NRF_SDK14PLUS_EVENT_HANDLERS +void btle_handler(const ble_evt_t *p_ble_evt, void *p_context); +#else +void btle_handler(ble_evt_t *p_ble_evt); +#endif + +#if !NRF_SDK14PLUS_EVENT_HANDLERS +static void sys_evt_dispatch(uint32_t sys_evt) +{ +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + pstorage_sys_event_handler(sys_evt); +#else + // Forward Softdevice events to the fstorage module + fs_sys_event_handler(sys_evt); +#endif +} +#endif + +/** + * This function is called in interrupt context to handle BLE events; i.e. pull + * system and user events out of the pending events-queue of the BLE stack. The + * BLE stack signals the availability of events by the triggering the SWI2 + * interrupt, which forwards the handling to this function. + * + * The event processing loop is implemented in intern_softdevice_events_execute(). + * + * This function will signal to the user code by calling signalEventsToProcess + * that their is events to process and BLE::processEvents should be called. + */ +static uint32_t signalEvent() +{ + if(isEventsSignaled == false) { + isEventsSignaled = true; + nRF5xn::Instance(BLE::DEFAULT_INSTANCE).signalEventsToProcess(BLE::DEFAULT_INSTANCE); + } + return NRF_SUCCESS; +} + + +error_t btle_init(void) +{ + nrf_clock_lf_cfg_t clockConfiguration; + ret_code_t err_code; + + // register softdevice handler vector + NVIC_SetVector(SD_EVT_IRQn, (uint32_t) SD_EVT_IRQHandler); + +#if (NRF_SD_BLE_API_VERSION >= 5) + err_code = nrf_sdh_enable_request(); + ASSERT_STATUS(err_code); +#else + // Configure the LF clock according to values provided by btle_clock.h. + // It is input from the chain of the yotta configuration system. + clockConfiguration.source = LFCLK_CONF_SOURCE; + clockConfiguration.xtal_accuracy = LFCLK_CONF_ACCURACY; + clockConfiguration.rc_ctiv = LFCLK_CONF_RC_CTIV; + clockConfiguration.rc_temp_ctiv = LFCLK_CONF_RC_TEMP_CTIV; + + SOFTDEVICE_HANDLER_INIT(&clockConfiguration, signalEvent); +#endif + + // Enable BLE stack + #if (NRF_SD_BLE_API_VERSION >= 5) + // Configure softdevice manually + // We could have used nrf_sdh_ble_default_cfg_set() but it's tightly coupled with the macros defined in sdk_config.h + ble_cfg_t ble_cfg; + uint32_t ram_start = 0; + + // Recover start address of application's RAM + err_code = nrf_sdh_ble_app_ram_start_get(&ram_start); + ASSERT_STATUS(err_code); + + // First configure GAP parameters, including the maximum number of connections + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.conn_cfg.conn_cfg_tag = NRF_CONNECTION_TAG; + ble_cfg.conn_cfg.params.gap_conn_cfg.conn_count = TOTAL_LINK_COUNT; + ble_cfg.conn_cfg.params.gap_conn_cfg.event_length = NRF_SDH_BLE_GAP_EVENT_LENGTH; // FIXME? + + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // GAP - Configure the number of peripheral and central links + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.conn_cfg.conn_cfg_tag = NRF_CONNECTION_TAG; + ble_cfg.gap_cfg.role_count_cfg.periph_role_count = PERIPHERAL_LINK_COUNT; + ble_cfg.gap_cfg.role_count_cfg.central_role_count = CENTRAL_LINK_COUNT; + ble_cfg.gap_cfg.role_count_cfg.central_sec_count = CENTRAL_LINK_COUNT ? + BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT : 0; + + err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // Configure GATT + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.conn_cfg.conn_cfg_tag = NRF_CONNECTION_TAG; + ble_cfg.conn_cfg.params.gatt_conn_cfg.att_mtu = NRF_SDH_BLE_GATT_MAX_MTU_SIZE; + + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATT, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // Number of custom UUIDs + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.common_cfg.vs_uuid_cfg.vs_uuid_count = UUID_TABLE_MAX_ENTRIES; + + err_code = sd_ble_cfg_set(BLE_COMMON_CFG_VS_UUID, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // GATT Server attribute table size + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.gatts_cfg.attr_tab_size.attr_tab_size = GATTS_ATTR_TAB_SIZE; + + err_code = sd_ble_cfg_set(BLE_GATTS_CFG_ATTR_TAB_SIZE, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // GATT Server, Service Changed characteristic + memset(&ble_cfg, 0, sizeof(ble_cfg_t)); + ble_cfg.gatts_cfg.service_changed.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT; + + err_code = sd_ble_cfg_set(BLE_GATTS_CFG_SERVICE_CHANGED, &ble_cfg, ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + // Enable BLE stack in softdevice + err_code = nrf_sdh_ble_enable(&ram_start); + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + #else + ble_enable_params_t ble_enable_params; + err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, + PERIPHERAL_LINK_COUNT, + &ble_enable_params); + + ble_enable_params.gatts_enable_params.attr_tab_size = GATTS_ATTR_TAB_SIZE; + ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT; + ble_enable_params.common_enable_params.vs_uuid_count = UUID_TABLE_MAX_ENTRIES; + + if(err_code != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + + if (softdevice_enable(&ble_enable_params) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + #endif + +#if (NRF_SD_BLE_API_VERSION <= 2) + ble_gap_addr_t addr; + if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } + if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) { + return ERROR_INVALID_PARAM; + } +#endif + +// From SDK 14 onwards event handlers are registered differently +// http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v14.0.0%2Fmigration.html +#if NRF_SDK14PLUS_EVENT_HANDLERS + // Register a handler for our BLE events. + NRF_SDH_BLE_OBSERVER(m_ble_observer, 3 /* default priority for user events */, btle_handler, NULL); +#else + ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler)); + ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch)); +#endif + + return ERROR_NONE; +} + +#if NRF_SDK14PLUS_EVENT_HANDLERS +void btle_handler(const ble_evt_t *p_ble_evt, void *p_context) +#else +void btle_handler(const ble_evt_t *p_ble_evt) +#endif +{ +#if NRF_SDK14PLUS_EVENT_HANDLERS + (void)p_context; // Keep compiler happy +#endif + using ble::pal::vendor::nordic::nRF5xGattClient; + using ble::pal::vendor::nordic::nRF5xSecurityManager; + +// In SDK14+, all other modules from the SDK will be registered independently as softdevice events observers +#if !NRF_SDK14PLUS_EVENT_HANDLERS + /* Library service handlers */ +#if SDK_CONN_PARAMS_MODULE_ENABLE + ble_conn_params_on_ble_evt(p_ble_evt); +#endif + +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + dm_ble_evt_handler(p_ble_evt); +#else + // Forward BLE events to the Connection State module. + // This must be called before any event handler that uses this module. + ble_conn_state_on_ble_evt(p_ble_evt); +#endif +#endif + +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + nRF5xGattClient::handle_events(p_ble_evt); +#endif + + nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); + nRF5xGap &gap = (nRF5xGap &) ble.getGap(); + nRF5xGattServer &gattServer = (nRF5xGattServer &) ble.getGattServer(); + nRF5xSecurityManager &securityManager = nRF5xSecurityManager::get_security_manager(); + + /* Custom event handler */ + switch (p_ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + gap.on_connection( + p_ble_evt->evt.gap_evt.conn_handle, + p_ble_evt->evt.gap_evt.params.connected + ); + break; + + case BLE_GAP_EVT_DISCONNECTED: { + Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle; + // Since we are not in a connection and have not started advertising, + // store bonds + gap.setConnectionHandle (BLE_CONN_HANDLE_INVALID); + + Gap::DisconnectionReason_t reason; + switch (p_ble_evt->evt.gap_evt.params.disconnected.reason) { + case BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION: + reason = Gap::LOCAL_HOST_TERMINATED_CONNECTION; + break; + case BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION: + reason = Gap::REMOTE_USER_TERMINATED_CONNECTION; + break; + case BLE_HCI_CONN_INTERVAL_UNACCEPTABLE: + reason = Gap::CONN_INTERVAL_UNACCEPTABLE; + break; + default: + /* Please refer to the underlying transport library for an + * interpretion of this reason's value. */ + reason = static_cast(p_ble_evt->evt.gap_evt.params.disconnected.reason); + break; + } + +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + // Close all pending discoveries for this connection + nRF5xGattClient::handle_connection_termination(handle); +#endif + + gap.processDisconnectionEvent(handle, reason); + break; + } + + +#if (NRF_SD_BLE_API_VERSION >= 5) +#ifndef S140 + // Handle PHY upgrade request + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + gap.on_phy_update_request( + p_ble_evt->evt.gap_evt.conn_handle, + p_ble_evt->evt.gap_evt.params.phy_update_request + ); + break; +#endif + case BLE_GAP_EVT_PHY_UPDATE: + gap.on_phy_update( + p_ble_evt->evt.gap_evt.conn_handle, + p_ble_evt->evt.gap_evt.params.phy_update + ); + break; + + // Handle Data length negotiation request + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + { + ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; + uint8_t const data_length_peer = + p_gap_evt->params.data_length_update_request.peer_params.max_tx_octets; + + const uint8_t max_data_length = NRF_SDH_BLE_GATT_MAX_MTU_SIZE + 4 /* L2CAP header size */; + + uint8_t const data_length = MIN(max_data_length, data_length_peer); + + ble_gap_data_length_params_t const dlp = + { + /* max_rx_octets */ data_length, + /* max_tx_octets */ data_length + }; + + ASSERT_STATUS_RET_VOID(sd_ble_gap_data_length_update(p_gap_evt->conn_handle, &dlp, NULL)); + break; + } + + // Handle MTU exchange request + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + { + // Respond with the server MTU + uint16_t conn_handle = p_ble_evt->evt.gatts_evt.conn_handle; + ASSERT_STATUS_RET_VOID(sd_ble_gatts_exchange_mtu_reply(conn_handle, NRF_SDH_BLE_GATT_MAX_MTU_SIZE)); + break; + } +#endif + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { + Gap::Handle_t connection = p_ble_evt->evt.gap_evt.conn_handle; + const ble_gap_evt_conn_param_update_request_t *update_request = + &p_ble_evt->evt.gap_evt.params.conn_param_update_request; + + sd_ble_gap_conn_param_update(connection, &update_request->conn_params); + break; + } + + case BLE_GAP_EVT_TIMEOUT: + gap.processTimeoutEvent(static_cast(p_ble_evt->evt.gap_evt.params.timeout.src)); + break; + + case BLE_GATTC_EVT_TIMEOUT: + case BLE_GATTS_EVT_TIMEOUT: + // Disconnect on GATT Server and Client timeout events. + // ASSERT_STATUS_RET_VOID (sd_ble_gap_disconnect(m_conn_handle, + // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); + break; + + case BLE_GAP_EVT_ADV_REPORT: + gap.on_advertising_packet(p_ble_evt->evt.gap_evt.params.adv_report); + break; + + default: + break; + } + + // Process security manager events + securityManager.sm_handler(p_ble_evt); + + gattServer.hwCallback(p_ble_evt); +} + +/*! @brief Callback when an error occurs inside the SoftDevice or ASSERT in debug*/ +void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) +{ + error("nrf failure at %s:%d", p_file_name, line_num); +} + +#if NRF_SD_BLE_API_VERSION >= 5 +/*! + @brief Handler for general errors above the SoftDevice layer. + Typically we can' recover from this so we do a reset. + This implementation will override the default weak symbol generated by the Nordic SDK +*/ +void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) +{ + ASSERT_STATUS_RET_VOID( id ); + NVIC_SystemReset(); +} +#else +/*! + @brief Handler for general errors above the SoftDevice layer. + Typically we can' recover from this so we do a reset. +*/ +void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name) +{ + ASSERT_STATUS_RET_VOID( error_code ); + NVIC_SystemReset(); +} +#endif + +#if NRF_SDK14PLUS_EVENT_HANDLERS +/*! + @brief Handler of Softdevice events. + This signals that the softdevie has events that need to be processed. +*/ +extern "C" void SD_EVT_IRQHandler(void) +{ + ASSERT_STATUS_RET_VOID(signalEvent()); +} +#endif diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.h new file mode 100644 index 0000000000..4c35282d8a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle.h @@ -0,0 +1,74 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BTLE_H_ +#define _BTLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common/common.h" + +#include "headers/nrf_ble.h" + +#if NRF_SD_BLE_API_VERSION >= 5 +#include "sdk_config.h" +#endif + +#define NRF_CONNECTION_TAG 1 /**= 5) // Softdevice event dispatching has changed in SDK14 + +error_t btle_init(void); + +// flag indicating if events have been signaled or not +// It is used by processEvents and signalEventsToProcess +// signalEventsToProcess raise the flag and processEvents +// clears it. +extern volatile bool isEventsSignaled; + +#ifdef __cplusplus +} +#endif + +#endif // ifndef _BTLE_H_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle_clock.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle_clock.h new file mode 100644 index 0000000000..bc4c1e29f4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/btle_clock.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA + * integrated circuit in a product or a software update for such product, must reproduce + * the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific prior + * written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary or object form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _BTLE_CLOCK_H_ +#define _BTLE_CLOCK_H_ + +#include "nrf5x_lf_clk_helper.h" + +/** + * @brief Module that generates settings for the low-frequency (LF) clock configuration. + * + * This module provides macros that are generated from the mbed config system macros. + * + * + * + * As a result, this module provides the following: @n + * - literal value LFCLK_CONF_SOURCE @n + * - literal value LFCLK_CONF_ACCURACY @n + * - literal value LFCLK_CONF_RC_CTIV @n + * - literal value LFCLK_CONF_RC_TEMP_CTIV + */ + + + +#include "nrf_sdm.h" + +#define DEFAULT_LFCLK_CONF_ACCURACY NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM + +#ifdef NRF52 + #define MAX_LFCLK_CONF_RC_CTIV 32 +#else + #define MAX_LFCLK_CONF_RC_CTIV 64 +#endif + +#define MAX_LFCLK_CONF_RC_TEMP_CTIV 33 + +#define DEFAULT_LFCLK_CONF_RC_CTIV 16 // Check temperature every 16 * 250ms. +#define DEFAULT_LFCLK_CONF_RC_TEMP_CTIV 1 // Only calibrate if temperature has changed. + +#define NRF_LF_SRC_XTAL 2 +#define NRF_LF_SRC_SYNTH 3 +#define NRF_LF_SRC_RC 4 + +#if MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_RC + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_RC + + #ifdef MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL + #define LFCLK_CONF_RC_CTIV MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL + #else + #define LFCLK_CONF_RC_CTIV DEFAULT_LFCLK_CONF_RC_CTIV + #endif + + #ifdef MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG + #define LFCLK_CONF_RC_TEMP_CTIV MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG + #else + #define LFCLK_CONF_RC_TEMP_CTIV DEFAULT_LFCLK_CONF_RC_TEMP_CTIV + #endif + + #if (LFCLK_CONF_RC_CTIV < 1) || (LFCLK_CONF_RC_CTIV > MAX_LFCLK_CONF_RC_CTIV) + #error Calibration timer interval out of range! + #endif + + #if (LFCLK_CONF_RC_TEMP_CTIV < 0 ) || (LFCLK_CONF_RC_TEMP_CTIV > 33) + #error Number/mode of LF RC calibration intervals out of range! + #endif + +#elif MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_SYNTH + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_SYNTH + #define LFCLK_CONF_RC_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + #define LFCLK_CONF_RC_TEMP_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + + #ifdef MBED_CONF_NORDIC_LF_CLOCK_HF_SYNTH_ACCURACY + #define LFCLK_CONF_ACCURACY MBED_CONF_NORDIC_LF_CLOCK_HF_SYNTH_ACCURACY + #endif + +#else // default is NRF_LF_SRC_SYNTH + #define LFCLK_CONF_SOURCE NRF_CLOCK_LF_SRC_XTAL + #define LFCLK_CONF_RC_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + #define LFCLK_CONF_RC_TEMP_CTIV 0 // Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. + + #ifdef MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY + #define LFCLK_CONF_ACCURACY MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY + #endif + +#endif + +#ifndef LFCLK_CONF_ACCURACY + #define LFCLK_CONF_ACCURACY DEFAULT_LFCLK_CONF_ACCURACY +#endif + +#if (LFCLK_CONF_ACCURACY > NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM) || (LFCLK_CONF_ACCURACY < NRF_CLOCK_LF_XTAL_ACCURACY_250_PPM) + #error Low frequency clock accuracy out of range! +#endif + + +#endif //_BTLE_CLOCK_H_ + + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.cpp new file mode 100644 index 0000000000..95be197637 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.cpp @@ -0,0 +1,361 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "custom_helper.h" +#include "../btle.h" + +/* + * The current version of the soft-device doesn't handle duplicate 128-bit UUIDs + * very well. It is therefore necessary to filter away duplicates before + * passing long UUIDs to sd_ble_uuid_vs_add(). The following types and data + * structures involved in maintaining a local cache of 128-bit UUIDs. + */ +typedef struct { + UUID::LongUUIDBytes_t uuid; + uint8_t type; +} converted_uuid_table_entry_t; + +static unsigned uuidTableEntries = 0; /* current usage of the table */ +converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES]; + +namespace { + +static void set_perm(ble_gap_conn_sec_mode_t& dest, GattAttribute::Security_t src) { + switch (src.value()) { + case GattAttribute::Security_t::NONE: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dest); + break; + + case GattAttribute::Security_t::UNAUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dest); + break; + + case GattAttribute::Security_t::AUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&dest); + break; + + case GattAttribute::Security_t::SC_AUTHENTICATED: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&dest); + break; + + default: + break; + } +} + +} +void custom_reset_128bits_uuid_table() { + uuidTableEntries = 0; +} + +/** + * lookup the cache of previously converted 128-bit UUIDs to find a type value. + * @param uuid base 128-bit UUID + * @param recoveredType the type field of the 3-byte nRF's uuid. + * @return true if a match is found. + */ +static bool +lookupConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t *recoveredType) +{ + unsigned i; + for (i = 0; i < uuidTableEntries; i++) { + unsigned byteIndex; + for (byteIndex = 0; byteIndex < UUID::LENGTH_OF_LONG_UUID; byteIndex++) { + /* Skip bytes 2 and 3, because they contain the shortUUID (16-bit) version of the + * long UUID; and we're comparing against the remainder. */ + if ((byteIndex == 2) || (byteIndex == 3)) { + continue; + } + + if (convertedUUIDTable[i].uuid[byteIndex] != uuid[byteIndex]) { + break; + } + } + + if (byteIndex == UUID::LENGTH_OF_LONG_UUID) { + *recoveredType = convertedUUIDTable[i].type; + return true; + } + } + + return false; +} + +static void +addToConvertedUUIDTable(const UUID::LongUUIDBytes_t uuid, uint8_t type) +{ + if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) { + return; /* recovery needed; or at least the user should be warned about this fact.*/ + } + + memcpy(convertedUUIDTable[uuidTableEntries].uuid, uuid, UUID::LENGTH_OF_LONG_UUID); + convertedUUIDTable[uuidTableEntries].uuid[2] = 0; + convertedUUIDTable[uuidTableEntries].uuid[3] = 0; + convertedUUIDTable[uuidTableEntries].type = type; + uuidTableEntries++; +} + +/** + * The nRF transport has its own 3-byte representation of a UUID. If the user- + * specified UUID is 128-bits wide, then the UUID base needs to be added to the + * soft-device and converted to a 3-byte handle before being used further. This + * function is responsible for this translation of user-specified UUIDs into + * nRF's representation. + * + * @param[in] uuid + * user-specified UUID + * @return nRF + * 3-byte UUID (containing a type and 16-bit UUID) representation + * to be used with SVC calls. + */ +ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid) +{ + ble_uuid_t nordicUUID; + nordicUUID.uuid = uuid.getShortUUID(); + nordicUUID.type = BLE_UUID_TYPE_UNKNOWN; /* to be set below */ + + if (uuid.shortOrLong() == UUID::UUID_TYPE_SHORT) { + nordicUUID.type = BLE_UUID_TYPE_BLE; + } else { + if (!lookupConvertedUUIDTable(uuid.getBaseUUID(), &nordicUUID.type)) { + nordicUUID.type = custom_add_uuid_base(uuid.getBaseUUID()); + addToConvertedUUIDTable(uuid.getBaseUUID(), nordicUUID.type); + } + } + + return nordicUUID; +} + +/**************************************************************************/ +/*! + @brief Adds the base UUID to the custom service. All UUIDs used + by this service are based on this 128-bit UUID. + + @note This UUID needs to be added to the SoftDevice stack before + adding the service's primary service via + 'sd_ble_gatts_service_add' + + @param[in] p_uuid_base A pointer to the 128-bit UUID array (8*16) + + @returns The UUID type. + A return value of 0 should be considered an error. + + @retval 0x00 BLE_UUID_TYPE_UNKNOWN + @retval 0x01 BLE_UUID_TYPE_BLE + @retval 0x02 BLE_UUID_TYPE_VENDOR_BEGIN + + @section EXAMPLE + @code + + // Take note that bytes 2/3 are blank since these are used to identify + // the primary service and individual characteristics + #define CFG_CUSTOM_UUID_BASE "\x6E\x40\x00\x00\xB5\xA3\xF3\x93\xE0\xA9\xE5\x0E\x24\xDC\xCA\x9E" + + uint8_t uuid_type = custom_add_uuid_base(CFG_CUSTOM_UUID_BASE); + ASSERT(uuid_type > 0, ERROR_NOT_FOUND); + + // We can now safely add the primary service and any characteristics + // for our custom service ... + + @endcode +*/ +/**************************************************************************/ +uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base) +{ + ble_uuid128_t base_uuid; + uint8_t uuid_type = 0; + + for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { + base_uuid.uuid128[i] = p_uuid_base[i]; + } + + ASSERT_INT( ERROR_NONE, sd_ble_uuid_vs_add( &base_uuid, &uuid_type ), 0); + + return uuid_type; +} + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ +error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base, + ble_uuid_t *p_uuid) +{ + UUID::LongUUIDBytes_t uuid_base_le; + + for (uint8_t i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { + uuid_base_le[i] = p_uuid_base[i]; + } + + ASSERT_STATUS( sd_ble_uuid_decode(UUID::LENGTH_OF_LONG_UUID, uuid_base_le, p_uuid)); + + return ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Adds a new characteristic to the custom service, assigning + properties, a UUID add-on value, etc. + + @param[in] service_handle + @param[in] p_uuid The 16-bit value to add to the base UUID + for this characteristic (normally >1 + since 1 is typically used by the primary + service). + @param[in] char_props The characteristic properties, as + defined by ble_gatt_char_props_t + @param[in] max_length The maximum length of this characeristic + @param[in] has_variable_len Whether the characteristic data has + variable length. + @param[out] p_char_handle + + @returns + @retval ERROR_NONE Everything executed normally +*/ +/**************************************************************************/ +error_t custom_add_in_characteristic(uint16_t service_handle, + ble_uuid_t *p_uuid, + uint8_t properties, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security, + GattAttribute::Security_t update_security, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + const uint8_t *userDescriptionDescriptorValuePtr, + uint16_t userDescriptionDescriptorValueLen, + const uint8_t *presentationFormatDescriptorValuePtr, + uint16_t presentationFormatDescriptorValueLen, + bool readAuthorization, + bool writeAuthorization, + ble_gatts_char_handles_t *p_char_handle) +{ + /* Characteristic metadata */ + ble_gatts_attr_md_t cccd_md; + ble_gatt_char_props_t char_props; + + memcpy(&char_props, &properties, 1); + + if (char_props.notify || char_props.indicate) { + /* Notification requires cccd */ + memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); + cccd_md.vloc = BLE_GATTS_VLOC_STACK; + set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE); + set_perm(cccd_md.write_perm, update_security); + } + + ble_gatts_char_md_t char_md = {0}; + + char_md.char_props = char_props; + char_md.p_cccd_md = + (char_props.notify || char_props.indicate) ? &cccd_md : NULL; + if ((userDescriptionDescriptorValueLen > 0) && (userDescriptionDescriptorValuePtr != NULL)) { + char_md.p_char_user_desc = const_cast(userDescriptionDescriptorValuePtr); + char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen; + char_md.char_user_desc_size = userDescriptionDescriptorValueLen; + } + if ((presentationFormatDescriptorValueLen > 0) && (presentationFormatDescriptorValuePtr != NULL)) { + ASSERT_TRUE( sizeof(ble_gatts_char_pf_t) == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM ); + ASSERT_TRUE( presentationFormatDescriptorValueLen == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM ); + char_md.p_char_pf = const_cast(reinterpret_cast(presentationFormatDescriptorValuePtr)); + } + + /* Attribute declaration */ + ble_gatts_attr_md_t attr_md = {0}; + + attr_md.rd_auth = readAuthorization; + attr_md.wr_auth = writeAuthorization; + + attr_md.vloc = BLE_GATTS_VLOC_STACK; + /* Always set variable size */ + attr_md.vlen = has_variable_len; + + set_perm(attr_md.read_perm, read_security); + set_perm(attr_md.write_perm, write_security); + + ble_gatts_attr_t attr_char_value = {0}; + + attr_char_value.p_uuid = p_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = length; + attr_char_value.max_len = max_length; + attr_char_value.p_value = p_data; + + ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, + &char_md, + &attr_char_value, + p_char_handle)); + + return ERROR_NONE; +} + + + +/**************************************************************************/ +/*! + @brief Adds a new descriptor to the custom service, assigning + value, a UUID add-on value, etc. + + @param[in] char_handle + @param[in] p_uuid The 16-bit value to add to the base UUID + for this descriptor (normally >1 + since 1 is typically used by the primary + service). + @param[in] max_length The maximum length of this descriptor + @param[in] has_variable_len Whether the characteristic data has + variable length. + + @returns + @retval ERROR_NONE Everything executed normally +*/ +/**************************************************************************/ +error_t custom_add_in_descriptor(uint16_t char_handle, + ble_uuid_t *p_uuid, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + uint16_t *p_desc_handle, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security) +{ + /* Descriptor metadata */ + ble_gatts_attr_md_t desc_md = {0}; + + desc_md.vloc = BLE_GATTS_VLOC_STACK; + /* Always set variable size */ + desc_md.vlen = has_variable_len; + + /* Make it readable and writable */ + set_perm(desc_md.read_perm, read_security); + set_perm(desc_md.write_perm, write_security); + + ble_gatts_attr_t attr_desc = {0}; + + attr_desc.p_uuid = p_uuid; + attr_desc.p_attr_md = &desc_md; + attr_desc.init_len = length; + attr_desc.max_len = max_length; + attr_desc.p_value = p_data; + + ASSERT_STATUS ( sd_ble_gatts_descriptor_add(char_handle, + &attr_desc, + p_desc_handle)); + + return ERROR_NONE; +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.h new file mode 100644 index 0000000000..e5cddc2bd5 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/btle/custom/custom_helper.h @@ -0,0 +1,74 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CUSTOM_HELPER_H_ +#define _CUSTOM_HELPER_H_ + +#include "common/common.h" +#include "headers/nrf_ble.h" +#include "ble/UUID.h" +#include "ble/GattCharacteristic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Reset the table of 128bits uuids. + * This table is used to keep track of vendors uuids added to the softdevice. + * It is important to reset it before disabling the softdevice otherwise the + * next time the softdevice will be enabled, this table will not be synchronmized + * with the softdevice table. + */ +void custom_reset_128bits_uuid_table(); +uint8_t custom_add_uuid_base(uint8_t const *const p_uuid_base); +error_t custom_decode_uuid(uint8_t const *const p_uuid_base, + ble_uuid_t *p_uuid); +ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid); + +error_t custom_add_in_characteristic(uint16_t service_handle, + ble_uuid_t *p_uuid, + uint8_t properties, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security, + GattAttribute::Security_t update_security, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + const uint8_t *userDescriptionDescriptorValuePtr, + uint16_t userDescriptionDescriptorValueLen, + const uint8_t *presentationFormatDescriptorValuePtr, + uint16_t presentationFormatDescriptorValueLen, + bool readAuthorization, + bool writeAuthorization, + ble_gatts_char_handles_t *p_char_handle); + +error_t custom_add_in_descriptor(uint16_t char_handle, + ble_uuid_t *p_uuid, + uint8_t *p_data, + uint16_t length, + uint16_t max_length, + bool has_variable_len, + uint16_t *p_desc_handle, + GattAttribute::Security_t read_security, + GattAttribute::Security_t write_security); + +#ifdef __cplusplus +} +#endif + +#endif // ifndef _CUSTOM_HELPER_H_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ansi_escape.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ansi_escape.h new file mode 100644 index 0000000000..392dedb44f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ansi_escape.h @@ -0,0 +1,103 @@ +/**************************************************************************/ +/*! + @file ansi_esc_code.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. + + This file is part of the tinyusb stack. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _ANSI_ESC_CODE_H_ +#define _ANSI_ESC_CODE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSI_CODE(seq) "\33[" seq +#define CSI_SGR(x) CSI_CODE(#x) "m" + +//------------- Cursor movement -------------// +#define ANSI_CURSOR_UP(n) CSI_CODE(#n "A") +#define ANSI_CURSOR_DOWN(n) CSI_CODE(#n "B") +#define ANSI_CURSOR_FORWARD(n) CSI_CODE(#n "C") +#define ANSI_CURSOR_BACKWARD(n) CSI_CODE(#n "D") +#define ANSI_CURSOR_LINE_DOWN(n) CSI_CODE(#n "E") +#define ANSI_CURSOR_LINE_UP(n) CSI_CODE(#n "F") +#define ANSI_CURSOR_POSITION(n, m) CSI_CODE(#n ";" #m "H") + +#define ANSI_ERASE_SCREEN(n) CSI_CODE(#n "J") +#define ANSI_ERASE_LINE(n) CSI_CODE(#n "K") + +/** text color */ +#define ANSI_TEXT_BLACK CSI_SGR(30) +#define ANSI_TEXT_RED CSI_SGR(31) +#define ANSI_TEXT_GREEN CSI_SGR(32) +#define ANSI_TEXT_YELLOW CSI_SGR(33) +#define ANSI_TEXT_BLUE CSI_SGR(34) +#define ANSI_TEXT_MAGENTA CSI_SGR(35) +#define ANSI_TEXT_CYAN CSI_SGR(36) +#define ANSI_TEXT_WHITE CSI_SGR(37) +#define ANSI_TEXT_DEFAULT CSI_SGR(39) + +/** background color */ +#define ANSI_BG_BLACK CSI_SGR(40) +#define ANSI_BG_RED CSI_SGR(41) +#define ANSI_BG_GREEN CSI_SGR(42) +#define ANSI_BG_YELLOW CSI_SGR(43) +#define ANSI_BG_BLUE CSI_SGR(44) +#define ANSI_BG_MAGENTA CSI_SGR(45) +#define ANSI_BG_CYAN CSI_SGR(46) +#define ANSI_BG_WHITE CSI_SGR(47) +#define ANSI_BG_DEFAULT CSI_SGR(49) + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_ANSI_ESC_CODE_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/assertion.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/assertion.h new file mode 100644 index 0000000000..71bacb3e81 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/assertion.h @@ -0,0 +1,197 @@ +/**************************************************************************/ +/*! + @file assertion.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _ASSERTION_H_ +#define _ASSERTION_H_ + +#include "projectconfig.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +static inline void debugger_breakpoint(void) ATTR_ALWAYS_INLINE; +static inline void debugger_breakpoint(void) +{ +#ifndef _TEST_ + __asm("BKPT #0\n"); +#endif +} + +//--------------------------------------------------------------------+ +// Compile-time Assert +//--------------------------------------------------------------------+ +#if defined __COUNTER__ && __COUNTER__ != __COUNTER__ + #define _ASSERT_COUNTER __COUNTER__ +#else + #define _ASSERT_COUNTER __LINE__ +#endif + +#define ASSERT_STATIC(const_expr, message) enum { XSTRING_CONCAT_(static_assert_, _ASSERT_COUNTER) = 1/(!!(const_expr)) } + +//--------------------------------------------------------------------+ +// Assert Helper +//--------------------------------------------------------------------+ +//#ifndef _TEST_ +// #define ASSERT_MESSAGE(format, ...) _PRINTF("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) +//#else +// #define ASSERT_MESSAGE(format, ...) _PRINTF("%d:note: Assert " format "\n", __LINE__, __VA_ARGS__) +//#endif + +#if CFG_DEBUG == 3 + #define ASSERT_MESSAGE(format, ...) debugger_breakpoint() +#elif CFG_DEBUG == 2 + #define ASSERT_MESSAGE(format, ...) printf("Assert at %s: %s: %d: " format "\n", __BASE_FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__) +#else + #define ASSERT_MESSAGE(format, ...) +#endif + +#define ASSERT_ERROR_HANDLER(x, para) \ + return (x) + +#define ASSERT_DEFINE_WITH_HANDLER(error_handler, handler_para, setup_statement, condition, error, format, ...) \ + do{\ + setup_statement;\ + if (!(condition)) {\ + ASSERT_MESSAGE(format, __VA_ARGS__);\ + error_handler(error, handler_para);\ + }\ + }while(0) + +#define ASSERT_DEFINE(...) ASSERT_DEFINE_WITH_HANDLER(ASSERT_ERROR_HANDLER, NULL, __VA_ARGS__) + +//--------------------------------------------------------------------+ +// error_t Status Assert TODO use ASSERT_DEFINE +//--------------------------------------------------------------------+ +#define ASSERT_STATUS_MESSAGE(sts, message) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, status, "%s: %s", ErrorStr[status], message) + +#define ASSERT_STATUS(sts) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, status, "error = %d", status) + +#define ASSERT_STATUS_RET_VOID(sts) \ + ASSERT_DEFINE(error_t status = (error_t)(sts),\ + ERROR_NONE == status, (void) 0, "error = %d", status) + +//--------------------------------------------------------------------+ +// Logical Assert +//--------------------------------------------------------------------+ +#define ASSERT_TRUE(condition , error) ASSERT_DEFINE( , (condition), error, "%s", "evaluated to false") +#define ASSERT_FALSE(condition , error) ASSERT_DEFINE( ,!(condition), error, "%s", "evaluated to true") + +//--------------------------------------------------------------------+ +// Pointer Assert +//--------------------------------------------------------------------+ +#define ASSERT_PTR(...) ASSERT_PTR_NOT_NULL(__VA_ARGS__) +#define ASSERT_PTR_NOT_NULL(pointer, error) ASSERT_DEFINE( , NULL != (pointer), error, "%s", "pointer is NULL") +#define ASSERT_PTR_NULL(pointer, error) ASSERT_DEFINE( , NULL == (pointer), error, "%s", "pointer is not NULL") + +//--------------------------------------------------------------------+ +// Integral Assert +//--------------------------------------------------------------------+ +#define ASSERT_XXX_EQUAL(type_format, expected, actual, error) \ + ASSERT_DEFINE(\ + uint32_t exp = (expected); uint32_t act = (actual),\ + exp==act,\ + error,\ + "expected " type_format ", actual " type_format, exp, act) + +#define ASSERT_XXX_WITHIN(type_format, lower, upper, actual, error) \ + ASSERT_DEFINE(\ + uint32_t low = (lower); uint32_t up = (upper); uint32_t act = (actual),\ + (low <= act) && (act <= up),\ + error,\ + "expected within " type_format " - " type_format ", actual " type_format, low, up, act) + +//--------------------------------------------------------------------+ +// Integer Assert +//--------------------------------------------------------------------+ +#define ASSERT_INT(...) ASSERT_INT_EQUAL(__VA_ARGS__) +#define ASSERT_INT_EQUAL(...) ASSERT_XXX_EQUAL("%d", __VA_ARGS__) +#define ASSERT_INT_WITHIN(...) ASSERT_XXX_WITHIN("%d", __VA_ARGS__) + +//--------------------------------------------------------------------+ +// Hex Assert +//--------------------------------------------------------------------+ +#define ASSERT_HEX(...) ASSERT_HEX_EQUAL(__VA_ARGS__) +#define ASSERT_HEX_EQUAL(...) ASSERT_XXX_EQUAL("0x%x", __VA_ARGS__) +#define ASSERT_HEX_WITHIN(...) ASSERT_XXX_WITHIN("0x%x", __VA_ARGS__) + +//--------------------------------------------------------------------+ +// Bin Assert +//--------------------------------------------------------------------+ +#define BIN8_PRINTF_PATTERN "%d%d%d%d%d%d%d%d" +#define BIN8_PRINTF_CONVERT(byte) \ + ((byte) & 0x80 ? 1 : 0), \ + ((byte) & 0x40 ? 1 : 0), \ + ((byte) & 0x20 ? 1 : 0), \ + ((byte) & 0x10 ? 1 : 0), \ + ((byte) & 0x08 ? 1 : 0), \ + ((byte) & 0x04 ? 1 : 0), \ + ((byte) & 0x02 ? 1 : 0), \ + ((byte) & 0x01 ? 1 : 0) + +#define ASSERT_BIN8(...) ASSERT_BIN8_EQUAL(__VA_ARGS__) +#define ASSERT_BIN8_EQUAL(expected, actual, error)\ + ASSERT_DEFINE(\ + uint8_t exp = (expected); uint8_t act = (actual),\ + exp==act,\ + error,\ + "expected " BIN8_PRINTF_PATTERN ", actual " BIN8_PRINTF_PATTERN, BIN8_PRINTF_CONVERT(exp), BIN8_PRINTF_CONVERT(act) ) + +#ifdef __cplusplus +} +#endif + +#endif /* _ASSERTION_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/binary.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/binary.h new file mode 100644 index 0000000000..585787eb2f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/binary.h @@ -0,0 +1,96 @@ +/**************************************************************************/ +/*! + @file binary.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _BINARY_H_ +#define _BINARY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/// n-th Bit +#define BIT(n) (1 << (n)) + +/// set n-th bit of x to 1 +#define BIT_SET(x, n) ( (x) | BIT(n) ) + +/// clear n-th bit of x +#define BIT_CLR(x, n) ( (x) & (~BIT(n)) ) + +/// test n-th bit of x +#define BIT_TEST(x, n) ( (x) & BIT(n) ) + +#if defined(__GNUC__) && !defined(__CC_ARM) // keil does not support binary format + +#define BIN8(x) ((uint8_t) (0b##x)) +#define BIN16(b1, b2) ((uint16_t) (0b##b1##b2)) +#define BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4)) + +#else + +// internal macro of B8, B16, B32 +#define _B8__(x) (((x&0x0000000FUL)?1:0) \ + +((x&0x000000F0UL)?2:0) \ + +((x&0x00000F00UL)?4:0) \ + +((x&0x0000F000UL)?8:0) \ + +((x&0x000F0000UL)?16:0) \ + +((x&0x00F00000UL)?32:0) \ + +((x&0x0F000000UL)?64:0) \ + +((x&0xF0000000UL)?128:0)) + +#define BIN8(d) ((uint8_t) _B8__(0x##d##UL)) +#define BIN16(dmsb,dlsb) (((uint16_t)BIN8(dmsb)<<8) + BIN8(dlsb)) +#define BIN32(dmsb,db2,db3,dlsb) \ + (((uint32_t)BIN8(dmsb)<<24) \ + + ((uint32_t)BIN8(db2)<<16) \ + + ((uint32_t)BIN8(db3)<<8) \ + + BIN8(dlsb)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BINARY_H_ */ + +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ble_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ble_error.h new file mode 100644 index 0000000000..36deb33080 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/ble_error.h @@ -0,0 +1,151 @@ +/**************************************************************************/ +/*! + @file ble_error.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief Error Header + * + * \note TBD + */ + +/** \ingroup Group_Common + * \defgroup Group_Error Error Codes + * @{ + */ + +#ifndef _BLE_ERROR_H_ +#define _BLE_ERROR_H_ + +#include "projectconfig.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef enum +{ + /*======================================================================= + NORDIC GLOBAL ERRORS 0x0000 .. 0x00FF + ----------------------------------------------------------------------- + Errors mapped from nrf_error.h + -----------------------------------------------------------------------*/ + ERROR_NONE = 0x0000 , ///< Successful command + ERROR_SVC_HANDLER_MISSING = 0x0001 , ///< SVC handler is missing + ERROR_SOFTDEVICE_NOT_ENABLED = 0x0002 , ///< SoftDevice has not been enabled + ERROR_INTERNAL = 0x0003 , ///< Internal Error + ERROR_NO_MEM = 0x0004 , ///< No Memory for operation + ERROR_NOT_FOUND = 0x0005 , ///< Not found + ERROR_NOT_SUPPORTED = 0x0006 , ///< Not supported + ERROR_INVALID_PARAM = 0x0007 , ///< Invalid Parameter + ERROR_INVALID_STATE = 0x0008 , ///< Invalid state, operation disallowed in this state + ERROR_INVALID_LENGTH = 0x0009 , ///< Invalid Length + ERROR_INVALID_FLAGS = 0x000A , ///< Invalid Flags + ERROR_INVALID_DATA = 0x000B , ///< Invalid Data + ERROR_DATA_SIZE = 0x000C , ///< Data size exceeds limit + ERROR_TIMEOUT = 0x000D , ///< Operation timed out + ERROR_NULL = 0x000E , ///< Null Pointer + ERROR_FORBIDDEN = 0x000F , ///< Forbidden Operation + ERROR_INVALID_ADDR = 0x0010 , ///< Bad Memory Address + ERROR_BUSY = 0x0011 , ///< Busy + /*=======================================================================*/ + + ERROR_INVALIDPARAMETER = 0x0100 , /**< An invalid parameter value was provided */ + ERROR_I2C_XFER_FAILED = 0x0101 , /**< an failed attempt to make I2C transfer */ + + /*======================================================================= + SIMPLE BINARY PROTOCOL ERRORS 0x0120 .. 0x013F + ----------------------------------------------------------------------- + Errors relating to the simple binary protocol (/src//protocol) + -----------------------------------------------------------------------*/ + ERROR_PROT_INVALIDMSGTYPE = 0x121, /**< Unexpected msg type encountered */ + ERROR_PROT_INVALIDCOMMANDID = 0x122, /**< Unknown or out of range command ID */ + ERROR_PROT_INVALIDPAYLOAD = 0x123, /**< Message payload has a problem (invalid len, etc.) */ + /*=======================================================================*/ + + //------------- based on Nordic SDM nrf_error_sdm.h -------------// + ERROR_SDM_LFCLK_SOURCE_UNKNOWN = 0x1000 , ///< Unknown lfclk source + ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION = 0x1001 , ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having enabled SoftDevice interrupts) + ERROR_SDM_INCORRECT_CLENR0 = 0x1002 , ///< Incorrect CLENR0 (can be caused by erronous SoftDevice flashing) + + //------------- based on Nordic SOC nrf_error_soc.h -------------// + /* Mutex Errors */ + ERROR_SOC_MUTEX_ALREADY_TAKEN = 0x2000 , ///< Mutex already taken + + /* NVIC errors */ + ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE = 0x2001 , ///< NVIC interrupt not available + ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED = 0x2002 , ///< NVIC interrupt priority not allowed + ERROR_SOC_NVIC_SHOULD_NOT_RETURN = 0x2003 , ///< NVIC should not return + + /* Power errors */ + ERROR_SOC_POWER_MODE_UNKNOWN = 0x2004 , ///< Power mode unknown + ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN = 0x2005 , ///< Power POF threshold unknown + ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN = 0x2006 , ///< Power off should not return + + /* Rand errors */ + ERROR_SOC_RAND_NOT_ENOUGH_VALUES = 0x2007 , ///< RAND not enough values + + /* PPI errors */ + ERROR_SOC_PPI_INVALID_CHANNEL = 0x2008 , ///< Invalid PPI Channel + ERROR_SOC_PPI_INVALID_GROUP = 0x2009 , ///< Invalid PPI Group + + //------------- based on Nordic STK (ble) ble_err.h -------------// + ERROR_BLE_INVALID_CONN_HANDLE = 0x3001 , /**< Invalid connection handle. */ + ERROR_BLE_INVALID_ATTR_HANDLE = 0x3002 , /**< Invalid attribute handle. */ + ERROR_BLE_NO_TX_BUFFERS = 0x3003 , /**< Buffer capacity exceeded. */ + + // L2CAP + ERROR_BLE_L2CAP_CID_IN_USE = 0x3100 , /**< CID already in use. */ + + // GAP + ERROR_BLE_GAP_UUID_LIST_MISMATCH = 0x3200 , /**< UUID list does not contain an integral number of UUIDs. */ + ERROR_BLE_GAP_DISCOVERABLE_WITH_WHITELIST = 0x3201 , /**< Use of Whitelist not permitted with discoverable advertising. */ + ERROR_BLE_GAP_INVALID_BLE_ADDR = 0x3202 , /**< The upper two bits of the address do not correspond to the specified address type. */ + + // GATTC + ERROR_BLE_GATTC_PROC_NOT_PERMITTED = 0x3300 , + + // GATTS + ERROR_BLEGATTS_INVALID_ATTR_TYPE = 0x3400 , /**< Invalid attribute type. */ + ERROR_BLEGATTS_SYS_ATTR_MISSING = 0x3401 , /**< System Attributes missing. */ + +}error_t; + +#ifdef __cplusplus + } +#endif + +#endif /* _BLE_ERROR_H_ */ + + /** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/common.h new file mode 100644 index 0000000000..6002c6dfb7 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/common.h @@ -0,0 +1,236 @@ +/**************************************************************************/ +/*! + @file common.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \defgroup Group_Common Common Files + * @{ + * + * \defgroup Group_CommonH common.h + * + * @{ + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// INCLUDES +//--------------------------------------------------------------------+ + +//------------- Standard Header -------------// +#include +#include +#include +#include +#include + +//------------- General Header -------------// +#include "projectconfig.h" +#include "compiler.h" +#include "assertion.h" +#include "binary.h" +#include "ble_error.h" + +//------------- MCU header -------------// +//#include "nrf.h" + +//--------------------------------------------------------------------+ +// TYPEDEFS +//--------------------------------------------------------------------+ +typedef unsigned char byte_t; +typedef float float32_t; +typedef double float64_t; + +//--------------------------------------------------------------------+ +// MACROS +//--------------------------------------------------------------------+ +#define STRING_(x) #x // stringify without expand +#define XSTRING_(x) STRING_(x) // expand then stringify +#define STRING_CONCAT_(a, b) a##b // concat without expand +#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) // expand then concat + +#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) +#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff)) +#define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16) +#define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16) + +#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB +#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff)) +#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff)) +#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB + +#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32) +#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32) + +//--------------------------------------------------------------------+ +// INLINE FUNCTION +//--------------------------------------------------------------------+ +#define memclr_(buffer, size) memset(buffer, 0, size) + +//------------- Conversion -------------// +/// form an uint32_t from 4 x uint8_t +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) +{ + return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; +} + +static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_high_u8(uint16_t u16) +{ + return (uint8_t) ((u16 >> 8) & 0x00ff); +} + +static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_low_u8(uint16_t u16) +{ + return (uint8_t) (u16 & 0x00ff); +} + +//------------- Min -------------// +static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t min8_of(uint8_t x, uint8_t y) +{ + return (x < y) ? x : y; +} + +static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint16_t min16_of(uint16_t x, uint16_t y) +{ + return (x < y) ? x : y; +} + +static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t min32_of(uint32_t x, uint32_t y) +{ + return (x < y) ? x : y; +} + +//------------- Max -------------// +static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t max32_of(uint32_t x, uint32_t y) +{ + return (x > y) ? x : y; +} + +//------------- Align -------------// +static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align32 (uint32_t value) +{ + return (value & 0xFFFFFFE0UL); +} + +static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align16 (uint32_t value) +{ + return (value & 0xFFFFFFF0UL); +} + +static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align_n (uint32_t alignment, uint32_t value) +{ + return value & (~(alignment-1)); +} + +static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align4k (uint32_t value) +{ + return (value & 0xFFFFF000UL); +} + +static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t offset4k(uint32_t value) +{ + return (value & 0xFFFUL); +} + +//------------- Mathematics -------------// +/// inclusive range checking +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower <= value) && (value <= upper); +} + +/// exclusive range checking +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower < value) && (value < upper); +} + +static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t log2_of(uint32_t value) +{ + uint8_t result = 0; // log2 of a value is its MSB's position + + while (value >>= 1) + { + result++; + } + return result; +} + +// return the number of set bits in value +static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t cardinality_of(uint32_t value) +{ + // Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only + // the high bit set, then it will only go once through the loop + // Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) + // mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method + // "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and + // published in 1964 in a book edited by Beckenbach.)" + uint8_t count; + for (count = 0; value; count++) + { + value &= value - 1; // clear the least significant bit set + } + + return count; +} + +#ifdef __cplusplus + } +#endif + +#endif /* _COMMON_H_ */ + +/** @} */ +/** @} */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/compiler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/compiler.h new file mode 100644 index 0000000000..5b04ac05d0 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/common/compiler.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/*! + @file compiler.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, K. Townsend (microBuilder.eu) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDER 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. +*/ +/**************************************************************************/ + +/** \file + * \brief GCC Header + */ + +/** \ingroup Group_Compiler + * \defgroup Group_GCC GNU GCC + * @{ + */ + +#ifndef _COMPILER_GCC_H_ +#define _COMPILER_GCC_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "projectconfig.h" + +//#ifndef __GNUC__ +// #define ATTR_ALWAYS_INLINE +// #define ATTR_CONST +//#else + +#ifdef _TEST_ + #define ATTR_ALWAYS_INLINE + #define STATIC_ + #define INLINE_ +#else + #define STATIC_ static + #define INLINE_ inline + + #if CFG_DEBUG == 3 + #define ATTR_ALWAYS_INLINE // no inline for debug = 3 + #endif +#endif + + +#ifdef __GNUC__ + +#define ALIGN_OF(x) __alignof__(x) + +/// Normally, the compiler places the objects it generates in sections like data or bss & function in text. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section +#define ATTR_SECTION(section) __attribute__ ((#section)) + +/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, an error that includes message is diagnosed. This is useful for compile-time checking +#define ATTR_ERROR(Message) __attribute__ ((error(Message))) + +/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning that includes message is diagnosed. This is useful for compile-time checking +#define ATTR_WARNING(Message) __attribute__ ((warning(Message))) + +/** + * \defgroup Group_VariableAttr Variable Attributes + * @{ + */ + +/// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes +#define ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes))) + +/// The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute +#define ATTR_PACKED __attribute__ ((packed)) + +#define ATTR_PREPACKED + +#define ATTR_PACKED_STRUCT(x) x __attribute__ ((packed)) +/** @} */ + +/** + * \defgroup Group_FuncAttr Function Attributes + * @{ + */ + +#ifndef ATTR_ALWAYS_INLINE +/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified +#define ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) +#endif + +/// The nonnull attribute specifies that some function parameters should be non-null pointers. f the compiler determines that a null pointer is passed in an argument slot marked as non-null, and the -Wnonnull option is enabled, a warning is issued. All pointer arguments are marked as non-null +#define ATTR_NON_NULL __attribute__ ((nonull)) + +/// Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure +#define ATTR_PURE __attribute__ ((pure)) + +/// Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory. +/// Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void +#define ATTR_CONST __attribute__ ((const)) + +/// The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses +#define ATTR_DEPRECATED __attribute__ ((deprecated)) + +/// Same as the deprecated attribute with optional message in the warning +#define ATTR_DEPRECATED_MESS(mess) __attribute__ ((deprecated(mess))) + +/// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code +#define ATTR_WEAK __attribute__ ((weak)) + +/// The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified +#define ATTR_ALIAS(func) __attribute__ ((alias(#func))) + +/// The weakref attribute marks a declaration as a weak reference. It is equivalent with weak + alias attribute, but require function is static +#define ATTR_WEAKREF(func) __attribute__ ((weakref(#func))) + +/// The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug +#define ATTR_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) + +/// This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly. +#define ATTR_USED __attribute__ ((used)) + +/// This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function. +#define ATTR_UNUSED __attribute__ ((unused)) + +#elif defined (__ICCARM__) //IAR + #define ATTR_ALWAYS_INLINE // IAR dosn't provide such a syntax extension in function's prototypes. + #define ATTR_CONST // IAR dosn't provide such a syntax extension in function's prototypes. +#endif + +/** @} */ + +#ifdef __cplusplus + } +#endif + +#endif /* _COMPILER_GCC_H_ */ + +/// @} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.cpp new file mode 100644 index 0000000000..32419875a2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.cpp @@ -0,0 +1,190 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include +#include + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/platform.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/memory_buffer_alloc.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ecp.h" + +#include "platform/NonCopyable.h" +#include "platform/CriticalSectionLock.h" +#include "ble/BLETypes.h" +#include "cmsis.h" +#include "nRF5xCrypto.h" +#include "platform/mbed_assert.h" +#include "nrf_soc.h" + + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +CryptoToolbox::CryptoToolbox() : _initialized(false) { + mbedtls_platform_setup(NULL); + mbedtls_entropy_init(&_entropy_context); + mbedtls_ecp_group_init(&_group); + int err = mbedtls_ecp_group_load( + &_group, + MBEDTLS_ECP_DP_SECP256R1 + ); + _initialized = err ? false : true; +} + +CryptoToolbox::~CryptoToolbox() { + mbedtls_ecp_group_free(&_group); + mbedtls_entropy_free(&_entropy_context); + mbedtls_platform_teardown(NULL); +} + +bool CryptoToolbox::generate_keys( + ArrayView X, + ArrayView Y, + ArrayView secret +) { + mbedtls_mpi secret_key; + mbedtls_ecp_point public_keys; + + mbedtls_mpi_init(&secret_key); + mbedtls_ecp_point_init(&public_keys); + + int err = mbedtls_ecp_gen_keypair( + &_group, + &secret_key, + &public_keys, + mbedtls_entropy_func, + &_entropy_context + ); + + if (!err) { + store_mpi(secret, secret_key); + store_mpi(X, public_keys.X); + store_mpi(Y, public_keys.Y); + } + + mbedtls_ecp_point_free(&public_keys); + mbedtls_mpi_free(&secret_key); + + return err ? false : true; +} + +bool CryptoToolbox::generate_shared_secret( + const ArrayView& peer_X, + const ArrayView& peer_Y, + const ArrayView& own_secret, + ArrayView shared_secret +) { + mbedtls_mpi result; + mbedtls_mpi secret_key; + mbedtls_ecp_point public_keys; + + mbedtls_mpi_init(&result); + mbedtls_mpi_init(&secret_key); + mbedtls_ecp_point_init(&public_keys); + + load_mpi(secret_key, own_secret); + load_mpi(public_keys.X, peer_X); + load_mpi(public_keys.Y, peer_Y); + mbedtls_mpi_lset( &public_keys.Z, 1 ); + + int err = mbedtls_ecdh_compute_shared( + &_group, + &result, + &public_keys, + &secret_key, + /* rng function; optional */ NULL, + /* rng param */ NULL + ); + + if (!err) { + store_mpi(shared_secret, result); + } + + mbedtls_ecp_point_free(&public_keys); + mbedtls_mpi_free(&secret_key); + mbedtls_mpi_free(&result); + + return err ? false : true; +} + +bool CryptoToolbox::ah( + const ArrayView& irk, + const ArrayView& prand, + ArrayView hash +) { + // Note copy then swap operation can be optimized. + + // Note: the encryption block works in big endian; go figure. + nrf_ecb_hal_data_t ecb_hal_data; + + memcpy(ecb_hal_data.key, irk.data(), irk.size()); + swap_endian(ecb_hal_data.key, sizeof(ecb_hal_data.key)); + + memcpy(ecb_hal_data.cleartext, prand.data(), prand.size()); + memset(ecb_hal_data.cleartext + prand.size(), 0, sizeof(ecb_hal_data.cleartext) - prand.size()); + swap_endian(ecb_hal_data.cleartext, sizeof(ecb_hal_data.cleartext)); + + uint32_t err = sd_ecb_block_encrypt(&ecb_hal_data); + + if (err) { + return false; + } + + swap_endian(ecb_hal_data.ciphertext, sizeof(ecb_hal_data.ciphertext)); + + memcpy(hash.data(), ecb_hal_data.ciphertext, hash.size()); + + return true; +} + + +void CryptoToolbox::load_mpi(mbedtls_mpi& dest, const ArrayView& src) { + ble::public_key_coord_t src_be = src.data(); + swap_endian(src_be.data(), src_be.size()); + mbedtls_mpi_read_binary(&dest, src_be.data(), src_be.size()); +} + +void CryptoToolbox::store_mpi(ArrayView& dest, const mbedtls_mpi& src) { + mbedtls_mpi_write_binary(&src, dest.data(), dest.size()); + swap_endian(dest.data(), dest.size()); +} + +void CryptoToolbox::swap_endian(uint8_t* buf, size_t len) { + for(size_t low = 0, high = (len - 1); high > low; --high, ++low) { + std::swap(buf[low], buf[high]); + } +} + +} // nordic +} // vendor +} // pal +} // ble + +#endif //defined(MBEDTLS_ECDH_C) + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.h new file mode 100644 index 0000000000..35c56a875e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xCrypto.h @@ -0,0 +1,146 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NRF5X_CRYPTO_ +#define NRF5X_CRYPTO_ + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/platform.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ecp.h" + +#include "platform/NonCopyable.h" +#include "ble/BLETypes.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +/** + * Toolbox of cryptographic functions used in BLE. + */ +class CryptoToolbox : mbed::NonCopyable { + +public: + /** + * Size of the Key used in lesc crypto operations. + */ + static const ptrdiff_t lesc_key_size_ = public_key_coord_t::size_; + + /** + * Size of an IRK. + */ + static const ptrdiff_t irk_size_ = irk_t::size_; + + /** + * Size of the hash generated by ah. + */ + static const ptrdiff_t hash_size_ = 3; + + /** + * Size of prand. + */ + static const ptrdiff_t prand_size_ = 3; + + /** + * Create a new CryptoToolbox. + */ + CryptoToolbox(); + + /** + * Destroy a CryptoTioolbox object. + */ + ~CryptoToolbox(); + + /** + * Generate lesc public and private keys. + * @param[out] X The component X of the public key. + * @param[out] Y The component Y of the public key. + * @param[out] secret The secret key. + * @return true if the shared secret has been successfully generated and + * false otherwise. + */ + bool generate_keys( + ArrayView X, + ArrayView Y, + ArrayView secret + ); + + /** + * Generate a shared secret from a peer public key and a local secret key. + * @param[in] peer_X The component X of the peer public key. + * @param[in] peer_Y The component Y of the peer public key. + * @param[in] own_secret The local secret key. + * @param[out] shared_secret The shared secret generated. + * @return true if the shared secret has been successfully generated and + * false otherwise. + */ + bool generate_shared_secret( + const ArrayView& peer_X, + const ArrayView& peer_Y, + const ArrayView& own_secret, + ArrayView shared_secret + ); + + /** + * Execute the function ah. This function can be used to generate private + * resolvable addresses and resolve them. + * + * @note all parameters passed and return by this fucntion are in little + * endian. + * + * @param[in] irk The key used to create hash. + * @param[in] prand The random part from which the hash will be generated. + * @param[out] hash The hash generated. + * + * @return true in case of success and false otherwise. + */ + bool ah( + const ArrayView& irk, + const ArrayView& prand, + ArrayView hash + ); + +private: + void load_mpi(mbedtls_mpi& dest, const ArrayView& src); + + void store_mpi(ArrayView& dest, const mbedtls_mpi& src); + + void swap_endian(uint8_t* buf, size_t len); + + bool _initialized; + mbedtls_entropy_context _entropy_context; + mbedtls_ecp_group _group; +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif // defined(MBEDTLS_ECDH_C) + +#endif // NRF5X_CRYPTO_ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.cpp new file mode 100644 index 0000000000..5c343eafa5 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.cpp @@ -0,0 +1,1661 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nRF5xn.h" +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#include "ble/BLE.h" + +#include "common/common.h" +#include "headers/ble_hci.h" +#include "ble/pal/ConnectionEventMonitor.h" +#include "nRF5xPalSecurityManager.h" +#include + +using ble::pal::vendor::nordic::nRF5xSecurityManager; +using ble::ArrayView; +using ble::pal::advertising_peer_address_type_t; +using ble::peer_address_type_t; + +typedef BLEProtocol::AddressType LegacyAddressType; +typedef BLEProtocol::AddressType_t LegacyAddressType_t; + +namespace { + +nRF5xSecurityManager& get_sm() { + return nRF5xSecurityManager::get_security_manager(); +} + +ble_error_t set_private_resolvable_address() { +#if (NRF_SD_BLE_API_VERSION <= 2) + ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE }; + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); +#else + ble_gap_privacy_params_t privacy_config = { 0 }; + uint32_t err = sd_ble_gap_privacy_get(&privacy_config); + if (err) { + return BLE_ERROR_UNSPECIFIED; + } + + privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; + err = sd_ble_gap_privacy_set(&privacy_config); +#endif + return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; +} + +ble_error_t set_private_non_resolvable_address() { +#if (NRF_SD_BLE_API_VERSION <= 2) + ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE }; + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); +#else + ble_gap_privacy_params_t privacy_config = { 0 }; + uint32_t err = sd_ble_gap_privacy_get(&privacy_config); + if (err) { + return BLE_ERROR_UNSPECIFIED; + } + + privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE; + err = sd_ble_gap_privacy_set(&privacy_config); +#endif + return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; +} + +bool is_advertising_non_connectable(const GapAdvertisingParams ¶ms) { + switch (params.getAdvertisingType()) { + case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED: + case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED: + return true; + default: + return false; + } +} + +bool is_identity_address(peer_address_type_t address_type) { + return address_type == peer_address_type_t::PUBLIC_IDENTITY || + address_type == peer_address_type_t::RANDOM_STATIC_IDENTITY; +} + +peer_address_type_t convert_nordic_address(bool identity, uint8_t address) { + if (identity) { + if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { + return peer_address_type_t::PUBLIC_IDENTITY; + } else { + return peer_address_type_t::RANDOM_STATIC_IDENTITY; + } + } else { + if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { + return peer_address_type_t::PUBLIC; + } else { + return peer_address_type_t::RANDOM; + } + } +} + +peer_address_type_t convert_identity_address(advertising_peer_address_type_t address) { + if (address == advertising_peer_address_type_t::PUBLIC) { + return peer_address_type_t::PUBLIC_IDENTITY; + } else { + return peer_address_type_t::RANDOM_STATIC_IDENTITY; + } +} + +// FIXME: update when SD 5 (not alpha!) or more is used for 52840. +#ifndef BLE_GAP_PHY_AUTO +#define BLE_GAP_PHY_AUTO 0 +#endif + +} // namespace + +void radioNotificationStaticCallback(bool param) { + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + gap.processRadioNotificationEvent(param); +} + +nRF5xGap::nRF5xGap() : Gap(), + advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), + whitelistAddressesSize(0), + whitelistAddresses(), + radioNotificationCallbackParam(false), + radioNotificationTimeout(), + _connection_event_handler(NULL), + _privacy_enabled(false), + _peripheral_privacy_configuration(default_peripheral_privacy_configuration), + _central_privacy_configuration(default_central_privacy_configuration), + _non_private_address_type(LegacyAddressType::RANDOM_STATIC), + _preferred_tx_phys(BLE_GAP_PHY_AUTO), + _preferred_rx_phys(BLE_GAP_PHY_AUTO), + _connections_role() +{ + m_connectionHandle = BLE_CONN_HANDLE_INVALID; +} +/**************************************************************************/ +/*! + @brief Sets the advertising parameters and payload for the device + + @param[in] params + Basic advertising details, including the advertising + delay, timeout and how the device should be advertised + @params[in] advData + The primary advertising data payload + @params[in] scanResponse + The optional Scan Response payload if the advertising + type is set to \ref GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED + in \ref GapAdveritinngParams + + @returns \ref ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @retval BLE_ERROR_BUFFER_OVERFLOW + The proposed action would cause a buffer overflow. All + advertising payloads must be <= 31 bytes, for example. + + @retval BLE_ERROR_NOT_IMPLEMENTED + A feature was requested that is not yet supported in the + nRF51 firmware or hardware. + + @retval BLE_ERROR_PARAM_OUT_OF_RANGE + One of the proposed values is outside the valid range. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) +{ + /* Make sure we don't exceed the advertising payload length */ + if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { + return BLE_ERROR_BUFFER_OVERFLOW; + } + + /* Make sure we have a payload! */ + if (advData.getPayloadLen() == 0) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Check the scan response payload limits */ + //if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED)) + //{ + // /* Check if we're within the upper limit */ + // if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) + // { + // return BLE_ERROR_BUFFER_OVERFLOW; + // } + // /* Make sure we have a payload! */ + // if (advData.getPayloadLen() == 0) + // { + // return BLE_ERROR_PARAM_OUT_OF_RANGE; + // } + //} + + /* Send advertising data! */ + ASSERT_TRUE(ERROR_NONE == + sd_ble_gap_adv_data_set(advData.getPayload(), + advData.getPayloadLen(), + scanResponse.getPayload(), + scanResponse.getPayloadLen()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + /* Make sure the GAP Service appearance value is aligned with the + *appearance from GapAdvertisingData */ + ASSERT_TRUE(ERROR_NONE == sd_ble_gap_appearance_set(advData.getAppearance()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + /* ToDo: Perform some checks on the payload, for example the Scan Response can't */ + /* contains a flags AD type, etc. */ + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Starts the BLE HW, initialising any services that were + added before this function was called. + + @note All services must be added before calling this function! + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) +{ + uint32_t err; + ble_gap_adv_params_t adv_para = {0}; + + /* Make sure we support the advertising type */ + if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) { + /* ToDo: This requires a propery security implementation, etc. */ + return BLE_ERROR_NOT_IMPLEMENTED; + } + + /* Check interval range */ + if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) { + /* Min delay is slightly longer for unconnectable devices */ + if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) || + (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } else { + if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) || + (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } + + /* Check timeout is zero for Connectable Directed */ + if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) { + /* Timeout must be 0 with this type, although we'll never get here */ + /* since this isn't implemented yet anyway */ + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Check timeout for other advertising types */ + if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && + (params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ + if (advertisingPolicyMode != Gap::ADV_POLICY_IGNORE_WHITELIST) { + ble_error_t error = generateStackWhitelist(whitelist); + if (error != BLE_ERROR_NONE) { + return error; + } + } + + if (_privacy_enabled) { + if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) { + ArrayView entries = get_sm().get_resolving_list(); + + size_t limit = std::min( + entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE + ); + + for (size_t i = 0; i < limit; ++i) { + whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); + } + whitelist.irk_count = limit; + } + + if (_peripheral_privacy_configuration.use_non_resolvable_random_address && + is_advertising_non_connectable(params) + ) { + set_private_non_resolvable_address(); + } else { + set_private_resolvable_address(); + } + } + adv_para.p_whitelist = &whitelist; +#else + if (_privacy_enabled) { + bool enable_resolution = + _peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE; + update_identities_list(enable_resolution); + + if (_peripheral_privacy_configuration.use_non_resolvable_random_address && + is_advertising_non_connectable(params) + ) { + set_private_non_resolvable_address(); + } else { + set_private_resolvable_address(); + } + } +#endif + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + /* Start Advertising */ + + + adv_para.type = params.getAdvertisingType(); + adv_para.p_peer_addr = NULL; // Undirected advertisement + adv_para.fp = advertisingPolicyMode; + adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms) + adv_para.timeout = params.getTimeout(); + +#if (NRF_SD_BLE_API_VERSION >= 5) + err = sd_ble_gap_adv_start(&adv_para, NRF_CONNECTION_TAG); +#else + err = sd_ble_gap_adv_start(&adv_para); +#endif + switch(err) { + case ERROR_NONE: + return BLE_ERROR_NONE; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) +ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams) +{ + + ble_gap_scan_params_t scanParams; + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ + if (scanningPolicyMode != Gap::SCAN_POLICY_IGNORE_WHITELIST) { + ble_error_t error = generateStackWhitelist(whitelist); + if (error != BLE_ERROR_NONE) { + return error; + } + } + + // FIXME: fill the irk list once addresses are resolved by the softdevice. + scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ + scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ +#else + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + scanParams.use_whitelist = scanningPolicyMode; + scanParams.adv_dir_report = 0; +#endif + + scanParams.active = scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + + scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + + if (_privacy_enabled) { + bool enable_resolution = + _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE; + + update_identities_list(enable_resolution); + + if (_central_privacy_configuration.use_non_resolvable_random_address) { + set_private_non_resolvable_address(); + } else { + set_private_resolvable_address(); + } + } + + if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::stopScan(void) { + if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + return BLE_STACK_BUSY; +} +#endif + +/**************************************************************************/ +/*! + @brief Stops the BLE HW and disconnects from any devices + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::stopAdvertising(void) +{ + /* Stop Advertising */ + ASSERT_TRUE(ERROR_NONE == sd_ble_gap_adv_stop(), BLE_ERROR_PARAM_OUT_OF_RANGE); + + state.advertising = 0; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + peer_address_type_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn +) { + // NOTE: Nordic address type is an closer to LegacyAddressType: resolved + // address are treaded either as PUBLIC or RANDOM STATIC adresses. + // The idea is to get the conversion done here and call the legacy function. + + LegacyAddressType_t legacy_address; + + switch (peerAddrType.value()) { + case peer_address_type_t::PUBLIC: + case peer_address_type_t::PUBLIC_IDENTITY: + legacy_address = LegacyAddressType::PUBLIC; + break; + case peer_address_type_t::RANDOM_STATIC_IDENTITY: + legacy_address = LegacyAddressType::RANDOM_STATIC; + break; + case peer_address_type_t::RANDOM: { + RandomAddressType_t random_address_type(RandomAddressType_t::STATIC); + ble_error_t err = getRandomAddressType(peerAddr, &random_address_type); + if (err) { + return err; + } + switch (random_address_type.value()) { + case RandomAddressType_t::STATIC: + legacy_address = LegacyAddressType::RANDOM_STATIC; + break; + case RandomAddressType_t::NON_RESOLVABLE_PRIVATE: + legacy_address = LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE; + break; + case RandomAddressType_t::RESOLVABLE_PRIVATE: + legacy_address = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; + break; + default: + return BLE_ERROR_UNSPECIFIED; + } + } break; + default: + return BLE_ERROR_INVALID_PARAM; + } + + bool identity = + peerAddrType == peer_address_type_t::PUBLIC_IDENTITY || + peerAddrType == peer_address_type_t::RANDOM_STATIC_IDENTITY; + + return connect(peerAddr, legacy_address, connectionParams, scanParamsIn, identity); +} + + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + LegacyAddressType_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn +) { + return connect(peerAddr, peerAddrType, connectionParams, scanParamsIn, false); +} + +ble_error_t nRF5xGap::connect( + const Address_t peerAddr, + LegacyAddressType_t peerAddrType, + const ConnectionParams_t *connectionParams, + const GapScanningParams *scanParamsIn, + bool identity +) { + ble_gap_addr_t addr; + ble_gap_addr_t* addr_ptr = &addr; + addr.addr_type = peerAddrType; + memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); + + ble_gap_conn_params_t connParams; + if (connectionParams != NULL) { + connParams.min_conn_interval = connectionParams->minConnectionInterval; + connParams.max_conn_interval = connectionParams->maxConnectionInterval; + connParams.slave_latency = connectionParams->slaveLatency; + connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; + } else { + connParams.min_conn_interval = 50; + connParams.max_conn_interval = 100; + connParams.slave_latency = 0; + connParams.conn_sup_timeout = 600; + } + + ble_gap_scan_params_t scanParams ={0}; + +#if (NRF_SD_BLE_API_VERSION <= 2) + /* Allocate the stack's whitelist statically */ + ble_gap_whitelist_t whitelist; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Initialize the whitelist */ + whitelist.pp_addrs = whitelistAddressPtrs; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.addr_count = 0; + whitelist.irk_count = 0; + + /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ + if (scanningPolicyMode != Gap::SCAN_POLICY_IGNORE_WHITELIST) { + ble_error_t error = generateStackWhitelist(whitelist); + if (error != BLE_ERROR_NONE) { + return error; + } + } + + scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ + scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ + if (_privacy_enabled) { + // configure the "whitelist" with the IRK associated with the identity + // address in input. + if (is_identity_address(peerAddrType)) { + ArrayView entries = get_sm().get_resolving_list(); + + size_t i; + for (i = 0; i < entries.size(); ++i) { + const ble::address_t& entry_address = entries[i].peer_identity_address; + + // entry found; fill the whitelist and invalidate addr_ptr + if (memcmp(entry_address.data(), peerAddr, entry_address.size_) == 0) { + whitelist.pp_irks[0] = (ble_gap_irk_t*) entries[i].peer_irk.data(); + whitelist.irk_count = 1; + scanParams.selective = 1; + addr_ptr = NULL; + break; + } + } + + // Occur only if the address in input hasn't been resolved. + if (i == entries.size()) { + return BLE_ERROR_INVALID_PARAM; + } + } + + set_private_resolvable_address(); + } +#else + /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ + + scanParams.use_whitelist = (whitelistAddressesSize) ? 1 : 0; + + if (_privacy_enabled) { + bool enable_resolution = + _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE; + + update_identities_list(enable_resolution); + + if (enable_resolution && identity) { + addr.addr_id_peer = 1; + } + + set_private_resolvable_address(); + } + +#endif + + if (scanParamsIn != NULL) { + scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + } else { + scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ + scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + } + +#if NRF_SD_BLE_API_VERSION >= 5 + uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams, NRF_CONNECTION_TAG); +#else + uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams); +#endif + if (rc == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + switch (rc) { + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case BLE_ERROR_GAP_INVALID_BLE_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + case BLE_ERROR_GAP_WHITELIST_IN_USE: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t nRF5xGap::readPhy(Handle_t connection) { + /* + * This function is not implemented as it is not possible with current + * nordic API to know which phy was used to establish the connection. + * + * TODO: Update when Nordic provides the API to do the job. + */ + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xGap::setPreferredPhys( + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys +) { + uint8_t preferred_tx_phys = txPhys? txPhys->value() : 0; + uint8_t preferred_rx_phys = rxPhys? rxPhys->value() : 0; + +#ifdef S140 + ble_opt_t opt = { 0 }; + opt.gap_opt.preferred_phys.tx_phys = preferred_tx_phys; + opt.gap_opt.preferred_phys.rx_phys = preferred_rx_phys; + + uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PREFERRED_PHYS_SET, &opt); + + switch (err) { + case NRF_SUCCESS: + break; + case NRF_ERROR_INVALID_ADDR: + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + return BLE_ERROR_UNSPECIFIED; + } + +#endif + + _preferred_tx_phys = preferred_tx_phys; + _preferred_rx_phys = preferred_rx_phys; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setPhy( + Handle_t connection, + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys, + CodedSymbolPerBit_t codedSymbol +) { +#ifdef S140 + return BLE_ERROR_NOT_IMPLEMENTED; +#else + // TODO handle coded symbol once supported by the softdevice. + ble_gap_phys_t gap_phys = { + txPhys? txPhys->value() : 0, + rxPhys? rxPhys->value() : 0 + }; + + uint32_t err = sd_ble_gap_phy_update(connection, &gap_phys); + + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + default: + return BLE_ERROR_UNSPECIFIED; + } +#endif +} + +ble_error_t nRF5xGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) +{ + uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; + switch (reason) { + case REMOTE_USER_TERMINATED_CONNECTION: + code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; + break; + case CONN_INTERVAL_UNACCEPTABLE: + code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE; + break; + default: + break; + } + + /* Disconnect if we are connected to a central device */ + ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +/*! + @brief Disconnects if we are connected to a central device + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +ble_error_t nRF5xGap::disconnect(DisconnectionReason_t reason) +{ + return disconnect(m_connectionHandle, reason); +} + +ble_error_t nRF5xGap::getPreferredConnectionParams(ConnectionParams_t *params) +{ + ASSERT_INT(NRF_SUCCESS, + sd_ble_gap_ppcp_get(reinterpret_cast(params)), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setPreferredConnectionParams(const ConnectionParams_t *params) +{ + ASSERT_INT(NRF_SUCCESS, + sd_ble_gap_ppcp_set(reinterpret_cast(params)), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams) +{ + uint32_t rc; + + rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast(const_cast(newParams))); + if (rc == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/**************************************************************************/ +/*! + @brief Clear nRF5xGap's state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::reset(void) +{ + /* Clear all state that is from the parent, including private members */ + if (Gap::reset() != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_STATE; + } + + /* Clear derived class members */ + m_connectionHandle = BLE_CONN_HANDLE_INVALID; + + /* Set the whitelist policy filter modes to IGNORE_WHITELIST */ + advertisingPolicyMode = Gap::ADV_POLICY_IGNORE_WHITELIST; + scanningPolicyMode = Gap::SCAN_POLICY_IGNORE_WHITELIST; + + /* Clear the internal whitelist */ + whitelistAddressesSize = 0; + + /* Reset existing mapping between a connection and its role */ + release_all_connections_role(); + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Sets the 16-bit connection handle +*/ +/**************************************************************************/ +void nRF5xGap::setConnectionHandle(uint16_t con_handle) +{ + m_connectionHandle = con_handle; +} + +/**************************************************************************/ +/*! + @brief Gets the 16-bit connection handle +*/ +/**************************************************************************/ +uint16_t nRF5xGap::getConnectionHandle(void) +{ + return m_connectionHandle; +} + +/**************************************************************************/ +/*! + @brief Sets the BLE device address + + @returns ble_error_t + + @section EXAMPLE + + @code + + uint8_t device_address[6] = { 0xca, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0 }; + nrf.getGap().setAddress(Gap::BLEProtocol::AddressType::RANDOM_STATIC, device_address); + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAddress(LegacyAddressType_t type, const Address_t address) +{ + if (type != LegacyAddressType::PUBLIC && + type != LegacyAddressType::RANDOM_STATIC + ) { + return BLE_ERROR_INVALID_PARAM; + } + + if (_privacy_enabled) { + return BLE_ERROR_INVALID_STATE; + } + + ble_gap_addr_t dev_addr; + memcpy(dev_addr.addr, address, ADDR_LEN); + if (type == LegacyAddressType::PUBLIC) { + dev_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + } else { + dev_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; + } + +#if (NRF_SD_BLE_API_VERSION <= 2) + uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr); +#else + uint32_t err = sd_ble_gap_addr_set(&dev_addr); +#endif + + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case BLE_ERROR_GAP_INVALID_BLE_ADDR: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address) +{ + // FIXME: check if privacy is enabled ? + if (typeP == NULL || address == NULL) { + return BLE_ERROR_INVALID_PARAM; + } + + ble_gap_addr_t dev_addr; +#if (NRF_SD_BLE_API_VERSION <= 2) + if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) { +#else + if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) { +#endif + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + switch (dev_addr.addr_type) { + case BLE_GAP_ADDR_TYPE_PUBLIC: + *typeP = LegacyAddressType::PUBLIC; + break; + + case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: + *typeP = LegacyAddressType::RANDOM_STATIC; + break; + + default: + return BLE_ERROR_INVALID_STATE; + } + + memcpy(address, dev_addr.addr, ADDR_LEN); + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setDeviceName(const uint8_t *deviceName) +{ + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed + + if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP) +{ + if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::setAppearance(GapAdvertisingData::Appearance appearance) +{ + if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +ble_error_t nRF5xGap::getAppearance(GapAdvertisingData::Appearance *appearanceP) +{ + if ((sd_ble_gap_appearance_get(reinterpret_cast(appearanceP)) == NRF_SUCCESS)) { + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } +} + +/* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ +ble_error_t nRF5xGap::setTxPower(int8_t txPower) +{ + unsigned rc; + if ((rc = sd_ble_gap_tx_power_set(txPower)) != NRF_SUCCESS) { + switch (rc) { + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_INVALID_PARAM: + default: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + } + + return BLE_ERROR_NONE; +} + +void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) +{ +#if defined(NRF51) + static const int8_t permittedTxValues[] = { + -30, -20, -16, -12, -8, -4, 0, 4 + }; +#elif defined(NRF52) +#if NRF_SD_BLE_API_VERSION >= 5 + static const int8_t permittedTxValues[] = { + -40, -20, -16, -12, -8, -4, 0, 3, 4 + }; +#else + static const int8_t permittedTxValues[] = { + -40, -20, -16, -12, -8, -4, 0, 4 + }; +#endif +#elif defined(NRF52840_XXAA) + static const int8_t permittedTxValues[] = { + -40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8, 9 + }; +#else +#error permitted TX power values unknown for this SOC +#endif + + *valueArrayPP = permittedTxValues; + *countP = sizeof(permittedTxValues) / sizeof(int8_t); +} + +/**************************************************************************/ +/*! + @brief Get the capacity of the internal whitelist maintained by this + implementation. + + @returns The capacity of the internal whitelist. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +uint8_t nRF5xGap::getMaxWhitelistSize(void) const +{ + return YOTTA_CFG_WHITELIST_MAX_SIZE; +} + +/**************************************************************************/ +/*! + @brief Get a copy of the implementation's internal whitelist. + + @param[out] whitelistOut + A \ref Gap::Whitelist_t structure containing a copy of the + addresses in the implemenetation's internal whitelist. + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const +{ + uint32_t i; + for (i = 0; i < whitelistAddressesSize && i < whitelistOut.capacity; ++i) { + memcpy( &whitelistOut.addresses[i].address, &whitelistAddresses[i].addr, sizeof(whitelistOut.addresses[0].address)); + whitelistOut.addresses[i].type = static_cast (whitelistAddresses[i].addr_type); + + + } + whitelistOut.size = i; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the whitelist that will be used in the next call to + startAdvertising(). + + @param[in] whitelistIn + A reference to a \ref Gap::Whitelist_t structure + representing a whitelist containing all the white listed + BLE addresses. + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_INVALID_PARAM + The supplied whitelist contains a private non-resolvable + address + + BLE_ERROR_PARAM_OUT_OF_RANGE + The size of the supplied whitelist exceeds the maximum + capacity of the implementation's internal whitelist. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) +{ + if (whitelistIn.size > getMaxWhitelistSize()) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + /* Test for invalid parameters before we change the internal state */ + for (uint32_t i = 0; i < whitelistIn.size; ++i) { + if (whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE || + whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE + ) { + /* This is not allowed because it is completely meaningless */ + return BLE_ERROR_INVALID_PARAM; + } + } + + whitelistAddressesSize = whitelistIn.size; + ble_gap_addr_t* pp_addrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + + for (uint32_t i = 0; i < whitelistIn.size; ++i) { + memcpy(&whitelistAddresses[i].addr, &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr)); + whitelistAddresses[i].addr_type = static_cast (whitelistIn.addresses[i].type); + pp_addrs[i] = &whitelistAddresses[i]; + } + + ble_gap_addr_t** addresses_list_ptr = (whitelistIn.size == 0) ? NULL : pp_addrs; + + uint32_t err = sd_ble_gap_whitelist_set(addresses_list_ptr, whitelistAddressesSize); + + switch(err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + + case BLE_ERROR_GAP_WHITELIST_IN_USE: + return BLE_ERROR_INVALID_STATE; + + case NRF_ERROR_INVALID_ADDR: + case BLE_ERROR_GAP_INVALID_BLE_ADDR: + case NRF_ERROR_DATA_SIZE: + return BLE_ERROR_INVALID_PARAM; + + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +/**************************************************************************/ +/*! + @brief Set the advertising policy filter mode that will be used in + the next call to startAdvertising(). + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) +{ + advertisingPolicyMode = mode; + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the scanning policy filter mode that will be used in + the next call to startAdvertising(). + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) +{ + scanningPolicyMode = mode; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Set the initiator policy filter mode that will be used in + the next call to startAdvertising() + + @returns \ref ble_errror_t + + @retval BLE_ERROR_NONE + Everything executed properly. + + BLE_ERROR_NOT_IMPLEMENTED + This feature is currently note implemented. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) +{ + return BLE_ERROR_NOT_IMPLEMENTED; +} + +/**************************************************************************/ +/*! + @brief Get the current advertising policy filter mode. + + @returns The advertising policy filter mode. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const +{ + return advertisingPolicyMode; +} + +/**************************************************************************/ +/*! + @brief Get the current scanning policy filter mode. + + @returns The scanning policy filter mode. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const +{ + return scanningPolicyMode; +} + +/**************************************************************************/ +/*! + @brief Get the current initiator policy filter mode. + + @returns The initiator policy filter mode. + + @note Currently initiator filtering using the whitelist is not + implemented in this module. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const +{ + return Gap::INIT_POLICY_IGNORE_WHITELIST; +} + +ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy) +{ + if (enable_privacy == _privacy_enabled) { + return BLE_ERROR_NONE; + } + + ble_error_t err = BLE_ERROR_UNSPECIFIED; + if (enable_privacy == false) { + err = setAddress(_non_private_address_type, _non_private_address); + } else { + err = getAddress(&_non_private_address_type, _non_private_address); + } + + if (err) { + return err; + } + +#if (NRF_SD_BLE_API_VERSION > 2) + ble_gap_privacy_params_t privacy_config = { 0 }; + if (sd_ble_gap_privacy_get(&privacy_config)) { + return BLE_ERROR_UNSPECIFIED; + } + + privacy_config.privacy_mode = enable_privacy ? + BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY : + BLE_GAP_PRIVACY_MODE_OFF; + if (sd_ble_gap_privacy_set(&privacy_config)) { + return BLE_ERROR_UNSPECIFIED; + } +#endif + + _privacy_enabled = enable_privacy; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setPeripheralPrivacyConfiguration( + const PeripheralPrivacyConfiguration_t *configuration +) { + _peripheral_privacy_configuration = *configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::getPeripheralPrivacyConfiguration( + PeripheralPrivacyConfiguration_t *configuration +) { + *configuration = _peripheral_privacy_configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setCentralPrivacyConfiguration( + const CentralPrivacyConfiguration_t *configuration +) { + _central_privacy_configuration = *configuration; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::getCentralPrivacyConfiguration( + CentralPrivacyConfiguration_t *configuration +) { + *configuration = _central_privacy_configuration; + return BLE_ERROR_NONE; +} + +void nRF5xGap::set_connection_event_handler( + ConnectionEventMonitor::EventHandler* connection_event_handler +) { + _connection_event_handler = connection_event_handler; +} + +void nRF5xGap::processDisconnectionEvent( + Handle_t handle, + DisconnectionReason_t reason +) { + release_connection_role(handle); + + if (_connection_event_handler) { + _connection_event_handler->on_disconnected( + handle, + reason + ); + } + + ::Gap::processDisconnectionEvent( + handle, + reason + ); +} + +ble_error_t nRF5xGap::update_identities_list(bool resolution_enabled) +{ + uint32_t err; + + if (resolution_enabled) { + ArrayView entries = get_sm().get_resolving_list(); + size_t limit = std::min( + entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE + ); + ble_gap_id_key_t* id_keys_pp[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + + for (size_t i = 0; i < limit; ++i) { + id_keys_pp[i] = &entries[i]; + } + + err = sd_ble_gap_device_identities_set( + limit ? id_keys_pp : NULL, + /* use the local IRK for all devices */ NULL, + limit + ); + } else { + err = sd_ble_gap_device_identities_set( + NULL, + /* use the local IRK for all devices */ NULL, + 0 + ); + } + + return err ? BLE_ERROR_INVALID_STATE : BLE_ERROR_NONE; +} + +void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t& evt) { + // set the new connection handle as the _default_ handle in gap + setConnectionHandle(handle); + + // add the connection and the role of the device in the local table + allocate_connection_role(handle, static_cast(evt.role)); + + // deal with own address + LegacyAddressType_t own_addr_type; + ble::address_t own_address; + const uint8_t* own_resolvable_address = NULL; + +#if (NRF_SD_BLE_API_VERSION <= 2) + if (evt.own_addr.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) { + own_addr_type = AddressType::PUBLIC; + } else { + own_addr_type = AddressType::RANDOM; + } + memcpy(own_address, evt.own_addr.addr, sizeof(own_address)); +#else + getAddress(&own_addr_type, own_address.data()); + if (_privacy_enabled) { + own_addr_type = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; + } +#endif + +#if (NRF_SD_BLE_API_VERSION <= 2) + bool private_peer_known = evt.irk_match; +#else + bool private_peer_known = evt.peer_addr.addr_id_peer; +#endif + + // Filter out private address non resolved if the its required by the + // resolution policy + if (_privacy_enabled && + evt.role == BLE_GAP_ROLE_PERIPH && + _peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && + private_peer_known == false && + get_sm().get_resolving_list().size() > 0 + ) { + // FIXME: should use BLE_HCI_AUTHENTICATION_FAILURE; not possible + // with the softdevice ... + sd_ble_gap_disconnect(handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + return; + } + + // deal with the peer address: If privacy is enabled then the softdevice + // indicates if the address has been resolved or not. If the address has + // been resolved then the identity address should be passed to the application. + // Depending on the privacy chosen by the application, connection request + // from privacy enabled peers may trigger a disconnection, the pairing procedure + // or the authentication procedure. + peer_address_type_t peer_addr_type = convert_nordic_address( + private_peer_known, + evt.peer_addr.addr_type + ); + + // NOTE: when privacy is enabled, the only address returned is the resolved + // address. + const uint8_t* peer_address = evt.peer_addr.addr; + const uint8_t* peer_resolvable_address = NULL; + + // notify internal event handler before applying the resolution strategy + if (_connection_event_handler) { + _connection_event_handler->on_connected( + handle, + static_cast(evt.role), + peer_addr_type, + peer_address, + own_addr_type, + own_address.data(), + reinterpret_cast(&(evt.conn_params)) + ); + } + + // Apply authentication strategy before application notification + if (_privacy_enabled && + !private_peer_known && + evt.role == BLE_GAP_ROLE_PERIPH && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + ) { + switch (_peripheral_privacy_configuration.resolution_strategy) { + case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE: + nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getSecurityManager().requestAuthentication(handle); + break; + + case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE: + // FIXME: lookup secure DB to know what to do. + break; + + default: + break; + } + } + + processConnectionEvent( + handle, + static_cast(evt.role), + peer_addr_type, + peer_address, + own_addr_type, + own_address.data(), + reinterpret_cast(&(evt.conn_params)), + peer_resolvable_address, + own_resolvable_address + ); +} + +void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { + bool peer_address_resolved = evt.peer_addr.addr_id_peer; + + if (_privacy_enabled && + evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && + peer_address_resolved == false && + get_sm().get_resolving_list().size() > 0 && + _central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::RESOLVE_AND_FILTER + ) { + return; + } + + peer_address_type_t peer_addr_type = convert_nordic_address( + evt.peer_addr.addr_id_peer, + evt.peer_addr.addr_type + ); + const uint8_t* peer_address = evt.peer_addr.addr; + + processAdvertisementReport( + peer_address, + evt.rssi, + evt.scan_rsp, + static_cast(evt.type), + evt.dlen, + evt.data, + peer_addr_type + ); +} + +ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + role = c.is_peripheral ? PERIPHERAL : CENTRAL; + return BLE_ERROR_NONE; + } + } + + return BLE_ERROR_INVALID_PARAM; +} + +void nRF5xGap::allocate_connection_role( + ble::connection_handle_t connection, + Role_t role +) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated == false) { + c.connection = connection; + c.is_peripheral = (role == Gap::PERIPHERAL); + c.is_allocated = true; + return; + } + } +} +void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + c.is_allocated = false; + return; + } + } +} + +void nRF5xGap::release_all_connections_role() { + for (size_t i = 0; i < max_connections_count; ++i) { + _connections_role[i].is_allocated = false; + } +} +void nRF5xGap::on_phy_update( + Handle_t connection, + const ble_gap_evt_phy_update_t& evt +) { + if (!_eventHandler) { + return; + } + + ble_error_t status; + switch (evt.status) { + case BLE_HCI_STATUS_CODE_SUCCESS: + status = BLE_ERROR_NONE; + break; + + case BLE_HCI_UNSUPPORTED_REMOTE_FEATURE: + status = BLE_ERROR_OPERATION_NOT_PERMITTED; + break; + + case BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION: + case BLE_HCI_DIFFERENT_TRANSACTION_COLLISION: + status = BLE_ERROR_INVALID_STATE; + break; + + case BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS: + status = BLE_ERROR_INVALID_PARAM; + break; + + default: + status = BLE_ERROR_UNSPECIFIED; + break; + } + + _eventHandler->onPhyUpdateComplete( + status, + connection, + Phy_t::LE_1M, + Phy_t::LE_1M + ); +} + +#ifndef S140 +void nRF5xGap::on_phy_update_request( + Handle_t connection, + const ble_gap_evt_phy_update_request_t& evt +) { + ble_gap_phys_t phys = { + _preferred_tx_phys & evt.peer_preferred_phys.tx_phys, + _preferred_rx_phys & evt.peer_preferred_phys.rx_phys + }; + + if (!phys.tx_phys) { + phys.tx_phys = BLE_GAP_PHY_AUTO; + } + + if (!phys.rx_phys) { + phys.rx_phys = BLE_GAP_PHY_AUTO; + } + + sd_ble_gap_phy_update(connection, &phys); +} +#endif + + + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.h new file mode 100644 index 0000000000..19273e815c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGap.h @@ -0,0 +1,346 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF5x_GAP_H__ +#define __NRF5x_GAP_H__ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#ifndef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT + #undef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#endif +#ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #if (NRF_SD_BLE_API_VERSION >= 3) + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT + #else + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT + #endif +#elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT + #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#endif +#include "ble/blecommon.h" +#include "headers/nrf_ble.h" +#include "ble/GapAdvertisingParams.h" +#include "ble/GapAdvertisingData.h" +#include "ble/Gap.h" +#include "ble/GapScanningParams.h" +#include "ble/pal/ConnectionEventMonitor.h" + +#include "nrf_soc.h" + +extern "C" { +#include "ble_radio_notification.h" +#include "app_util_platform.h" +} + +void radioNotificationStaticCallback(bool param); + +/**************************************************************************/ +/*! + \brief + +*/ +/**************************************************************************/ +class nRF5xGap : public ::Gap, public ble::pal::ConnectionEventMonitor { +public: + nRF5xGap(); + + virtual ~nRF5xGap() { } + /* Functions that must be implemented from Gap */ + virtual ble_error_t setAddress(AddressType_t type, const Address_t address); + virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address); + virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &); + + virtual uint16_t getMinAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MIN);} + virtual uint16_t getMinNonConnectableAdvertisingInterval(void) const { + #if (NRF_SD_BLE_API_VERSION >= 5) // In SD v5+, non connectable advertising interval is the same as connectable advertising interval + // The Mbed infrastructure expects 100ms+ - so for now return that + // return getMinAdvertisingInterval(); + // FIXME infrastructure + return GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON; + #else + return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_NONCON_INTERVAL_MIN); + #endif + } + virtual uint16_t getMaxAdvertisingInterval(void) const {return GapAdvertisingParams::ADVERTISEMENT_DURATION_UNITS_TO_MS(BLE_GAP_ADV_INTERVAL_MAX);} + + virtual ble_error_t startAdvertising(const GapAdvertisingParams &); + virtual ble_error_t stopAdvertising(void); + virtual ble_error_t connect(const Address_t, ble::peer_address_type_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); + virtual ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams); + ble_error_t connect(const Address_t, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams, bool identity); + + virtual ble_error_t readPhy(Handle_t connection); + virtual ble_error_t setPreferredPhys( + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys + ); + virtual ble_error_t setPhy( + Handle_t connection, + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys, + CodedSymbolPerBit_t codedSymbol + ); + + virtual ble_error_t disconnect(Handle_t connectionHandle, DisconnectionReason_t reason); + virtual ble_error_t disconnect(DisconnectionReason_t reason); + + virtual ble_error_t setDeviceName(const uint8_t *deviceName); + virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP); + virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance); + virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP); + + virtual ble_error_t setTxPower(int8_t txPower); + virtual void getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP); + + void setConnectionHandle(uint16_t con_handle); + uint16_t getConnectionHandle(void); + + virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params); + virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params); + virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params); + + virtual ble_error_t reset(void); + + /* + * The following functions are part of the whitelisting experimental API. + * Therefore, this functionality can change in the near future. + */ + virtual uint8_t getMaxWhitelistSize(void) const; + virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; + virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); + + virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); + virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); + virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); + virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; + virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; + virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; + + virtual ble_error_t initRadioNotification(void) { + if (ble_radio_notification_init(APP_IRQ_PRIORITY_HIGH /*MID*/, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + return BLE_ERROR_UNSPECIFIED; + } + + virtual ble_error_t enablePrivacy(bool enable); + + virtual ble_error_t setPeripheralPrivacyConfiguration( + const PeripheralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t getPeripheralPrivacyConfiguration( + PeripheralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t setCentralPrivacyConfiguration( + const CentralPrivacyConfiguration_t *configuration + ); + + virtual ble_error_t getCentralPrivacyConfiguration( + CentralPrivacyConfiguration_t *configuration + ); +/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); + virtual ble_error_t stopScan(void); +#endif + +private: + /* + * Whitelisting API related structures and helper functions. + */ + + /* Policy modes set by the user. By default these are set to ignore the whitelist */ + Gap::AdvertisingPolicyMode_t advertisingPolicyMode; + Gap::ScanningPolicyMode_t scanningPolicyMode; + + /* Internal representation of a whitelist */ + uint8_t whitelistAddressesSize; + ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; + +private: + bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ + Timeout radioNotificationTimeout; + + /* + * A helper function to post radio notification callbacks with low interrupt priority. + */ + void postRadioNotificationCallback(void) { +#ifdef YOTTA_CFG_MBED_OS + /* + * In mbed OS, all user-facing BLE events (interrupts) are posted to the + * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards + * its critical sections from interrupts by acquiring CriticalSectionLock, + * which results in a call to sd_nvic_critical_region_enter(). Thus, it is + * safe to invoke MINAR APIs from interrupt context as long as those + * interrupts are blocked by sd_nvic_critical_region_enter(). + * + * Radio notifications are a special case for the above. The Radio + * Notification IRQ is handled at a very high priority--higher than the + * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification + * events can preempt MINAR's critical sections. Using MINAR APIs (such as + * posting an event) directly in processRadioNotification() may result in a + * race condition ending in a hard-fault. + * + * The solution is to *not* call MINAR APIs directly from the Radio + * Notification handling; i.e. to do the bulk of RadioNotification + * processing at a reduced priority which respects MINAR's critical + * sections. Unfortunately, on a cortex-M0, there is no clean way to demote + * priority for the currently executing interrupt--we wouldn't want to + * demote the radio notification handling anyway because it is sensitive to + * timing, and the system expects to finish this handling very quickly. The + * workaround is to employ a Timeout to trigger + * postRadioNotificationCallback() after a very short delay (~0 us) and post + * the MINAR callback that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + minar::Scheduler::postCallback( + mbed::util::FunctionPointer1(&radioNotificationCallback, &FunctionPointerWithContext::call).bind(radioNotificationCallbackParam) + ); +#else + /* + * In mbed classic, all user-facing BLE events execute callbacks in interrupt + * mode. Radio Notifications are a special case because its IRQ is handled at + * a very high priority. Thus Radio Notification events can preempt other + * operations that require interaction with the SoftDevice such as advertising + * payload updates and changing the Gap state. Therefore, executing a Radio + * Notification callback directly from processRadioNotification() may result + * in a race condition ending in a hard-fault. + * + * The solution is to *not* execute the Radio Notification callback directly + * from the Radio Notification handling; i.e. to do the bulk of the + * Radio Notification processing at a reduced priority. Unfortunately, on a + * cortex-M0, there is no clean way to demote priority for the currently + * executing interrupt--we wouldn't want to demote the radio notification + * handling anyway because it is sensitive to timing, and the system expects + * to finish this handling very quickly. The workaround is to employ a Timeout + * to trigger postRadioNotificationCallback() after a very short delay (~0 us) + * and execute the callback in that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio + * notification event is generated. + */ + radioNotificationCallback.call(radioNotificationCallbackParam); +#endif /* #ifdef YOTTA_CFG_MBED_OS */ + } + + /** + * A helper function to process radio-notification events; to be called internally. + * @param param [description] + */ + void processRadioNotificationEvent(bool param) { + radioNotificationCallbackParam = param; + radioNotificationTimeout.attach_us(mbed::callback(this, &nRF5xGap::postRadioNotificationCallback), 0); + } + friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */ +public: + /** @note Implements ConnectionEventMonitor. + * @copydoc ConnectionEventMonitor::set_connection_event_handler + */ + virtual void set_connection_event_handler( + ConnectionEventMonitor::EventHandler* connection_event_handler + ); + + /** + * @copydoc ::Gap::processDisconnectionEvent + */ + void processDisconnectionEvent( + Handle_t handle, + DisconnectionReason_t reason + ); + + /** + * Return the role of the local peripheral for a given connection. + * + * @param[in] connection The connection queried. + * @param[out] role The role of the local device in the connection. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + ble_error_t get_role(ble::connection_handle_t connection, Role_t& role); + +private: + friend void btle_handler(const ble_evt_t *p_ble_evt); + friend void btle_handler(const ble_evt_t *p_ble_evt, void *p_context); + + ble_error_t update_identities_list(bool resolution_enabled); + void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt); + void on_advertising_packet(const ble_gap_evt_adv_report_t &evt); + + void allocate_connection_role(ble::connection_handle_t, Role_t); + void release_connection_role(ble::connection_handle_t); + void release_all_connections_role(); + + void on_phy_update(Handle_t connection, const ble_gap_evt_phy_update_t& evt); + // FIXME: remove guard when S140 updated + #ifndef S140 + void on_phy_update_request(Handle_t connection, const ble_gap_evt_phy_update_request_t& evt); + #endif + + uint16_t m_connectionHandle; + ConnectionEventMonitor::EventHandler* _connection_event_handler; + + bool _privacy_enabled; + PeripheralPrivacyConfiguration_t _peripheral_privacy_configuration; + CentralPrivacyConfiguration_t _central_privacy_configuration; + AddressType_t _non_private_address_type; + Address_t _non_private_address; + uint8_t _preferred_tx_phys; + uint8_t _preferred_rx_phys; + + struct connection_role_t { + connection_role_t() : + connection(), + is_peripheral(false), + is_allocated(false) + { } + + ble::connection_handle_t connection; + uint8_t is_peripheral:1; + uint8_t is_allocated:1; + }; + + static const size_t max_connections_count = + NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT; + + connection_role_t _connections_role[max_connections_count]; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGap(nRF5xGap const &); + void operator=(nRF5xGap const &); +}; + +#endif // ifndef __NRF5x_GAP_H__ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.cpp new file mode 100644 index 0000000000..8c93ac118c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.cpp @@ -0,0 +1,862 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nRF5xGattServer.h" +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif + +#include "common/common.h" +#include "btle/custom/custom_helper.h" + +#include "nRF5xn.h" + +namespace { + +static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID_OFFSET + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS, + /* .update = */ 0 + } + } +}; + +static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_ATTERR_INVALID + } + } +}; + +static ble_error_t set_attribute_value( + Gap::Handle_t connectionHandle, + GattAttribute::Handle_t attributeHandle, + ble_gatts_value_t *value +) { + uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, value); + switch(err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_NOT_FOUND: + case NRF_ERROR_DATA_SIZE: + case BLE_ERROR_INVALID_CONN_HANDLE: + case BLE_ERROR_GATTS_INVALID_ATTR_TYPE: + return BLE_ERROR_PARAM_OUT_OF_RANGE; + case NRF_ERROR_FORBIDDEN: + return BLE_ERROR_OPERATION_NOT_PERMITTED; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +} // end of anonymous namespace + +/**************************************************************************/ +/*! + @brief Adds a new service to the GATT table on the peripheral + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::addService(GattService &service) +{ + /* ToDo: Make sure this service UUID doesn't already exist (?) */ + /* ToDo: Basic validation */ + + /* Add the service to the nRF51 */ + ble_uuid_t nordicUUID; + nordicUUID = custom_convert_to_nordic_uuid(service.getUUID()); + + uint16_t serviceHandle; + ASSERT_TRUE( ERROR_NONE == + sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, + &nordicUUID, + &serviceHandle), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + service.setHandle(serviceHandle); + + /* Add characteristics to the service */ + for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) { + if (characteristicCount >= BLE_TOTAL_CHARACTERISTICS) { + return BLE_ERROR_NO_MEM; + } + GattCharacteristic *p_char = service.getCharacteristic(i); + GattAttribute *p_description_descriptor = NULL; + GattAttribute *p_presentation_format_descriptor = NULL; + + /* Skip any incompletely defined, read-only characteristics. */ + if ((p_char->getValueAttribute().getValuePtr() == NULL) && + (p_char->getValueAttribute().getLength() == 0) && + (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) { + continue; + } + + nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID()); + + /* The user-description and presentation-format descriptors are special cases + * that need to be handled at the time of adding each characteristic. The + * following block is meant to discover their presence. */ + const uint8_t *userDescriptionDescriptorValuePtr = NULL; + uint16_t userDescriptionDescriptorValueLen = 0; + const uint8_t *presentationFormatDescriptorValuePtr = NULL; + uint16_t presentationFormatDescriptorValueLen = 0; + for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) { + GattAttribute *p_desc = p_char->getDescriptor(j); + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) { + p_description_descriptor = p_desc; + userDescriptionDescriptorValuePtr = p_desc->getValuePtr(); + userDescriptionDescriptorValueLen = p_desc->getLength(); + } + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) { + p_presentation_format_descriptor = p_desc; + presentationFormatDescriptorValuePtr = p_desc->getValuePtr(); + presentationFormatDescriptorValueLen = p_desc->getLength(); + } + } + + ASSERT_TRUE ( ERROR_NONE == + custom_add_in_characteristic( + BLE_GATT_HANDLE_INVALID, + &nordicUUID, + p_char->getProperties(), + p_char->getReadSecurityRequirement(), + p_char->getWriteSecurityRequirement(), + p_char->getUpdateSecurityRequirement(), + p_char->getValueAttribute().getValuePtr(), + p_char->getValueAttribute().getLength(), + p_char->getValueAttribute().getMaxLength(), + p_char->getValueAttribute().hasVariableLength(), + userDescriptionDescriptorValuePtr, + userDescriptionDescriptorValueLen, + presentationFormatDescriptorValuePtr, + presentationFormatDescriptorValueLen, + p_char->isReadAuthorizationEnabled(), + p_char->isWriteAuthorizationEnabled(), + &nrfCharacteristicHandles[characteristicCount] + ), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + + /* Update the characteristic handle */ + p_characteristics[characteristicCount] = p_char; + p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle); + if (p_description_descriptor) { + p_description_descriptor->setHandle( + nrfCharacteristicHandles[characteristicCount].user_desc_handle + ); + } + if (p_presentation_format_descriptor) { + // The handle is not available from the SoftDevice + p_presentation_format_descriptor->setHandle(GattAttribute::INVALID_HANDLE); + } + characteristicCount++; + + /* Add optional descriptors if any */ + for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) { + if (descriptorCount >= BLE_TOTAL_DESCRIPTORS) { + return BLE_ERROR_NO_MEM; + } + + GattAttribute *p_desc = p_char->getDescriptor(j); + /* skip the user-description or presentation-format descriptor here; + * they have already been handled when adding the characteristic (above). */ + if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC + || p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) { + continue; + } + + nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID()); + + ASSERT_TRUE(ERROR_NONE == + custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID, + &nordicUUID, + p_desc->getValuePtr(), + p_desc->getLength(), + p_desc->getMaxLength(), + p_desc->hasVariableLength(), + &nrfDescriptorHandles[descriptorCount], + p_desc->getReadSecurityRequirement(), + p_desc->getWriteSecurityRequirement()), + BLE_ERROR_PARAM_OUT_OF_RANGE); + + p_descriptors[descriptorCount] = p_desc; + p_desc->setHandle(nrfDescriptorHandles[descriptorCount]); + descriptorCount++; + } + } + + serviceCount++; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Reads the value of a characteristic, based on the service + and characteristic index fields + + @param[in] attributeHandle + The handle of the GattCharacteristic to read from + @param[in] buffer + Buffer to hold the the characteristic's value + (raw byte array in LSB format) + @param[in/out] len + input: Length in bytes to be read. + output: Total length of attribute value upon successful return. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) +{ + return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP); +} + +ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) +{ + ble_gatts_value_t value = { + /* .len = */ *lengthP, + /* .offset = */ 0, + /* .p_value = */ buffer, + }; + + ASSERT_TRUE( ERROR_NONE == + sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE); + *lengthP = value.len; + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Updates the value of a characteristic, based on the service + and characteristic index fields + + @param[in] charHandle + The handle of the GattCharacteristic to write to + @param[in] buffer + Data to use when updating the characteristic's value + (raw byte array in LSB format) + @param[in] len + The number of bytes in buffer + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) +{ + return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly); +} + +ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) +{ + ble_error_t returnValue = BLE_ERROR_NONE; + + ble_gatts_value_t value = { + /* .len = */ len, + /* .offset = */ 0, + /* .p_value = */ const_cast(buffer), + }; + + if (localOnly) { + /* Only update locally regardless of notify/indicate */ + ASSERT_INT( ERROR_NONE, + sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + return BLE_ERROR_NONE; + } + + int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); + if ((characteristicIndex != -1) && + (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { + /* HVX update for the characteristic value */ + ble_gatts_hvx_params_t hvx_params; + + hvx_params.handle = attributeHandle; + hvx_params.type = + (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; + hvx_params.offset = 0; + hvx_params.p_data = const_cast(buffer); + hvx_params.p_len = &len; + + if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */ + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + connectionHandle = gap.getConnectionHandle(); + } + + bool updatesEnabled = false; + if (connectionHandle != BLE_CONN_HANDLE_INVALID) { + ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled); + + // FIXME: The softdevice allocates and populates CCCD when the client + // interract with them. Checking for updates may return an out of + // range error in such case. + if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) { + return err; + } + } + + bool updates_permitted = false; + ble_gap_conn_sec_t connection_security; + uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security); + if (!err && + (connection_security.sec_mode.sm == 1) && + (connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) { + updates_permitted = true; + } + + if (updatesEnabled && updates_permitted) { + error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); + if (error != ERROR_NONE) { + switch (error) { + case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */ + case ERROR_BUSY: + returnValue = BLE_STACK_BUSY; + break; + + case ERROR_INVALID_STATE: + case ERROR_BLEGATTS_SYS_ATTR_MISSING: + returnValue = BLE_ERROR_INVALID_STATE; + break; + + default : + ASSERT_INT( ERROR_NONE, + sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), + BLE_ERROR_PARAM_OUT_OF_RANGE ); + + /* Notifications consume application buffers. The return value can + * be used for resending notifications. */ + returnValue = BLE_STACK_BUSY; + break; + } + } + } else { + returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); + } + } else { + returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); + } + + return returnValue; +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) +{ + /* Forward the call with the default connection handle. */ + nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); + return areUpdatesEnabled(gap.getConnectionHandle(), characteristic, enabledP); +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) +{ + return areUpdatesEnabled(connectionHandle, characteristic.getValueHandle(), enabledP); +} + +ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, bool *enabledP) +{ + int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); + if (characteristicIndex == -1) { + return BLE_ERROR_INVALID_PARAM; + } + + /* Read the cccd value from the GATT server. */ + GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle; + uint16_t cccdValue; + uint16_t length = sizeof(cccdValue); + ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast(&cccdValue), &length); + if (rc != BLE_ERROR_NONE) { + return rc; + } + if (length != sizeof(cccdValue)) { + return BLE_ERROR_INVALID_STATE; + } + + /* Check for NOTFICATION or INDICATION in CCCD. */ + if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) { + *enabledP = true; + } + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Clear nRF5xGattServer's state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly +*/ +/**************************************************************************/ +ble_error_t nRF5xGattServer::reset(void) +{ + /* Clear all state that is from the parent, including private members */ + if (GattServer::reset() != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_STATE; + } + + /* Clear derived class members */ + memset(p_characteristics, 0, sizeof(p_characteristics)); + memset(p_descriptors, 0, sizeof(p_descriptors)); + memset(nrfCharacteristicHandles, 0, sizeof(ble_gatts_char_handles_t)); + memset(nrfDescriptorHandles, 0, sizeof(nrfDescriptorHandles)); + descriptorCount = 0; + + releaseAllWriteRequests(); + + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Callback handler for events getting pushed up from the SD +*/ +/**************************************************************************/ +void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt) +{ + GattAttribute::Handle_t handle_value; + GattServerEvents::gattEvent_t eventType; + const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; + + switch (p_ble_evt->header.evt_id) { + case BLE_GATTS_EVT_WRITE: { + /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ + + /* 1.) Handle CCCD changes */ + handle_value = gattsEventP->params.write.handle; + int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); + if ((characteristicIndex != -1) && + (p_characteristics[characteristicIndex]->getProperties() & + (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { + + uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ + + if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || + ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { + eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; + } else { + eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; + } + + handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); + return; + } + + /* 2.) Changes to the characteristic value will be handled with other events below */ + eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; + } + break; + + case BLE_GATTS_EVT_HVC: + /* Indication confirmation received */ + eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; + handle_value = gattsEventP->params.hvc.handle; + break; + +#if NRF_SD_BLE_API_VERSION >= 4 // This event has been renamed in API V4+ + case BLE_GATTS_EVT_HVN_TX_COMPLETE: { + handleDataSentEvent(p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count); + return; + } +#else + case BLE_EVT_TX_COMPLETE: { + handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); + return; + } +#endif + + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); + return; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + switch (gattsEventP->params.authorize_request.type) { + case BLE_GATTS_AUTHORIZE_TYPE_READ: + eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; + handle_value = gattsEventP->params.authorize_request.request.read.handle; + break; + case BLE_GATTS_AUTHORIZE_TYPE_WRITE: + eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; + handle_value = gattsEventP->params.authorize_request.request.write.handle; + break; + default: + return; + } + break; + + case BLE_EVT_USER_MEM_REQUEST: { + uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle; + + // allocate a new long request for this connection + // NOTE: we don't care about the result at this stage, + // it is not possible to cancel the operation anyway. + // If the request was not allocated then it will gracefully failled + // at subsequent stages. + allocateLongWriteRequest(conn_handle); + sd_ble_user_mem_reply(conn_handle, NULL); + return; + } + + default: + return; + } + + int characteristicIndex = resolveValueHandleToCharIndex(handle_value); + if (characteristicIndex == -1) { + // filter out the case were the request is a long one, + // and there is no attribute handle provided + uint8_t write_op = gattsEventP->params.authorize_request.request.write.op; + if (eventType != GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ || + (write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW && + write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { + return; + } + } + + /* Find index (charHandle) in the pool */ + switch (eventType) { + case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { + GattWriteCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .writeOp = */ static_cast(gattsEventP->params.write.op), + /* .offset = */ gattsEventP->params.write.offset, + /* .len = */ gattsEventP->params.write.len, + /* .data = */ gattsEventP->params.write.data + }; + handleDataWrittenEvent(&cbParams); + break; + } + case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { + uint16_t conn_handle = gattsEventP->conn_handle; + const ble_gatts_evt_write_t& input_req = gattsEventP->params.authorize_request.request.write; + const uint16_t max_size = getBiggestCharacteristicSize(); + + // this is a long write request, handle it here. + switch (input_req.op) { + case BLE_GATTS_OP_PREP_WRITE_REQ: { + // verify that the request is not outside of the possible range + if ((input_req.offset + input_req.len) > max_size) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // find the write request + long_write_request_t* req = findLongWriteRequest(conn_handle); + if (!req) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + return; + } + + // initialize the first request by setting the offset + if (req->length == 0) { + req->attr_handle = input_req.handle; + req->offset = input_req.offset; + } else { + // it should be the subsequent write + if ((req->offset + req->length) != input_req.offset) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // it is not allowed to write multiple characteristic with the same request + if (input_req.handle != req->attr_handle) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + } + + // start the copy of what is in input + memcpy(req->data + req->length, input_req.data, input_req.len); + + // update the lenght of the data written + req->length = req->length + input_req.len; + + // success, signal it to the softdevice + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS, + /* .update = */ 1, + /* .offset = */ input_req.offset, + /* .len = */ input_req.len, + /* .p_data = */ input_req.data + } + } + }; + + sd_ble_gatts_rw_authorize_reply(conn_handle, &reply); + } return; + + case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: { + releaseLongWriteRequest(conn_handle); + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); + } return; + + case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: { + long_write_request_t* req = findLongWriteRequest(conn_handle); + if (!req) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + return; + } + + GattWriteAuthCallbackParams cbParams = { + /* .connHandle = */ conn_handle, + /* .handle = */ req->attr_handle, + /* .offset = */ req->offset, + /* .len = */ req->length, + /* .data = */ req->data, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams); + + // the user code didn't provide the write authorization, + // just leave here. + if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) { + // report the status of the operation in any cases + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + // FIXME can't use ::write here, this function doesn't take the offset into account ... + ble_gatts_value_t value = { + /* .len = */ req->length, + /* .offset = */ req->offset, + /* .p_value = */ req->data + }; + uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value); + if (update_err) { + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); + releaseLongWriteRequest(conn_handle); + return; + } + + sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); + + GattWriteCallbackParams writeParams = { + /* .connHandle = */ conn_handle, + /* .handle = */ req->attr_handle, + /* .writeOp = */ static_cast(input_req.op), + /* .offset = */ req->offset, + /* .len = */ req->length, + /* .data = */ req->data, + }; + handleDataWrittenEvent(&writeParams); + releaseLongWriteRequest(conn_handle); + } return; + } + + GattWriteAuthCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, + /* .len = */ gattsEventP->params.authorize_request.request.write.len, + /* .data = */ gattsEventP->params.authorize_request.request.write.data, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, + /* .params = */ { + /* .write = */ { + /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams), + /* .update = */ 1, + /* .offset = */ cbParams.offset, + /* .len = */ cbParams.len, + /* .p_data = */ cbParams.data + } + } + }; + + if (reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) + { + reply.params.write.update = 0; + } + + sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); + + /* + * If write-authorization is enabled for a characteristic, + * AUTHORIZATION_REQ event (if replied with true) is *not* + * followed by another DATA_WRITTEN event; so we still need + * to invoke handleDataWritten(), much the same as we would + * have done if write-authorization had not been enabled. + */ + if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { + GattWriteCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .writeOp = */ static_cast(gattsEventP->params.authorize_request.request.write.op), + /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, + /* .len = */ gattsEventP->params.authorize_request.request.write.len, + /* .data = */ gattsEventP->params.authorize_request.request.write.data, + }; + handleDataWrittenEvent(&cbParams); + } + break; + } + case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { + GattReadAuthCallbackParams cbParams = { + /* .connHandle = */ gattsEventP->conn_handle, + /* .handle = */ handle_value, + /* .offset = */ gattsEventP->params.authorize_request.request.read.offset, + /* .len = */ 0, + /* .data = */ NULL, + /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member + * set to AUTH_CALLBACK_REPLY_SUCCESS if the client + * request is to proceed. */ + }; + + ble_gatts_rw_authorize_reply_params_t reply = { + /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ, + /* .params = */ { + /* .read = */ { + /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams) + } + } + }; + + if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { + if (cbParams.data != NULL) { + reply.params.read.update = 1; + reply.params.read.offset = cbParams.offset; + reply.params.read.len = cbParams.len; + reply.params.read.p_data = cbParams.data; + } + } + + sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); + break; + } + + default: + handleEvent(eventType, handle_value); + break; + } +} + +uint16_t nRF5xGattServer::getBiggestCharacteristicSize() const { + uint16_t result = 0; + for (size_t i = 0; i < characteristicCount; ++i) { + uint16_t current_size = p_characteristics[i]->getValueAttribute().getMaxLength(); + if (current_size > result) { + result = current_size; + } + } + return result; +} + +nRF5xGattServer::long_write_request_t* nRF5xGattServer::allocateLongWriteRequest(uint16_t connection_handle) { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data == NULL) { + uint16_t block_size = getBiggestCharacteristicSize(); + req.data = static_cast(malloc(block_size)); + req.offset = 0; + req.length = 0; + req.conn_handle = connection_handle; + return &req; + } + } + // if nothing has been found then return null + return NULL; +} + +bool nRF5xGattServer::releaseLongWriteRequest(uint16_t connection_handle) { + long_write_request_t* req = findLongWriteRequest(connection_handle); + if (!req) { + return false; + } + + free(req->data); + req->data = NULL; + + // the other fields are not relevant, return now + return true; +} + +nRF5xGattServer::long_write_request_t* nRF5xGattServer::findLongWriteRequest(uint16_t connection_handle) { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data != NULL && req.conn_handle == connection_handle) { + return &req; + } + } + // if nothing has been found then return null + return NULL; +} + +void nRF5xGattServer::releaseAllWriteRequests() { + for (size_t i = 0; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) { + long_write_request_t& req = long_write_requests[i]; + if (req.data != NULL) { + free(req.data); + req.data = NULL; + } + } +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.h new file mode 100644 index 0000000000..253c2d1446 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xGattServer.h @@ -0,0 +1,167 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF51822_GATT_SERVER_H__ +#define __NRF51822_GATT_SERVER_H__ + +#include + +#include "ble/blecommon.h" +#include "headers/nrf_ble.h" /* nordic ble */ +#include "ble/Gap.h" +#include "ble/GattServer.h" + +class nRF5xGattServer : public GattServer +{ +public: + /* Functions that must be implemented from GattServer */ + virtual ble_error_t addService(GattService &); + virtual ble_error_t read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP); + virtual ble_error_t write(GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t, const uint8_t[], uint16_t, bool localOnly = false); + virtual ble_error_t areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP); + virtual ble_error_t reset(void); + + /* nRF51 Functions */ + void eventCallback(void); + void hwCallback(const ble_evt_t *p_ble_evt); + + +private: + const static unsigned BLE_TOTAL_CHARACTERISTICS = NRF_SDH_BLE_TOTAL_CHARACTERISTICS; + const static unsigned BLE_TOTAL_DESCRIPTORS = NRF_SDH_BLE_TOTAL_DESCRIPTORS; + const static unsigned TOTAL_CONCURRENT_LONG_WRITE_REQUESTS = 3; + +private: + struct long_write_request_t { + // the connection handle for a long write request + uint16_t conn_handle; + + // the attribute handle for the long write request + // This implementation folow the bluetooth route + // where a write request target a single characteristic + // (see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] - 4.9.4) + uint16_t attr_handle; + + // offset of the transaction + uint16_t offset; + + // length of the data + uint16_t length; + + // current data + uint8_t* data; + }; + + +private: + /** + * resolve a value attribute to its owning characteristic. + * @param valueHandle the value handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveValueHandleToCharIndex(GattAttribute::Handle_t valueHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].value_handle == valueHandle) { + return charIndex; + } + } + + return -1; + } + + /** + * resolve a CCCD attribute handle to its owning characteristic. + * @param cccdHandle the CCCD handle to be resolved. + * @return characteristic index if a resolution is found, else -1. + */ + int resolveCCCDHandleToCharIndex(GattAttribute::Handle_t cccdHandle) const { + unsigned charIndex; + for (charIndex = 0; charIndex < characteristicCount; charIndex++) { + if (nrfCharacteristicHandles[charIndex].cccd_handle == cccdHandle) { + return charIndex; + } + } + + return -1; + } + + /** + * Return the biggest size used by a characteristic in the server + */ + uint16_t getBiggestCharacteristicSize() const; + + /** + * Allocate a new write long request. return null if no requests are available. + * @param connection_handle The connection handle to be associated with the request. + * @return the allocated request or NULL if no requests are available. + */ + long_write_request_t* allocateLongWriteRequest(uint16_t connection_handle); + + /** + * Release a long write request and free a slot for subsequent write long requests. + * @param connection_handle The connection handle associated with the request + * @return true if the request where allocated and was release, false otherwise. + */ + bool releaseLongWriteRequest(uint16_t connection_handle); + + /** + * Find a long write request from a characteristic handle + * @param connection_handle The connection handle associated with the request. + * @return a pointer to the request if found otherwise NULL. + */ + long_write_request_t* findLongWriteRequest(uint16_t connection_handle); + + /** + * Release all pending write requests. + */ + void releaseAllWriteRequests(); + + /** + * Query if updates of a characteristics are enabled for a given connection. + */ + ble_error_t areUpdatesEnabled( + Gap::Handle_t connectionHandle, + GattAttribute::Handle_t valueHandle, + bool *enabledP + ); + +private: + GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; + ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; + GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS]; + uint8_t descriptorCount; + uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS]; + long_write_request_t long_write_requests[TOTAL_CONCURRENT_LONG_WRITE_REQUESTS]; + + /* + * Allow instantiation from nRF5xn when required. + */ + friend class nRF5xn; + + nRF5xGattServer() : GattServer(), p_characteristics(), nrfCharacteristicHandles(), p_descriptors(), descriptorCount(0), nrfDescriptorHandles(), long_write_requests() { + /* empty */ + } + +private: + nRF5xGattServer(const nRF5xGattServer &); + const nRF5xGattServer& operator=(const nRF5xGattServer &); +}; + +#endif // ifndef __NRF51822_GATT_SERVER_H__ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.cpp new file mode 100644 index 0000000000..1778a102f1 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.cpp @@ -0,0 +1,1681 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "nRF5xPalGattClient.h" + +#include "ble/pal/PalGattClient.h" +#include "ble/pal/SimpleAttServerMessage.h" + +#include "headers/nrf_ble.h" +#include "headers/ble_gatt.h" +#include "headers/ble_types.h" +#include "headers/ble_err.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +namespace { + +/** + * Extract an uint16_t value from a memory location. + */ +static uint16_t bytes_to_u16(const void* b) +{ + uint16_t res; + memcpy(&res, b, sizeof(uint16_t)); + return res; +} + +/** + * Push an uint16_t value into a byte stream. + * + * @note it is incremented. + */ +static void u16_to_stream(uint8_t *&it, uint16_t v) +{ + memcpy(it, &v, sizeof(uint16_t)); + it += 2; +} + +/** + * Convert a pal::attribute_handle_range_t into a ble_gattc_handle_range_t. + */ +static ble_gattc_handle_range_t to_nordic_handle_range(const attribute_handle_range_t &range) +{ + ble_gattc_handle_range_t result = { + range.begin, + range.end + }; + return result; +} + +/** + * Convert a ble_gattc_handle_range_t into a pal::attribute_handle_range_t. + */ +static attribute_handle_range_t to_ble_handle_range(const ble_gattc_handle_range_t &range) +{ + attribute_handle_range_t result = { + range.start_handle, + range.end_handle + }; + return result; +} + +/** + * Convert an error from the softdevice into a ble_error_t + */ +static ble_error_t convert_sd_error(uint32_t err) +{ + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_PARAM: + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_ADDR: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_DATA_SIZE: + return BLE_ERROR_PARAM_OUT_OF_RANGE; +#if (NRF_SD_BLE_API_VERSION <= 3) // Removed in Softdevice v4.0 + case BLE_ERROR_NO_TX_PACKETS: + return BLE_ERROR_NO_MEM; +#endif + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +/** + * Convert a UUID into a ble_uuid_t . + * If the UUID is a 128 bit one then it is registered into the softdevice. + */ +static ble_error_t to_nordic_uuid(const UUID &uuid, ble_uuid_t &nordic_uuid) +{ + if (uuid.getLen() == UUID::LENGTH_OF_LONG_UUID) { + // first try to get the long UUID in the table of UUIDs + uint32_t err = sd_ble_uuid_decode( + uuid.getLen(), + uuid.getBaseUUID(), + &nordic_uuid + ); + + // UUID found and filed, return. + if (err == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } + + ble_uuid128_t uuid128; + memcpy(uuid128.uuid128, uuid.getBaseUUID(), sizeof(uuid128.uuid128)); + + // UUID not found, try to register it + err = sd_ble_uuid_vs_add(&uuid128, &nordic_uuid.type); + if (err == NRF_SUCCESS) { + nordic_uuid.uuid = bytes_to_u16(uuid.getBaseUUID() + 12); + } + + return convert_sd_error(err); + } else { + nordic_uuid.type = BLE_UUID_TYPE_BLE; + nordic_uuid.uuid = uuid.getShortUUID(); + return BLE_ERROR_NONE; + } +} + +/** + * Convert an attribute error code from the softdevice into a valid ATT error. + */ +static uint8_t convert_sd_att_error_code(uint16_t err) +{ + if (err < 0x101 || err > 0x1FF) { + return AttErrorResponse::UNLIKELY_ERROR; + } else { + return err & 0xFF; + } +} + +static const size_t long_uuid_length = 16; +static const size_t read_by_group_type_long_uuid_index = 4; +static const size_t characteristic_declaration_length = 1 + 2 + 16; + +} // end of anonymous namespace + +nRF5xGattClient::nRF5xGattClient() : + ble::pal::GattClient(), + _procedures() +{ +} + +nRF5xGattClient::~nRF5xGattClient() +{ + terminate(); +} + +ble_error_t nRF5xGattClient::initialize() +{ + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGattClient::exchange_mtu(connection_handle_t connection) +{ + // FIXME: implement when SD 140 5.x.x is present + // (see sd_ble_gatts_exchange_mtu_reply) + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xGattClient::get_mtu_size( + connection_handle_t connection_handle, uint16_t& mtu_size +) { +#if (NRF_SD_BLE_API_VERSION >= 3) + // FIXME: implement when MTU size can be configured; the mtu size must be + // stored locally when BLE_GATTC_EVT_EXCHANGE_MTU_RSP has been received + mtu_size = BLE_GATT_MTU_SIZE_DEFAULT; +#else + mtu_size = GATT_RX_MTU; +#endif + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGattClient::discover_primary_service( + connection_handle_t connection, + attribute_handle_t discovery_range_begining +) { + return launch_procedure( + connection, discovery_range_begining + ); +} + +ble_error_t nRF5xGattClient::discover_primary_service_by_service_uuid( + connection_handle_t connection_handle, + attribute_handle_t discovery_range_beginning, + const UUID& uuid +) { + return launch_procedure( + connection_handle, discovery_range_beginning, uuid + ); +} + +ble_error_t nRF5xGattClient::find_included_service( + connection_handle_t connection_handle, + attribute_handle_range_t service_range +) { + return launch_procedure( + connection_handle, service_range + ); +} + +ble_error_t nRF5xGattClient::discover_characteristics_of_a_service( + connection_handle_t connection_handle, + attribute_handle_range_t discovery_range +) { + return launch_procedure( + connection_handle, discovery_range + ); +} + +ble_error_t nRF5xGattClient::discover_characteristics_descriptors( + connection_handle_t connection_handle, + attribute_handle_range_t descriptors_discovery_range +) { + return launch_procedure( + connection_handle, descriptors_discovery_range + ); +} + +ble_error_t nRF5xGattClient::read_attribute_value( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle +) { + return launch_procedure( + connection_handle, attribute_handle + ); +} + +ble_error_t nRF5xGattClient::read_using_characteristic_uuid( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& uuid +) { + return launch_procedure( + connection_handle, read_range, uuid + ); +} + +ble_error_t nRF5xGattClient::read_attribute_blob( + connection_handle_t connection, + attribute_handle_t attribute_handle, + uint16_t offset +) { + return launch_procedure( + connection, attribute_handle, offset + ); +} + +ble_error_t nRF5xGattClient::read_multiple_characteristic_values( + connection_handle_t connection, + const ArrayView& characteristic_handles +) { + return launch_procedure( + connection, characteristic_handles + ); +} + +ble_error_t nRF5xGattClient::write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value +) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_WRITE_CMD, + /* exec flags */ 0, + characteristic_value_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); +} + +ble_error_t nRF5xGattClient::signed_write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value +) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_SIGN_WRITE_CMD, + /* exec flags */ 0, + characteristic_value_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); +} + +ble_error_t nRF5xGattClient::write_attribute( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView& value +) { + return launch_procedure( + connection_handle, attribute_handle, value + ); +} + +ble_error_t nRF5xGattClient::queue_prepare_write( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset +) { + return launch_procedure( + connection_handle, characteristic_value_handle, value, offset + ); +} + +ble_error_t nRF5xGattClient::execute_write_queue( + connection_handle_t connection_handle, + bool execute +) { + return launch_procedure( + connection_handle, execute + ); +} + + +/** + * Base definition of a GATT procedure. + * + * Nordic implementation of discovery procedures requires more than a single + * request to the BLE peer when it involves 128bit UUID. As a consequence it is + * necessary to reserve the connection slot, maintain state between requests and + * interpret responses depending on the context. + * + * The concept of procedures for Gatt operations formalize the process. A + * procedure lifecycle is defined by three function: + * - start: Launch of the procedure. It initiate the first request to send to + * the peer. It must be implemented by Procedure derived classes. + * - handle: Event handler that process ble events comming from the softdevice. + * This function drive the procedure flow and must be implemented by + * Procedure derived classes. + * - terminate: end the procedure and forward the result to the GattClient + * event handle. + * + * @note Commands such as write without response or signed write without response + * are not procedures. + */ +struct nRF5xGattClient::GattProcedure { + /** + * Initialize the procedure. + * + * @param connection Handle representing the connection used by the procedure. + * @param op Opcode of the procedure. + */ + GattProcedure(connection_handle_t connection, AttributeOpcode op) : + connection_handle(connection), procedure_opcode(op) { } + + /** + * To overide in child if necessary. + */ + virtual ~GattProcedure() { } + + /** + * Handle events targeting the connection. + */ + virtual void handle(const ble_evt_t &evt) = 0; + + /** + * Terminate the execution of the procedure and forward msg to the handler + * registered in the client. + * + * @note delete this. + */ + void terminate(const AttServerMessage &msg) + { + get_client().remove_procedure(this); + get_client().on_server_event(connection_handle, msg); + delete this; + } + + /** + * Terminate the procedure with an unlikely error. + */ + void abort() + { + terminate(AttErrorResponse( + procedure_opcode, AttErrorResponse::UNLIKELY_ERROR + )); + } + + const connection_handle_t connection_handle; + const AttributeOpcode procedure_opcode; +}; + + +/** + * A regular procedure is a procedure that follows Gatt specification. + * + * It initiate a single request to the peer and excepts a single response. This + * kind of procedure doesn't requires extra processing step. + * + * Given that such procedure expects a single event type from the soft device, + * error handling can be generalized. + */ +struct nRF5xGattClient::RegularGattProcedure : GattProcedure { + + /** + * Construct a RegularGattProcedure. + * + * @param connection Handle of the connection used by the procedure. + * @param op Attribute operation code + * @param event_type Type of event expected by the stack. + */ + RegularGattProcedure( + connection_handle_t connection, AttributeOpcode op, BLE_GATTC_EVTS event_type + ) : GattProcedure(connection, op), _event_type(event_type) { } + + /** + * Handle events from the BLE stack; do not overide in child. + * + * @note This function offload error handling from user error handler. If + * the event in input match the expected event type and does not carry error + * then it is forwarded to the do_handle function. Otherwise the procedure + * is terminated and an error is forwarded to the client event handler. + */ + virtual void handle(const ble_evt_t &evt) + { + if (evt.header.evt_id == _event_type) { + const ble_gattc_evt_t &gattc_evt = evt.evt.gattc_evt; + if (gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + procedure_opcode, + gattc_evt.error_handle, + convert_sd_att_error_code(gattc_evt.gatt_status) + )); + return; + } else { + do_handle(gattc_evt); + } + } else { + abort(); + } + } + + /** + * Handle gatt event received from the stack. + * + * @note The event passed in parameter is valid. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) = 0; + +protected: + BLE_GATTC_EVTS _event_type; +}; + + +/** + * Procedure that handle discovery of primary services. + * + * The softdevice doesn't forward to user UUID of services that are 128 bit long. + * In such case a read request is issued for each service attribute handle + * to extract that information. + */ +struct nRF5xGattClient::DiscoverPrimaryServiceProcedure : GattProcedure { + + typedef ArrayView services_array_t; + + DiscoverPrimaryServiceProcedure(connection_handle_t connection) : + GattProcedure(connection, AttributeOpcode::READ_BY_GROUP_TYPE_REQUEST), + response(NULL), count(0), idx(0) { } + + virtual ~DiscoverPrimaryServiceProcedure() + { + if (response) { + delete[] response; + } + } + + ble_error_t start(attribute_handle_t begining) + { + uint32_t err = sd_ble_gattc_primary_services_discover( + connection_handle, begining, /* p_srvc_uuid */ NULL + ); + return convert_sd_error(err); + } + + /** + * Dispatch responses either to service discovery handler or attribute read + * handler. + */ + virtual void handle(const ble_evt_t &evt) + { + switch (evt.header.evt_id) { + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + handle_service_discovered(evt.evt.gattc_evt); + return; + case BLE_GATTC_EVT_READ_RSP: + handle_uuid_read(evt.evt.gattc_evt); + return; + default: + abort(); + return; + } + } + + /** + * Dispatch service discovery response either to the short UUID handler or + * the long UUID handler. + */ + void handle_service_discovered(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_BY_GROUP_TYPE_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + services_array_t services( + evt.params.prim_srvc_disc_rsp.services, + evt.params.prim_srvc_disc_rsp.count + ); + + // note 128 bit and 16 bits UUID cannot be mixed up + if (services[0].uuid.type == BLE_UUID_TYPE_BLE) { + handle_16bit_services_discovered(services); + } else { + handle_128bit_services_discovered(services); + } + } + + /** + * Handle discovery of services with a 16 bit UUID. + * + * The procedure ends here. + */ + void handle_16bit_services_discovered(const services_array_t &services) + { + /** + * Custom implementation of AttReadByGroupTypeResponse that can be used + * with data returned by the nordic stack. + */ + struct CustomAttReadByGroupTypeResponse : AttReadByGroupTypeResponse { + CustomAttReadByGroupTypeResponse(const services_array_t &s) : + AttReadByGroupTypeResponse(), services(s) { + } + + virtual size_t size() const + { + return services.size(); + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + to_ble_handle_range(services[i].handle_range), + make_const_ArrayView( + reinterpret_cast(&services[i].uuid.uuid), + sizeof(uint16_t) + ) + }; + return result; + } + + const services_array_t &services; + }; + + terminate(CustomAttReadByGroupTypeResponse(services)); + } + + /** + * Handle discovery of services with a 128 UUID. + * + * Handle of the services discovered will be stored locally then the + * procedure sequentially initiate a read request of each of these attribute + * handle to acquire the value of the UUID of the service. + * + * The procedure ends once all the informations initially sent by the peer + * has been reconstructed and forwarded to the registered client handler. + */ + void handle_128bit_services_discovered(const services_array_t &services) + { + response = new(std::nothrow) packed_discovery_response_t[services.size()]; + if (!response) { + abort(); + return; + } + + count = services.size(); + idx = 0; + for (size_t i = 0; i < count; ++i) { + uint8_t *it = &response[i][0]; + u16_to_stream(it, services[i].handle_range.start_handle); + u16_to_stream(it, services[i].handle_range.end_handle); + } + + read_service_uuid(); + } + + /** + * Initiate the read request of the next service attribute handle. + */ + void read_service_uuid(void) + { + // note: use read multiple once different mtu size are supported ? + uint16_t attribute_handle = bytes_to_u16(&response[idx][0]); + + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + if (err) { + abort(); + } + } + + /** + * Handle reception of a service (long) UUID. + */ + void handle_uuid_read(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + const ble_gattc_evt_read_rsp_t &rsp = evt.params.read_rsp; + + uint16_t expected_handle = bytes_to_u16(&response[idx][0]); + + if (rsp.handle != expected_handle || rsp.offset != 0 || + rsp.len != long_uuid_length) { + abort(); + return; + } + + memcpy(&response[idx][read_by_group_type_long_uuid_index], rsp.data, rsp.len); + + ++idx; + + if (idx == count) { + terminate(SimpleAttReadByGroupTypeResponse( + sizeof(packed_discovery_response_t), + make_const_ArrayView( + reinterpret_cast(response), + count * sizeof(packed_discovery_response_t) + )) + ); + } else { + read_service_uuid(); + } + } + + // Hold read by group type response of services with 128 bit UUID. + // The response is composed of the service attribute handle (2 bytes), the + // end group handle (2 bytes) and the service UUID (16 bytes). + typedef uint8_t packed_discovery_response_t[20]; + + packed_discovery_response_t* response; + uint16_t count; + uint16_t idx; +}; + + +/** + * Procedure that manage Discover Primary Service by Service UUID transactions. + * + * @note Even if the softdevice doesn't forward the complete content of the peer + * response it is possible to reconstruct it by keeping a copy of the UUID to + * find. + */ +struct nRF5xGattClient::DiscoverPrimaryServiceByUUIDProcedure : RegularGattProcedure { + + typedef ArrayView services_array_t; + + DiscoverPrimaryServiceByUUIDProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::FIND_BY_TYPE_VALUE_REQUEST, + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP + ), + _service_uuid() { } + + ble_error_t start(attribute_handle_t begining, const UUID &uuid) + { + ble_uuid_t nordic_uuid; + ble_error_t ble_err = to_nordic_uuid(uuid, nordic_uuid); + if (ble_err) { + return ble_err; + } + + uint32_t err = sd_ble_gattc_primary_services_discover( + connection_handle, begining, &nordic_uuid + ); + if (!err) { + _service_uuid = uuid; + } + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + services_array_t services( + evt.params.prim_srvc_disc_rsp.services, + evt.params.prim_srvc_disc_rsp.count + ); + + /** + * Implementation of AttReadByGroupTypeResponse that addapt Nordic data + * structure. + */ + struct CustomAttReadByGroupTypeResponse : AttReadByGroupTypeResponse { + CustomAttReadByGroupTypeResponse(const services_array_t &s, const UUID &u) : + AttReadByGroupTypeResponse(), services(s), uuid(u) { + } + + virtual size_t size() const + { + return services.size(); + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + to_ble_handle_range(services[i].handle_range), + make_ArrayView(uuid.getBaseUUID(), uuid.getLen()) + }; + return result; + } + + const services_array_t &services; + const UUID &uuid; + }; + + terminate(CustomAttReadByGroupTypeResponse(services, _service_uuid)); + } + + UUID _service_uuid; +}; + + +/** + * Procedure that manage Find Included Services transactions. + */ +struct nRF5xGattClient::FindIncludedServicesProcedure : RegularGattProcedure { + + typedef ArrayView services_array_t; + + FindIncludedServicesProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_BY_TYPE_REQUEST, + BLE_GATTC_EVT_REL_DISC_RSP + ) { } + + ble_error_t start(attribute_handle_range_t service_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(service_range); + uint32_t err = sd_ble_gattc_relationships_discover( + connection_handle, &range + ); + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + // recompose the message into a raw att read by type response. + const ble_gattc_evt_rel_disc_rsp_t &resp = evt.params.rel_disc_rsp; + + bool contain_short_uuid = + (resp.includes[0].included_srvc.uuid.type == BLE_UUID_TYPE_BLE); + + uint8_t element_size = 6; + if (contain_short_uuid) { + element_size += 2; + } + + // It would be more efficient to use an API like alloca but it is + // unavailable and unsafe. Another alternative would be to have a fixed + // size stack buffer since the size of the MTU is fixed however once new + // softdevices lands could would have to be rewritten because they support + // variable MTU size. + size_t buffer_size = element_size * resp.count; + uint8_t* buffer = new(std::nothrow) uint8_t[buffer_size]; + if (!buffer) { + abort(); + return; + } + + uint8_t *it = buffer; + for(size_t i = 0; i < resp.count; ++i) { + u16_to_stream(it, resp.includes[i].handle); + u16_to_stream(it, resp.includes[i].included_srvc.handle_range.start_handle); + u16_to_stream(it, resp.includes[i].included_srvc.handle_range.end_handle); + if (contain_short_uuid) { + u16_to_stream(it, resp.includes[i].included_srvc.uuid.uuid); + } + } + + terminate(SimpleAttReadByTypeResponse( + element_size, + make_const_ArrayView(buffer, buffer_size) + )); + + delete[] buffer; + } + + UUID _service_uuid; +}; + + +/** + * Procedure that handle Discover All Characteristics of a Service transactions. + * + * The softdevice doesn't forward to user UUID of services that are 128 bit long. + * In such case a read request is issued for each attribute handle of + * characteristics that exposes a long UUID. + */ +struct nRF5xGattClient::DiscoverCharacteristicsProcedure : GattProcedure { + /** + * Data structure returned by the function flatten_response. + */ + struct read_by_type_response_t { + uint16_t count; + uint16_t element_size; + uint8_t* buffer; + }; + + DiscoverCharacteristicsProcedure(connection_handle_t connection) : + GattProcedure(connection, AttributeOpcode::READ_BY_TYPE_REQUEST), + _response(), _idx(0) { } + + virtual ~DiscoverCharacteristicsProcedure() + { + if (_response.buffer) { + delete[] _response.buffer; + } + } + + ble_error_t start(attribute_handle_range_t discovery_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(discovery_range); + uint32_t err = sd_ble_gattc_characteristics_discover( + connection_handle, + &range + ); + + return convert_sd_error(err); + } + + /** + * Dispatch ble events to the appropriate handler: + * - handle_characteristic_discovered: For a discovery response. + * - handle_uuid_read: For a read response. + */ + virtual void handle(const ble_evt_t &evt) + { + switch (evt.header.evt_id) { + case BLE_GATTC_EVT_CHAR_DISC_RSP: + handle_characteristic_discovered(evt.evt.gattc_evt); + return; + case BLE_GATTC_EVT_READ_RSP: + handle_uuid_read(evt.evt.gattc_evt); + return; + default: + abort(); + return; + } + } + + void handle_characteristic_discovered(const ble_gattc_evt_t &evt) + { + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_BY_TYPE_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + // layout the data structure into a flat byte array. + _response = flatten_response(evt.params.char_disc_rsp); + if (!_response.buffer) { + abort(); + return; + } + + // If element size is equal to 7 then the characteristic discovered + // have 16 bit UUID. It is not necessary to read their characteristic + // declaration attribute. + if (_response.element_size == 7) { + forward_response_and_terminate(); + } else { + // 128 bit UUID. + // read sequentially each characteristic declaration attribute + // discovered. + _idx = 0; + read_characteristic_uuid(); + } + } + + /** + * Initiate read of the next characteristic declaration attribute. + */ + void read_characteristic_uuid(void) + { + // note: use read multiple once different mtu size are supported ? + uint16_t attribute_handle = + bytes_to_u16(&_response.buffer[_idx * _response.element_size]); + + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + if (err) { + abort(); + } + } + + /** + * Handle read response of a characteristic declaration attribute. + * It add the data in the response then initiate the read of the next + * attribute or terminate the procedure if all characteristic declaration + * attributes have been read. + */ + void handle_uuid_read(const ble_gattc_evt_t &evt) + { + // should never happen + if (!_response.buffer) { + abort(); + return; + } + + if (evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { + terminate(AttErrorResponse( + AttributeOpcode::READ_REQUEST, + convert_sd_att_error_code(evt.gatt_status) + )); + return; + } + + const ble_gattc_evt_read_rsp_t &rsp = evt.params.read_rsp; + uint8_t* current_element = &_response.buffer[_idx * _response.element_size]; + uint16_t expected_handle = bytes_to_u16(current_element); + + if (rsp.handle != expected_handle || rsp.offset != 0 || + rsp.len != characteristic_declaration_length) { + abort(); + return; + } + + // note: elements are the pair characteristic declaration handle followed + // by the attribute value. + memcpy(current_element + 2, rsp.data, rsp.len); + + ++_idx; + + if (_idx == _response.count) { + forward_response_and_terminate(); + } else { + read_characteristic_uuid(); + } + } + + /** + * Terminate the procedure by forwarding the AttReadByTypeResponse built. + */ + void forward_response_and_terminate() { + terminate(SimpleAttReadByTypeResponse( + _response.element_size, + make_const_ArrayView( + _response.buffer, + _response.element_size * _response.count + ) + )); + } + + /** + * Convert a ble_gattc_evt_char_disc_rsp_t into a raw response. + * + * If UUIDs present are 16 bits long then the output contain the whole + * response. Otherwise only the handle declaration of each characteristic + * discovered is present and properties, handle value and UUID are populated + * by reading the attribute handle. + */ + static read_by_type_response_t flatten_response(const ble_gattc_evt_char_disc_rsp_t& resp) + { + read_by_type_response_t result = { resp.count, 0 }; + + bool short_uuid = (resp.chars[0].uuid.type == BLE_UUID_TYPE_BLE); + + // att handle + prop + value handle + uuid size + result.element_size = 5 + (short_uuid ? 2 : 16) ; + + size_t buffer_size = resp.count * result.element_size; + result.buffer = new(std::nothrow) uint8_t[buffer_size]; + if(!result.buffer) { + return result; + } + + uint8_t *it = result.buffer; + for(size_t i = 0; i < resp.count; ++i) { + u16_to_stream(it, resp.chars[i].handle_decl); + if (short_uuid) { + *it++ = get_properties(resp.chars[i]); + u16_to_stream(it, resp.chars[i].handle_value); + u16_to_stream(it, resp.chars[i].uuid.uuid); + } else { + // leave the characteristic value declaration empty; it will be + // fullfiled by a read of the attribute. + it += (1 + 2 + 16); + } + } + + return result; + } + + /** + * Compute characteristic properties from ble_gattc_char_t. + */ + static uint8_t get_properties(const ble_gattc_char_t& char_desc) + { + return + (char_desc.char_props.broadcast << 0) | + (char_desc.char_props.read << 1) | + (char_desc.char_props.write_wo_resp << 2) | + (char_desc.char_props.write << 3) | + (char_desc.char_props.notify << 4) | + (char_desc.char_props.indicate << 5) | + (char_desc.char_props.auth_signed_wr << 6) | + (char_desc.char_ext_props << 7); + } + + read_by_type_response_t _response; + uint16_t _idx; +}; + +/** + * Procedure that handle discovery of characteristic descriptors. + */ +struct nRF5xGattClient::DiscoverDescriptorsProcedure : RegularGattProcedure { + DiscoverDescriptorsProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::FIND_INFORMATION_REQUEST, + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP + ) { + } + + ble_error_t start(attribute_handle_range_t discovery_range) + { + ble_gattc_handle_range_t range = to_nordic_handle_range(discovery_range); + uint32_t err = sd_ble_gattc_attr_info_discover( + connection_handle, + &range + ); + + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + /** + * Adapt ble_gattc_evt_attr_info_disc_rsp_t into + * pal::AttFindInformationResponse + */ + struct CustomFindInformationResponse : AttFindInformationResponse { + CustomFindInformationResponse(const ble_gattc_evt_attr_info_disc_rsp_t &resp) : + AttFindInformationResponse(), response(resp) {} + + virtual size_t size() const + { + return response.count; + } + +#if (NRF_SD_BLE_API_VERSION < 3) + virtual information_data_t operator[](size_t i) const + { + information_data_t result = { + response.attr_info[i].handle + }; + + if (response.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT) { + result.uuid = UUID(response.attr_info[i].info.uuid16.uuid); + } else { + result.uuid = UUID( + response.attr_info[i].info.uuid128.uuid128, + UUID::LSB + ); + } + + return result; + } +#else + virtual information_data_t operator[](size_t i) const + { + if (response.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT) { + information_data_t result = { + response.info.attr_info16[i].handle, + UUID(response.info.attr_info16[i].uuid.uuid) + }; + + return result; + } else { + information_data_t result = { + response.info.attr_info128[i].handle, + UUID( + response.info.attr_info128[i].uuid.uuid128, + UUID::LSB + ) + }; + + return result; + } + } + + +#endif + + + const ble_gattc_evt_attr_info_disc_rsp_t &response; + }; + + terminate(CustomFindInformationResponse(evt.params.attr_info_disc_rsp)); + } +}; + + +/** + * Procedure that handle read of attribute handles. + */ +struct nRF5xGattClient::ReadAttributeProcedure : RegularGattProcedure { + ReadAttributeProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::READ_REQUEST, BLE_GATTC_EVT_READ_RSP + ) { } + + ble_error_t start(attribute_handle_t attribute_handle) + { + uint32_t err = sd_ble_gattc_read(connection_handle, attribute_handle, 0); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_read_rsp_t& rsp = evt.params.read_rsp; + if (rsp.offset != 0 ) { + abort(); + return; + } + + terminate(AttReadResponse(make_const_ArrayView(rsp.data, rsp.len))); + } +}; + +/** + * Procedure that handle read of characteristic using characteristic UUID. + */ +struct nRF5xGattClient::ReadUsingCharacteristicUUIDProcedure : RegularGattProcedure { + ReadUsingCharacteristicUUIDProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_BY_TYPE_REQUEST, + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP + ) { } + + ble_error_t start(attribute_handle_range_t read_range, const UUID& uuid) + { + ble_uuid_t nordic_uuid = { 0 }; + ble_error_t ble_err = to_nordic_uuid(uuid, nordic_uuid); + if (ble_err) { + return ble_err; + } + + ble_gattc_handle_range_t range = { + read_range.begin, + read_range.end + }; + + uint32_t err = sd_ble_gattc_char_value_by_uuid_read( + connection_handle, + &nordic_uuid, + &range + ); + return convert_sd_error(err); + } + +#if (NRF_SD_BLE_API_VERSION >= 3) + /** + * Adapt ble_gattc_evt_char_val_by_uuid_read_rsp_t into AttReadByTypeResponse. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_char_val_by_uuid_read_rsp_t &rsp = + evt.params.char_val_by_uuid_read_rsp; + + uint8_t element_size = sizeof(uint16_t) + rsp.value_len; + + terminate(SimpleAttReadByTypeResponse( + element_size, + make_const_ArrayView( + rsp.handle_value, + rsp.count * element_size + ) + )); + } + +#else + /** + * Adapt ble_gattc_evt_char_val_by_uuid_read_rsp_t into AttReadByTypeResponse. + */ + virtual void do_handle(const ble_gattc_evt_t &evt) + { + struct CustomReadByTypeResponse : AttReadByTypeResponse { + CustomReadByTypeResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t& rsp) : + AttReadByTypeResponse(), response(rsp) { } + + virtual size_t size() const + { + return response.count; + } + + virtual attribute_data_t operator[](size_t i) const + { + attribute_data_t result = { + response.handle_value[i].handle, + make_const_ArrayView( + response.handle_value[i].p_value, + response.value_len + ) + }; + return result; + } + + const ble_gattc_evt_char_val_by_uuid_read_rsp_t& response; + } + + terminate(CustomReadByTypeResponse(evt.params.char_val_by_uuid_read_rsp)); + } +#endif +}; + +/** + * Procedure that handles read blob transactions. + */ +struct nRF5xGattClient::ReadAttributeBlobProcedure : RegularGattProcedure { + ReadAttributeBlobProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::READ_BLOB_REQUEST, BLE_GATTC_EVT_READ_RSP + ) { } + + ble_error_t start(attribute_handle_t attribute_handle, uint16_t offset) + { + uint32_t err = sd_ble_gattc_read( + connection_handle, attribute_handle, offset + ); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttReadBlobResponse(make_const_ArrayView( + evt.params.read_rsp.data, + evt.params.read_rsp.len + ))); + } +}; + +/** + * Procedure that handles Read Multiple Characteristic Values transactions. + */ +struct nRF5xGattClient::ReadMultipleCharacteristicsProcedure : RegularGattProcedure { + ReadMultipleCharacteristicsProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::READ_MULTIPLE_REQUEST, + BLE_GATTC_EVT_CHAR_VALS_READ_RSP + ) { } + + ble_error_t start(const ArrayView& characteristic_handles) + { + uint32_t err = sd_ble_gattc_char_values_read( + connection_handle, + characteristic_handles.data(), + characteristic_handles.size() + ); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttReadMultipleResponse(make_const_ArrayView( + evt.params.char_vals_read_rsp.values, + evt.params.char_vals_read_rsp.len + ))); + } +}; + +/** + * Procedure that handles Write transactions. + */ +struct nRF5xGattClient::WriteAttributeProcedure : RegularGattProcedure { + WriteAttributeProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, AttributeOpcode::WRITE_REQUEST, BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start( + attribute_handle_t attribute_handle, const ArrayView& value + ) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_WRITE_REQ, + /* exec flags */ 0, + attribute_handle, + /* offset */ 0, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + terminate(AttWriteResponse()); + } +}; + +/** + * Procedure that handles Prepare Write transactions. + */ +struct nRF5xGattClient::QueuePrepareWriteProcedure : RegularGattProcedure { + QueuePrepareWriteProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::PREPARE_WRITE_REQUEST, + BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start( + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset + ) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_PREP_WRITE_REQ, + /* exec flags */ 0, + characteristic_value_handle, + offset, + static_cast(value.size()), + const_cast(value.data()) + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_write_rsp_t &response = evt.params.write_rsp; + + if (response.write_op != BLE_GATT_OP_PREP_WRITE_REQ) { + abort(); + return; + } + + terminate(AttPrepareWriteResponse( + response.handle, + response.offset, + make_const_ArrayView(response.data, response.len) + )); + } +}; + +/** + * Procedure that handles Execute Write transactions. + */ +struct nRF5xGattClient::ExecuteWriteQueueProcedure : RegularGattProcedure { + ExecuteWriteQueueProcedure(connection_handle_t connection) : + RegularGattProcedure( + connection, + AttributeOpcode::EXECUTE_WRITE_REQUEST, + BLE_GATTC_EVT_WRITE_RSP + ) { } + + ble_error_t start(bool execute) { + ble_gattc_write_params_t write_params = { + BLE_GATT_OP_EXEC_WRITE_REQ, + static_cast( + execute ? + BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL : + BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE + ), + /* attribute handle */ 0, + /* value offset */ 0, + /* buffer size*/ 0, + /* buffer data */ NULL + }; + + uint32_t err = sd_ble_gattc_write(connection_handle, &write_params); + return convert_sd_error(err); + } + + virtual void do_handle(const ble_gattc_evt_t &evt) + { + const ble_gattc_evt_write_rsp_t &response = evt.params.write_rsp; + if (response.write_op != BLE_GATT_OP_EXEC_WRITE_REQ) { + abort(); + return; + } + + terminate(AttExecuteWriteResponse()); + } +}; + +// NOTE: position after declaration of GattProcedure on purpose. +ble_error_t nRF5xGattClient::terminate() +{ + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i]) { + _procedures[i]->abort(); + _procedures[i] = NULL; + } + } + + return BLE_ERROR_NONE; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, const A0& a0 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, const A0& a0, const A1& a1 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1, a2); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +template +ble_error_t nRF5xGattClient::launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2, const A3& a3 +) { + ProcType* p = new(std::nothrow) ProcType(connection); + if (!p) { + return BLE_ERROR_NO_MEM; + } + + if (!register_procedure(p)) { + delete p; + return BLE_ERROR_INVALID_STATE; + } + + ble_error_t err = p->start(a0, a1, a2, a3); + if (err) { + remove_procedure(p); + delete p; + } + + return err; +} + +nRF5xGattClient::GattProcedure* nRF5xGattClient::get_procedure( + connection_handle_t connection +) const { + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i] && _procedures[i]->connection_handle == connection) { + return _procedures[i]; + } + } + return NULL; +} + +bool nRF5xGattClient::register_procedure(GattProcedure *p) +{ + if (get_procedure(p->connection_handle)) { + return false; + } + + for (size_t i = 0; i < max_procedures_count; ++i) { + if (!_procedures[i]) { + _procedures[i] = p; + return true; + } + } + + return false; +} + +bool nRF5xGattClient::remove_procedure(nRF5xGattClient::GattProcedure* p) +{ + for (size_t i = 0; i < max_procedures_count; ++i) { + if (_procedures[i] == p) { + _procedures[i] = NULL; + return true; + } + } + + return false; +} + +// singleton of the ARM Cordio client +nRF5xGattClient& nRF5xGattClient::get_client() +{ + static nRF5xGattClient _client; + return _client; +} + +void nRF5xGattClient::handle_events(const ble_evt_t *evt) { + switch (evt->header.evt_id) { + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + case BLE_GATTC_EVT_REL_DISC_RSP: + case BLE_GATTC_EVT_CHAR_DISC_RSP: + case BLE_GATTC_EVT_DESC_DISC_RSP: + case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP: + case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP: + case BLE_GATTC_EVT_READ_RSP: + case BLE_GATTC_EVT_CHAR_VALS_READ_RSP: + case BLE_GATTC_EVT_WRITE_RSP: + get_client().handle_procedure_event(*evt); + break; + case BLE_GATTC_EVT_HVX: + get_client().handle_hvx_event(*evt); + break; + case BLE_GATTC_EVT_TIMEOUT: + get_client().handle_timeout_event(*evt); + break; + } +} + +void nRF5xGattClient::handle_procedure_event(const ble_evt_t &evt) +{ + GattProcedure* p = get_procedure(evt.evt.gattc_evt.conn_handle); + if (p) { + p->handle(evt); + } +} + +void nRF5xGattClient::handle_hvx_event(const ble_evt_t &evt) +{ + connection_handle_t connection = evt.evt.gattc_evt.conn_handle; + const ble_gattc_evt_hvx_t &hvx_evt = evt.evt.gattc_evt.params.hvx; + + switch (hvx_evt.type) { + case BLE_GATT_HVX_NOTIFICATION: + on_server_event( + connection, + AttHandleValueNotification( + hvx_evt.handle, + make_const_ArrayView(hvx_evt.data, hvx_evt.len) + ) + ); + return; + case BLE_GATT_HVX_INDICATION: + // send confirmation first then process the event + sd_ble_gattc_hv_confirm(connection, hvx_evt.handle); + on_server_event( + connection, + AttHandleValueIndication( + hvx_evt.handle, + make_const_ArrayView(hvx_evt.data, hvx_evt.len) + ) + ); + return; + default: + return; + } +} + +void nRF5xGattClient::handle_timeout_event(const ble_evt_t &evt) +{ + connection_handle_t connection = evt.evt.gattc_evt.conn_handle; + GattProcedure* p = get_procedure(connection); + if (p) { + p->abort(); + } + + on_transaction_timeout(connection); +} + +void nRF5xGattClient::handle_connection_termination(connection_handle_t connection) +{ + GattProcedure* p = get_client().get_procedure(connection); + if (p) { + p->abort(); + } +} + +} // nordic +} // vendor +} // pal +} // ble + + + + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.h new file mode 100644 index 0000000000..6c298aa3e3 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalGattClient.h @@ -0,0 +1,257 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLE_NORDIC_PAL_GATT_CLIENT_H_ +#define BLE_NORDIC_PAL_GATT_CLIENT_H_ + +#include "ble/pal/PalGattClient.h" +#include "ble/blecommon.h" +#include "ble/UUID.h" + +#include "headers/nrf_ble.h" +#include "headers/ble_gatt.h" +#include "headers/ble_types.h" +#include "btle.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +/** + * Implementation of pal::GattClient for the Nordic stack. + */ +class nRF5xGattClient : public ble::pal::GattClient { + +public: + nRF5xGattClient(); + + virtual ~nRF5xGattClient(); + + /** + * see pal::GattClient::initialize . + */ + virtual ble_error_t initialize(); + + /** + * see pal::GattClient::terminate . + */ + virtual ble_error_t terminate(); + + /** + * see pal::GattClient::exchange_mtu . + */ + virtual ble_error_t exchange_mtu(connection_handle_t connection); + + /** + * see pal::GattClient::get_mtu_size . + */ + virtual ble_error_t get_mtu_size( + connection_handle_t connection_handle, uint16_t& mtu_size + ); + + /** + * see pal::GattClient::discover_primary_service . + */ + virtual ble_error_t discover_primary_service( + connection_handle_t connection, + attribute_handle_t discovery_range_begining + ); + + /** + * see pal::GattClient::discover_primary_service_by_service_uuid . + */ + virtual ble_error_t discover_primary_service_by_service_uuid( + connection_handle_t connection_handle, + attribute_handle_t discovery_range_beginning, + const UUID& uuid + ); + + /** + * see pal::GattClient::find_included_service . + */ + virtual ble_error_t find_included_service( + connection_handle_t connection_handle, + attribute_handle_range_t service_range + ); + + /** + * see pal::GattClient::discover_characteristics_of_a_service . + */ + virtual ble_error_t discover_characteristics_of_a_service( + connection_handle_t connection_handle, + attribute_handle_range_t discovery_range + ); + + /** + * see pal::GattClient::discover_characteristics_descriptors . + */ + virtual ble_error_t discover_characteristics_descriptors( + connection_handle_t connection_handle, + attribute_handle_range_t descriptors_discovery_range + ); + + /** + * see pal::GattClient::read_attribute_value . + */ + virtual ble_error_t read_attribute_value( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle + ); + + /** + * see pal::GattClient::read_using_characteristic_uuid . + */ + virtual ble_error_t read_using_characteristic_uuid( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& uuid + ); + + /** + * see pal::GattClient::read_attribute_blob . + */ + virtual ble_error_t read_attribute_blob( + connection_handle_t connection, + attribute_handle_t attribute_handle, + uint16_t offset + ); + + /** + * see pal::GattClient::read_multiple_characteristic_values . + */ + virtual ble_error_t read_multiple_characteristic_values( + connection_handle_t connection, + const ArrayView& characteristic_handles + ); + + /** + * see pal::GattClient::write_without_response . + */ + virtual ble_error_t write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::signed_write_without_response . + */ + virtual ble_error_t signed_write_without_response( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::write_attribute . + */ + virtual ble_error_t write_attribute( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView& value + ); + + /** + * see pal::GattClient::queue_prepare_write . + */ + virtual ble_error_t queue_prepare_write( + connection_handle_t connection_handle, + attribute_handle_t characteristic_value_handle, + const ArrayView& value, + uint16_t offset + ); + + /** + * see pal::GattClient::execute_write_queue . + */ + virtual ble_error_t execute_write_queue( + connection_handle_t connection_handle, + bool execute + ); + + // singleton of the ARM Cordio client + static nRF5xGattClient& get_client(); + + /** + * Function call from btle.cpp + * + * Do not call directly. + */ + static void handle_events(const ble_evt_t *p_ble_evt); + + /** + * Called by btle.cpp when a disconnection happens. + */ + static void handle_connection_termination(connection_handle_t connection); + +private: + struct GattProcedure; + struct RegularGattProcedure; + struct DiscoverPrimaryServiceProcedure; + struct DiscoverPrimaryServiceByUUIDProcedure; + struct FindIncludedServicesProcedure; + struct DiscoverCharacteristicsProcedure; + struct DiscoverDescriptorsProcedure; + struct ReadAttributeProcedure; + struct ReadUsingCharacteristicUUIDProcedure; + struct ReadAttributeBlobProcedure; + struct ReadMultipleCharacteristicsProcedure; + struct WriteAttributeProcedure; + struct QueuePrepareWriteProcedure; + struct ExecuteWriteQueueProcedure; + + template + ble_error_t launch_procedure(connection_handle_t connection, const A0& a0); + + template + ble_error_t launch_procedure( + connection_handle_t connection, const A0& a0, const A1& a1 + ); + + template + ble_error_t launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2 + ); + + template + ble_error_t launch_procedure( + connection_handle_t connection, + const A0& a0, const A1& a1, const A2& a2, const A3& a3 + ); + + GattProcedure* get_procedure(connection_handle_t) const; + bool register_procedure(GattProcedure*); + bool remove_procedure(GattProcedure*); + + void handle_procedure_event(const ble_evt_t &evt); + void handle_hvx_event(const ble_evt_t &evt); + void handle_timeout_event(const ble_evt_t &evt); + + static const size_t max_procedures_count = + CENTRAL_LINK_COUNT + PERIPHERAL_LINK_COUNT; + + // Note: Ideally we would have used an array of variant here + GattProcedure* _procedures[max_procedures_count]; +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif /* BLE_NORDIC_PAL_GATT_CLIENT_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp new file mode 100644 index 0000000000..a1d6b1e7e9 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp @@ -0,0 +1,1255 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nRF5xPalSecurityManager.h" +#include "nRF5xn.h" +#include "ble/Gap.h" +#include "nRF5xGap.h" +#include "nrf_ble.h" +#include "ble_gap.h" +#include "nrf_soc.h" +#include "nrf_error.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +namespace { +static ble_error_t convert_sd_error(uint32_t err) { + switch (err) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + case NRF_ERROR_INVALID_ADDR: + case NRF_ERROR_INVALID_PARAM: + case BLE_ERROR_INVALID_CONN_HANDLE: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + case BLE_ERROR_INVALID_ROLE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_NOT_SUPPORTED: + return BLE_ERROR_NOT_IMPLEMENTED; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + case NRF_ERROR_TIMEOUT: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_NO_MEM: + return BLE_ERROR_NO_MEM; + default: + return BLE_ERROR_UNSPECIFIED; + } +} +} + +enum pairing_role_t { + PAIRING_INITIATOR, + PAIRING_RESPONDER +}; + +struct nRF5xSecurityManager::pairing_control_block_t { + pairing_control_block_t* next; + connection_handle_t connection; + pairing_role_t role; + + // flags of the key present + KeyDistribution initiator_dist; + KeyDistribution responder_dist; + + // own keys + ble_gap_enc_key_t own_enc_key; + ble_gap_id_key_t own_id_key; + ble_gap_sign_info_t own_sign_key; + ble_gap_lesc_p256_pk_t own_pk; + + // peer keys + ble_gap_enc_key_t peer_enc_key; + ble_gap_id_key_t peer_id_key; + ble_gap_sign_info_t peer_sign_key; + ble_gap_lesc_p256_pk_t peer_pk; + + // flag required to help DHKey computation/process; should be removed with + // later versions of the softdevice + uint8_t own_oob:1; + uint8_t peer_oob:1; +}; + +nRF5xSecurityManager::nRF5xSecurityManager() + : ::ble::pal::SecurityManager(), + _sign_counter(), + _io_capability(io_capability_t::NO_INPUT_NO_OUTPUT), + _min_encryption_key_size(7), + _max_encryption_key_size(16), + _control_blocks(NULL), + resolving_list_entry_count(0) +{ + +} + +nRF5xSecurityManager::~nRF5xSecurityManager() +{ + terminate(); +} + +//////////////////////////////////////////////////////////////////////////// +// SM lifecycle management +// + +ble_error_t nRF5xSecurityManager::initialize() +{ +#if defined(MBEDTLS_ECDH_C) + if (_crypto.generate_keys( + make_ArrayView(X), + make_ArrayView(Y), + make_ArrayView(secret) + )) { + return BLE_ERROR_NONE; + } + + return BLE_ERROR_INTERNAL_STACK_FAILURE; +#endif + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::terminate() +{ + release_all_pairing_cb(); + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::reset() +{ + ble_error_t err = terminate(); + if (err) { + return err; + } + + return initialize(); +} + +//////////////////////////////////////////////////////////////////////////// +// Resolving list management +// + +// FIXME: on nordic, the irk is passed in sd_ble_gap_scan_start where whitelist +// and resolving list are all mixed up. + +uint8_t nRF5xSecurityManager::read_resolving_list_capacity() +{ + return MAX_RESOLVING_LIST_ENTRIES; +} + +ble_error_t nRF5xSecurityManager::add_device_to_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address, + const irk_t &peer_irk +) { + if (resolving_list_entry_count >= MAX_RESOLVING_LIST_ENTRIES) { + return BLE_ERROR_INVALID_STATE; + } + + ble_gap_id_key_t& entry = resolving_list[resolving_list_entry_count]; + entry.id_addr_info.addr_type = peer_identity_address_type.value(); + memcpy( + entry.id_addr_info.addr, + peer_identity_address.data(), + peer_identity_address.size() + ); + memcpy( + entry.id_info.irk, + peer_irk.data(), + peer_irk.size() + ); + + ++resolving_list_entry_count; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::remove_device_from_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address +) { + size_t entry_index; + + // first the index needs to be found + for (entry_index = 0; entry_index < resolving_list_entry_count; ++entry_index) { + ble_gap_id_key_t& entry = resolving_list[entry_index]; + if (entry.id_addr_info.addr_type == peer_identity_address_type.value() && + entry.id_addr_info.addr == peer_identity_address + ) { + break; + } + } + + if (entry_index == resolving_list_entry_count) { + return BLE_ERROR_INVALID_PARAM; + } + + // Elements after the entry can be moved in the list + for (size_t i = entry_index; i < (resolving_list_entry_count - 1); ++i) { + resolving_list[i] = resolving_list[i + 1]; + } + + --resolving_list_entry_count; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::clear_resolving_list() +{ + resolving_list_entry_count = 0; + return BLE_ERROR_NONE; +} + +ArrayView nRF5xSecurityManager::get_resolving_list() { + return ArrayView( + resolving_list, + resolving_list_entry_count + ); +} + +//////////////////////////////////////////////////////////////////////////// +// Pairing +// + + +ble_error_t nRF5xSecurityManager::send_pairing_request( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + // allocate the control block required for the procedure completion + pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_NO_MEM; + } + pairing_cb->role = PAIRING_INITIATOR; + + // override signing parameter + initiator_dist.set_signing(false); + responder_dist.set_signing(false); + + // override link parameter + initiator_dist.set_link(false); + responder_dist.set_link(false); + + ble_gap_sec_params_t security_params = make_security_params( + oob_data_flag, + authentication_requirements, + initiator_dist, + responder_dist + ); + + uint32_t err = sd_ble_gap_authenticate( + connection, + &security_params + ); + + if (err) { + release_pairing_cb(pairing_cb); + } + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::send_pairing_response( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); + if (!pairing_cb) { + // not enough memory; try to reject the pairing request instead of + // waiting for timeout. + cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON); + return BLE_ERROR_NO_MEM; + } + pairing_cb->role = PAIRING_RESPONDER; + + // override signing parameter + initiator_dist.set_signing(false); + responder_dist.set_signing(false); + + // override link parameter + initiator_dist.set_link(false); + responder_dist.set_link(false); + + ble_gap_sec_params_t security_params = make_security_params( + oob_data_flag, + authentication_requirements, + initiator_dist, + responder_dist + ); + + ble_gap_sec_keyset_t keyset = make_keyset( + *pairing_cb, + initiator_dist, + responder_dist + ); + + uint32_t err = sd_ble_gap_sec_params_reply( + connection, + /* status */ BLE_GAP_SEC_STATUS_SUCCESS, + /* params */ &security_params, + /* keys */ &keyset + ); + + if (err) { + release_pairing_cb(pairing_cb); + } + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::cancel_pairing( + connection_handle_t connection, pairing_failure_t reason +) { + uint32_t err = 0; + + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + + // If there is no control block yet then if the local device is a central + // then we must reject the security request otherwise it is a response to + // a pairing feature exchange from a central. + if (!pairing_cb) { + ::Gap::Role_t current_role; + if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) { + return BLE_ERROR_INVALID_PARAM; + } + + if (current_role == ::Gap::PERIPHERAL) { + // response to a pairing feature request + err = sd_ble_gap_sec_params_reply( + connection, + reason.value() | 0x80, + /* sec params */ NULL, + /* keyset */ NULL + ); + } else { + // response to a peripheral security request + err = sd_ble_gap_authenticate(connection, NULL); + } + } else { + // At this point this must be a response to a key + err = sd_ble_gap_auth_key_reply( + connection, + /* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE, + /* key */ NULL + ); + } + + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Feature support +// + +ble_error_t nRF5xSecurityManager::get_secure_connections_support( + bool &enabled +) { + enabled = true; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_io_capability(io_capability_t io_capability) +{ + _io_capability = io_capability; + return BLE_ERROR_NONE; +} + +//////////////////////////////////////////////////////////////////////////// +// Security settings +// + +ble_error_t nRF5xSecurityManager::set_authentication_timeout( + connection_handle_t connection, uint16_t timeout_in_10ms +) { + ble_opt_t opt; + opt.gap_opt.auth_payload_timeout.conn_handle = connection; + opt.gap_opt.auth_payload_timeout.auth_payload_timeout = timeout_in_10ms; + uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, &opt); + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::get_authentication_timeout( + connection_handle_t connection, uint16_t &timeout_in_10ms +) { + ble_opt_t opt; + opt.gap_opt.auth_payload_timeout.conn_handle = connection; + + uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, &opt); + if (err) { + return convert_sd_error(err); + } + + timeout_in_10ms = opt.gap_opt.auth_payload_timeout.auth_payload_timeout; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_encryption_key_requirements( + uint8_t min_encryption_key_size, + uint8_t max_encryption_key_size +) { + if ((min_encryption_key_size < 7) || (min_encryption_key_size > 16) || + (min_encryption_key_size > max_encryption_key_size)) { + return BLE_ERROR_INVALID_PARAM; + } + + _min_encryption_key_size = min_encryption_key_size; + _max_encryption_key_size = max_encryption_key_size; + + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::slave_security_request( + connection_handle_t connection, + AuthenticationMask authentication +) { + // In the peripheral role, only the bond, mitm, lesc and keypress fields of + // this structure are used. + ble_gap_sec_params_t security_params = { + /* bond */ authentication.get_bondable(), + /* mitm */ authentication.get_mitm(), + /* lesc */ authentication.get_secure_connections(), + /* keypress */ authentication.get_keypress_notification(), + /* remainder of the data structure is ignored */ 0 + }; + + uint32_t err = sd_ble_gap_authenticate( + connection, + &security_params + ); + + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Encryption +// + +ble_error_t nRF5xSecurityManager::enable_encryption( + connection_handle_t connection, + const ltk_t <k, + const rand_t &rand, + const ediv_t &ediv, + bool mitm +) { + ble_gap_master_id_t master_id; + memcpy(master_id.rand, rand.data(), rand.size()); + memcpy(&master_id.ediv, ediv.data(), ediv.size()); + + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = false; + enc_info.auth = mitm; + + // FIXME: how to pass the lenght of the LTK ??? + enc_info.ltk_len = ltk.size(); + + uint32_t err = sd_ble_gap_encrypt( + connection, + &master_id, + &enc_info + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::enable_encryption( + connection_handle_t connection, + const ltk_t <k, + bool mitm +) { + ble_gap_master_id_t master_id = {0}; + + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = true; + enc_info.auth = mitm; + enc_info.ltk_len = ltk.size(); + + uint32_t err = sd_ble_gap_encrypt( + connection, + &master_id, + &enc_info + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::encrypt_data( + const byte_array_t<16> &key, + encryption_block_t &data +) { + nrf_ecb_hal_data_t ecb; + memcpy(&ecb.key, key.data(), key.size()); + memcpy(&ecb.cleartext, data.data(), data.size()); + + uint32_t err = sd_ecb_block_encrypt(&ecb); + if (err) { + return convert_sd_error(err); + } + + memcpy(data.data(), &ecb.ciphertext, data.size()); + return BLE_ERROR_NONE; +} + +//////////////////////////////////////////////////////////////////////////// +// Privacy +// + +ble_error_t nRF5xSecurityManager::set_private_address_timeout( + uint16_t timeout_in_seconds +) { + ble_gap_privacy_params_t privacy_config; + + uint32_t err = sd_ble_gap_privacy_get(&privacy_config); + if (err) { + return convert_sd_error(err); + } + + privacy_config.private_addr_cycle_s = timeout_in_seconds; + err = sd_ble_gap_privacy_set(&privacy_config); + + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// Keys +// + +ble_error_t nRF5xSecurityManager::set_ltk( + connection_handle_t connection, + const ltk_t& ltk, + bool mitm, + bool secure_connections +) { + ble_gap_enc_info_t enc_info; + memcpy(enc_info.ltk, ltk.data(), ltk.size()); + enc_info.lesc = secure_connections; + enc_info.auth = mitm; + enc_info.ltk_len = ltk.size(); + + // FIXME: provide peer irk and csrk ? + uint32_t err = sd_ble_gap_sec_info_reply( + connection, + &enc_info, + /* id info */ NULL, + /* sign info */ NULL // Not supported + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_ltk_not_found( + connection_handle_t connection +) { + uint32_t err = sd_ble_gap_sec_info_reply( + connection, + NULL, + NULL, + NULL // Not supported + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_irk(const irk_t& irk) +{ + + ble_gap_privacy_params_t privacy_config; + + // get the previous config + uint32_t err = sd_ble_gap_privacy_get(&privacy_config); + if (err) { + return convert_sd_error(err); + } + + // set the new irk + memcpy(privacy_config.p_device_irk, irk.data(), irk.size()); + err = sd_ble_gap_privacy_set(&privacy_config); + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::set_csrk( + const csrk_t& csrk, + sign_count_t sign_counter +) { + _csrk = csrk; + _sign_counter = sign_counter; + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xSecurityManager::set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk, + bool authenticated, + sign_count_t sign_counter +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection) +{ + return BLE_ERROR_NOT_IMPLEMENTED; +} +//////////////////////////////////////////////////////////////////////////// +// Authentication +// + +ble_error_t nRF5xSecurityManager::get_random_data(byte_array_t<8> &random_data) +{ + uint32_t err = sd_rand_application_vector_get( + random_data.data(), random_data.size() + ); + return convert_sd_error(err); +} + +//////////////////////////////////////////////////////////////////////////// +// MITM +// + +ble_error_t nRF5xSecurityManager::set_display_passkey(passkey_num_t passkey) +{ + PasskeyAscii passkey_ascii(passkey); + ble_opt_t sd_passkey; + sd_passkey.gap_opt.passkey.p_passkey = passkey ? passkey_ascii.value() : NULL; + uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &sd_passkey); + return convert_sd_error(err); +} + + +ble_error_t nRF5xSecurityManager::passkey_request_reply( + connection_handle_t connection, const passkey_num_t passkey +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + PasskeyAscii pkasc(passkey); + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + BLE_GAP_AUTH_KEY_TYPE_PASSKEY, + pkasc.value() + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + ble_gap_lesc_oob_data_t oob_own; + ble_gap_lesc_oob_data_t oob_peer; + + // is own address important ? + memcpy(oob_own.r, local_random.data(), local_random.size()); + // FIXME: What to do with local confirm ??? + + // is peer address important ? + memcpy(oob_peer.r, peer_random.data(), peer_random.size()); + memcpy(oob_peer.c, peer_confirm.data(), peer_confirm.size()); + + uint32_t err = sd_ble_gap_lesc_oob_data_set( + connection, + pairing_cb->own_oob ? &oob_own : NULL, + pairing_cb->peer_oob ? &oob_peer : NULL + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::legacy_pairing_oob_request_reply( + connection_handle_t connection, + const oob_tk_t& oob_data +) { + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + BLE_GAP_AUTH_KEY_TYPE_OOB, + oob_data.data() + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::confirmation_entered( + connection_handle_t connection, bool confirmation +) { + pairing_control_block_t* pairing_cb = get_pairing_cb(connection); + if (!pairing_cb) { + return BLE_ERROR_INVALID_STATE; + } + + uint32_t err = sd_ble_gap_auth_key_reply( + connection, + confirmation ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, + NULL + ); + + return convert_sd_error(err); +} + +ble_error_t nRF5xSecurityManager::send_keypress_notification( + connection_handle_t connection, Keypress_t keypress +) { + uint32_t err = sd_ble_gap_keypress_notify( + connection, + static_cast(keypress) + ); + return convert_sd_error(err); +} + + +ble_error_t nRF5xSecurityManager::generate_secure_connections_oob() +{ +#if defined(MBEDTLS_ECDH_C) + ble_gap_lesc_p256_pk_t own_secret; + ble_gap_lesc_oob_data_t oob_data; + + memcpy(own_secret.pk, secret.data(), secret.size()); + + uint32_t err = sd_ble_gap_lesc_oob_data_get( + BLE_CONN_HANDLE_INVALID, + &own_secret, + &oob_data + ); + + if (!err) { + get_event_handler()->on_secure_connections_oob_generated( + oob_data.r, + oob_data.c + ); + } + + return convert_sd_error(err); +#endif + return BLE_ERROR_NOT_IMPLEMENTED; +} + +nRF5xSecurityManager& nRF5xSecurityManager::get_security_manager() +{ + static nRF5xSecurityManager _security_manager; + return _security_manager; +} + +/** + * EDIV and Rand are invalid if both are zero + */ +bool is_ediv_rand_valid(const uint16_t ediv, const uint8_t* rand) +{ + for (int i = 0; i < BLE_GAP_SEC_RAND_LEN; ++i) { + if (rand[i]) { + return true; + } + } + + if (ediv != 0) { + return true; + } + + return false; +} + +bool nRF5xSecurityManager::sm_handler(const ble_evt_t *evt) +{ + nRF5xSecurityManager& self = nRF5xSecurityManager::get_security_manager(); + SecurityManager::EventHandler* handler = self.get_event_handler(); + + if ((evt == NULL) || (handler == NULL)) { + return false; + } + + const ble_gap_evt_t& gap_evt = evt->evt.gap_evt; + uint16_t connection = gap_evt.conn_handle; + pairing_control_block_t* pairing_cb = self.get_pairing_cb(connection); + + switch (evt->header.evt_id) { + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { + const ble_gap_sec_params_t& params = + gap_evt.params.sec_params_request.peer_params; + + KeyDistribution initiator_dist( + params.kdist_peer.enc, + params.kdist_peer.id, + params.kdist_peer.sign, + params.kdist_peer.link + ); + + KeyDistribution responder_dist( + params.kdist_own.enc, + params.kdist_own.id, + params.kdist_own.sign, + params.kdist_own.link + ); + + if (pairing_cb && pairing_cb->role == PAIRING_INITIATOR) { + // override signing parameter + initiator_dist.set_signing(false); + responder_dist.set_signing(false); + + // override link parameter + initiator_dist.set_link(false); + responder_dist.set_link(false); + + // when this event is received by an initiator, it should not be + // forwarded via the handler; this is not a behaviour expected + // by the bluetooth standard ... + ble_gap_sec_keyset_t keyset = make_keyset( + *pairing_cb, + initiator_dist, + responder_dist + ); + uint32_t err = sd_ble_gap_sec_params_reply( + connection, + /* status */ BLE_GAP_SEC_STATUS_SUCCESS, + /* params */ NULL, + /* keys ... */ &keyset + ); + + // in case of error; release the pairing control block and signal + // it to the event handler + if (err) { + release_pairing_cb(pairing_cb); + handler->on_pairing_error( + connection, + pairing_failure_t::UNSPECIFIED_REASON + ); + } + } else { + handler->on_pairing_request( + connection, + params.oob, + AuthenticationMask( + params.bond, + params.mitm, + params.lesc, + params.keypress + ), + initiator_dist, + responder_dist + ); + } + return true; + } + + case BLE_GAP_EVT_SEC_INFO_REQUEST: { + const ble_gap_evt_sec_info_request_t& req = + gap_evt.params.sec_info_request; + + if (is_ediv_rand_valid(req.master_id.ediv, req.master_id.rand)) { + handler->on_ltk_request( + connection, + ediv_t((uint8_t*)(&req.master_id.ediv)), + rand_t(req.master_id.rand) + ); + } else { + /* no valid EDIV and Rand + * request ltk generated with secure connection */ + handler->on_ltk_request(connection); + } + + return true; + } + + case BLE_GAP_EVT_PASSKEY_DISPLAY: { + const ble_gap_evt_passkey_display_t& req = + gap_evt.params.passkey_display; + + if (req.match_request == 0) { + handler->on_passkey_display( + connection, + PasskeyAscii::to_num(req.passkey) + ); + } else { + handler->on_passkey_display( + connection, + PasskeyAscii::to_num(req.passkey) + ); + handler->on_confirmation_request(connection); + } + + return true; + } + + case BLE_GAP_EVT_KEY_PRESSED: { + handler->on_keypress_notification( + connection, + (Keypress_t)gap_evt.params.key_pressed.kp_not + ); + return true; + } + + case BLE_GAP_EVT_AUTH_KEY_REQUEST: { + uint8_t key_type = gap_evt.params.auth_key_request.key_type; + + switch (key_type) { + case BLE_GAP_AUTH_KEY_TYPE_NONE: // Illegal + break; + + case BLE_GAP_AUTH_KEY_TYPE_PASSKEY: + handler->on_passkey_request(connection); + break; + + case BLE_GAP_AUTH_KEY_TYPE_OOB: + handler->on_legacy_pairing_oob_request(connection); + break; + } + + return true; + } + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { +#if defined(MBEDTLS_ECDH_C) + const ble_gap_evt_lesc_dhkey_request_t& dhkey_request = + gap_evt.params.lesc_dhkey_request; + + static const size_t key_size = public_key_coord_t::size_; + ble_gap_lesc_dhkey_t shared_secret; + + _crypto.generate_shared_secret( + make_const_ArrayView(dhkey_request.p_pk_peer->pk), + make_const_ArrayView(dhkey_request.p_pk_peer->pk + key_size), + make_const_ArrayView(secret), + shared_secret.key + ); + + sd_ble_gap_lesc_dhkey_reply(connection, &shared_secret); + + if (dhkey_request.oobd_req) { + handler->on_secure_connections_oob_request(connection); + } +#endif + return true; + } + + case BLE_GAP_EVT_AUTH_STATUS: { + const ble_gap_evt_auth_status_t& status = gap_evt.params.auth_status; + + switch (status.auth_status) { + // NOTE: pairing_cb must be valid if this event has been + // received as it is being allocated earlier and release + // in this block + // The memory is released before the last call to the event handler + // to free the heap a bit before subsequent allocation with user + // code. + case BLE_GAP_SEC_STATUS_SUCCESS: { + KeyDistribution own_dist; + KeyDistribution peer_dist; + + if (pairing_cb->role == PAIRING_INITIATOR) { + own_dist = pairing_cb->initiator_dist; + peer_dist = pairing_cb->responder_dist; + } else { + own_dist = pairing_cb->responder_dist; + peer_dist = pairing_cb->initiator_dist; + } + + if (is_ediv_rand_valid( + pairing_cb->own_enc_key.master_id.ediv, + pairing_cb->own_enc_key.master_id.rand + ) + ) { + if (own_dist.get_encryption()) { + handler->on_keys_distributed_local_ltk( + connection, + ltk_t(pairing_cb->own_enc_key.enc_info.ltk) + ); + + handler->on_keys_distributed_local_ediv_rand( + connection, + ediv_t(reinterpret_cast( + &pairing_cb->own_enc_key.master_id.ediv + )), + pairing_cb->own_enc_key.master_id.rand + ); + } + + if (peer_dist.get_encryption()) { + handler->on_keys_distributed_ltk( + connection, + ltk_t(pairing_cb->peer_enc_key.enc_info.ltk) + ); + + handler->on_keys_distributed_ediv_rand( + connection, + ediv_t(reinterpret_cast( + &pairing_cb->peer_enc_key.master_id.ediv + )), + pairing_cb->peer_enc_key.master_id.rand + ); + } + } else { + /* no valid EDIV and Rand meaning this is a + * Secure Connections key */ + handler->on_secure_connections_ltk_generated( + connection, + ltk_t(pairing_cb->own_enc_key.enc_info.ltk) + ); + } + + if (peer_dist.get_identity()) { + handler->on_keys_distributed_irk( + connection, + irk_t(pairing_cb->peer_id_key.id_info.irk) + ); + + advertising_peer_address_type_t + address_type(advertising_peer_address_type_t::PUBLIC); + + if (pairing_cb->peer_id_key.id_addr_info.addr_type) { + address_type = advertising_peer_address_type_t::RANDOM; + } + + handler->on_keys_distributed_bdaddr( + connection, + address_type, + ble::address_t(pairing_cb->peer_id_key.id_addr_info.addr) + ); + } + + if (peer_dist.get_signing()) { + handler->on_keys_distributed_csrk( + connection, + pairing_cb->peer_sign_key.csrk + ); + } + + self.release_pairing_cb(pairing_cb); + handler->on_pairing_completed(connection); + break; + } + + case BLE_GAP_SEC_STATUS_TIMEOUT: + if (!pairing_cb) { + // Note: if pairing_cb does not exist then the timeout; + // is caused by a security request as the paiting_cb is + // created when the module receive the pairing request. + handler->on_link_encryption_request_timed_out(connection); + } else { + self.release_pairing_cb(pairing_cb); + handler->on_pairing_timed_out(connection); + } + break; + + case BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED: + case BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE: + case BLE_GAP_SEC_STATUS_AUTH_REQ: + case BLE_GAP_SEC_STATUS_CONFIRM_VALUE: + case BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP: + case BLE_GAP_SEC_STATUS_ENC_KEY_SIZE: + case BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED: + case BLE_GAP_SEC_STATUS_UNSPECIFIED: + case BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS: + case BLE_GAP_SEC_STATUS_INVALID_PARAMS: + case BLE_GAP_SEC_STATUS_DHKEY_FAILURE: + case BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE: + case BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG: + case BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED: + self.release_pairing_cb(pairing_cb); + handler->on_pairing_error( + connection, + (pairing_failure_t::type) (status.auth_status & 0xF) + ); + break; + + default: + self.release_pairing_cb(pairing_cb); + break; + } + + return true; + } + + case BLE_GAP_EVT_CONN_SEC_UPDATE: { + const ble_gap_evt_conn_sec_update_t& req = + gap_evt.params.conn_sec_update; + + if((req.conn_sec.sec_mode.sm == 1) && (req.conn_sec.sec_mode.lv >= 2)) { + handler->on_link_encryption_result( + connection, link_encryption_t::ENCRYPTED + ); + } else { + handler->on_link_encryption_result( + connection, link_encryption_t::NOT_ENCRYPTED + ); + } + return true; + } + + case BLE_GAP_EVT_TIMEOUT: { + switch (gap_evt.params.timeout.src) { + case BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD: + handler->on_valid_mic_timeout(connection); + return true; + + default: + return false; + } + return false; + } + + case BLE_GAP_EVT_SEC_REQUEST: { + const ble_gap_evt_sec_request_t& req = gap_evt.params.sec_request; + handler->on_slave_security_request( + connection, + AuthenticationMask(req.bond, req.mitm, req.lesc, req.keypress) + ); + return true; + } + + default: + return false; + } +} + +ble_gap_sec_params_t nRF5xSecurityManager::make_security_params( + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + ble_gap_sec_params_t security_params = { + /* bond */ authentication_requirements.get_bondable(), + /* mitm */ authentication_requirements.get_mitm(), + /* lesc */ authentication_requirements.get_secure_connections(), + /* keypress */ authentication_requirements.get_keypress_notification(), + /* io_caps */ _io_capability.value(), + /* oob */ oob_data_flag, + /* min_key_size */ _min_encryption_key_size, + /* max_key_size */ _max_encryption_key_size, + /* kdist_periph */ { + /* enc */ responder_dist.get_encryption(), + /* id */ responder_dist.get_identity(), + /* sign */ responder_dist.get_signing(), + /* link */ responder_dist.get_link() + }, + /* kdist_central */ { + /* enc */ initiator_dist.get_encryption(), + /* id */ initiator_dist.get_identity(), + /* sign */ initiator_dist.get_signing(), + /* link */ initiator_dist.get_link() + } + }; + return security_params; +} + +ble_gap_sec_keyset_t nRF5xSecurityManager::make_keyset( + pairing_control_block_t& pairing_cb, + KeyDistribution initiator_dist, + KeyDistribution responder_dist +) { + pairing_cb.initiator_dist = initiator_dist; + pairing_cb.responder_dist = responder_dist; + + ble_gap_sec_keyset_t keyset = { + /* keys_own */ { + &pairing_cb.own_enc_key, + &pairing_cb.own_id_key, + &pairing_cb.own_sign_key, + &pairing_cb.own_pk + }, + /* keys_peer */ { + &pairing_cb.peer_enc_key, + &pairing_cb.peer_id_key, + &pairing_cb.peer_sign_key, + &pairing_cb.peer_pk + } + }; + + // copy csrk if necessary + if (keyset.keys_own.p_sign_key) { + memcpy(keyset.keys_own.p_sign_key->csrk, _csrk.data(), _csrk.size()); + } + + // copy public keys used +#if defined(MBEDTLS_ECDH_C) + memcpy(pairing_cb.own_pk.pk, X.data(), X.size()); + memcpy(pairing_cb.own_pk.pk + X.size(), Y.data(), Y.size()); +#endif + return keyset; +} + +nRF5xSecurityManager::pairing_control_block_t* +nRF5xSecurityManager::allocate_pairing_cb(connection_handle_t connection) +{ + pairing_control_block_t* pairing_cb = + new (std::nothrow) pairing_control_block_t(); + if (pairing_cb) { + pairing_cb->next = _control_blocks; + _control_blocks = pairing_cb; + } + return pairing_cb; +} + +void nRF5xSecurityManager::release_pairing_cb(pairing_control_block_t* pairing_cb) +{ + if (pairing_cb == _control_blocks) { + _control_blocks = _control_blocks->next; + delete pairing_cb; + } else { + pairing_control_block_t* it = _control_blocks; + while (it->next) { + if (it->next == pairing_cb) { + it->next = pairing_cb->next; + delete pairing_cb; + return; + } + it = it->next; + } + } +} + +nRF5xSecurityManager::pairing_control_block_t* +nRF5xSecurityManager::get_pairing_cb(connection_handle_t connection) +{ + pairing_control_block_t* pcb = _control_blocks; + while (pcb) { + if (pcb->connection == connection) { + return pcb; + } + pcb = pcb->next; + } + + return NULL; +} + +void nRF5xSecurityManager::release_all_pairing_cb() +{ + while(_control_blocks) { + release_pairing_cb(_control_blocks); + } +} + +} // nordic +} // vendor +} // pal +} // ble + diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.h new file mode 100644 index 0000000000..30ac7e20cc --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xPalSecurityManager.h @@ -0,0 +1,380 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NRF5X_PAL_SECURITY_MANAGER_ +#define NRF5X_PAL_SECURITY_MANAGER_ + +#include "ble/BLETypes.h" +#include "ble/pal/PalSecurityManager.h" +#include "nrf_ble.h" +#include "nRF5xCrypto.h" + + +namespace ble { +namespace pal { +namespace vendor { +namespace nordic { + +class nRF5xSecurityManager : public ::ble::pal::SecurityManager { +public: + nRF5xSecurityManager(); + + virtual ~nRF5xSecurityManager(); + + //////////////////////////////////////////////////////////////////////////// + // SM lifecycle management + // + + /** + * @see ::ble::pal::SecurityManager::initialize + */ + virtual ble_error_t initialize(); + + /** + * @see ::ble::pal::SecurityManager::terminate + */ + virtual ble_error_t terminate(); + + /** + * @see ::ble::pal::SecurityManager::reset + */ + virtual ble_error_t reset() ; + + //////////////////////////////////////////////////////////////////////////// + // Resolving list management + // + + /** + * @see ::ble::pal::SecurityManager::read_resolving_list_capacity + */ + virtual uint8_t read_resolving_list_capacity(); + + /** + * @see ::ble::pal::SecurityManager::add_device_to_resolving_list + */ + virtual ble_error_t add_device_to_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address, + const irk_t &peer_irk + ); + + /** + * @see ::ble::pal::SecurityManager::remove_device_from_resolving_list + */ + virtual ble_error_t remove_device_from_resolving_list( + advertising_peer_address_type_t peer_identity_address_type, + const address_t &peer_identity_address + ); + + /** + * @see ::ble::pal::SecurityManager::clear_resolving_list + */ + virtual ble_error_t clear_resolving_list(); + + /** + * Return the IRKs present in the resolving list + * @param count The number of entries present in the resolving list. + * @param pointer to the first entry of the resolving list. + */ + ArrayView get_resolving_list(); + + //////////////////////////////////////////////////////////////////////////// + // Pairing + // + + /** + * @see ::ble::pal::SecurityManager::send_pairing_request + */ + virtual ble_error_t send_pairing_request( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + /** + * @see ::ble::pal::SecurityManager::send_pairing_response + */ + virtual ble_error_t send_pairing_response( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + /** + * @see ::ble::pal::SecurityManager::cancel_pairing + */ + virtual ble_error_t cancel_pairing( + connection_handle_t connection, pairing_failure_t reason + ); + + + //////////////////////////////////////////////////////////////////////////// + // Feature support + // + + /** + * @see ::ble::pal::SecurityManager::get_secure_connections_support + */ + virtual ble_error_t get_secure_connections_support( + bool &enabled + ); + + /** + * @see ::ble::pal::SecurityManager::set_io_capability + */ + virtual ble_error_t set_io_capability(io_capability_t io_capability); + + //////////////////////////////////////////////////////////////////////////// + // Security settings + // + + /** + * @see ::ble::pal::SecurityManager::set_authentication_timeout + */ + virtual ble_error_t set_authentication_timeout( + connection_handle_t, uint16_t timeout_in_10ms + ); + + /** + * @see ::ble::pal::SecurityManager::get_authentication_timeout + */ + virtual ble_error_t get_authentication_timeout( + connection_handle_t, uint16_t &timeout_in_10ms + ); + + /** + * @see ::ble::pal::SecurityManager::set_encryption_key_requirements + */ + virtual ble_error_t set_encryption_key_requirements( + uint8_t min_encryption_key_size, + uint8_t max_encryption_key_size + ); + + /** + * @see ::ble::pal::SecurityManager::slave_security_request + */ + virtual ble_error_t slave_security_request( + connection_handle_t connection, + AuthenticationMask authentication + ); + + //////////////////////////////////////////////////////////////////////////// + // Encryption + // + + /** + * @see ::ble::pal::SecurityManager::enable_encryption + */ + virtual ble_error_t enable_encryption( + connection_handle_t connection, + const ltk_t <k, + const rand_t &rand, + const ediv_t &ediv, + bool mitm + ); + + /** + * @see ::ble::pal::SecurityManager::enable_encryption + */ + virtual ble_error_t enable_encryption( + connection_handle_t connection, + const ltk_t <k, + bool mitm + ) ; + + /** + * @see ::ble::pal::SecurityManager::encrypt_data + */ + virtual ble_error_t encrypt_data( + const byte_array_t<16> &key, + encryption_block_t &data + ); + + //////////////////////////////////////////////////////////////////////////// + // Privacy + // + + /** + * @see ::ble::pal::SecurityManager::set_private_address_timeout + */ + virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds); + + //////////////////////////////////////////////////////////////////////////// + // Keys + // + + /** + * @see ::ble::pal::SecurityManager::set_ltk + */ + virtual ble_error_t set_ltk( + connection_handle_t connection, + const ltk_t <k, + bool mitm, + bool secure_connections + ); + + /** + * @see ::ble::pal::SecurityManager::set_ltk_not_found + */ + virtual ble_error_t set_ltk_not_found( + connection_handle_t connection + ); + + /** + * @see ::ble::pal::SecurityManager::set_irk + */ + virtual ble_error_t set_irk(const irk_t &irk); + + /** + * @see ::ble::pal::SecurityManager::set_csrk + */ + virtual ble_error_t set_csrk(const csrk_t &csrk, sign_count_t sign_counter); + + /** + * @see ::ble::pal::SecurityManager::set_peer_csrk + */ + virtual ble_error_t set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk, + bool authenticated, + sign_count_t sign_counter + ); + + /** + * @see ::ble::pal::SecurityManager::remove_peer_csrk + */ + virtual ble_error_t remove_peer_csrk(connection_handle_t connection); + + //////////////////////////////////////////////////////////////////////////// + // Authentication + // + + /** + * @see ::ble::pal::SecurityManager::get_random_data + */ + virtual ble_error_t get_random_data(byte_array_t<8> &random_data); + + //////////////////////////////////////////////////////////////////////////// + // MITM + // + + /** + * @see ::ble::pal::SecurityManager::set_display_passkey + */ + virtual ble_error_t set_display_passkey(passkey_num_t passkey); + + /** + * @see ::ble::pal::SecurityManager::passkey_request_reply + */ + virtual ble_error_t passkey_request_reply( + connection_handle_t connection, + passkey_num_t passkey + ); + + /** + * @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply + */ + virtual ble_error_t secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm + ); + + /** + * @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply + */ + virtual ble_error_t legacy_pairing_oob_request_reply( + connection_handle_t connection, + const oob_tk_t &oob_data + ); + + /** + * @see ::ble::pal::SecurityManager::confirmation_entered + */ + virtual ble_error_t confirmation_entered( + connection_handle_t connection, bool confirmation + ); + + /** + * @see ::ble::pal::SecurityManager::send_keypress_notification + */ + virtual ble_error_t send_keypress_notification( + connection_handle_t connection, Keypress_t keypress + ); + + /** + * @see ::ble::pal::SecurityManager::generate_secure_connections_oob + */ + virtual ble_error_t generate_secure_connections_oob(); + + // singleton of nordic Security Manager + static nRF5xSecurityManager& get_security_manager(); + + // Event handler + bool sm_handler(const ble_evt_t *evt); + +private: + csrk_t _csrk; + sign_count_t _sign_counter; + io_capability_t _io_capability; + uint8_t _min_encryption_key_size; + uint8_t _max_encryption_key_size; + + struct pairing_control_block_t; + + ble_gap_sec_params_t make_security_params( + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + ble_gap_sec_keyset_t make_keyset( + pairing_control_block_t& pairing_cb, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + pairing_control_block_t* allocate_pairing_cb(connection_handle_t connection); + void release_pairing_cb(pairing_control_block_t* pairing_cb); + pairing_control_block_t* get_pairing_cb(connection_handle_t connection); + void release_all_pairing_cb(); + + pairing_control_block_t* _control_blocks; +#if defined(MBEDTLS_ECDH_C) + CryptoToolbox _crypto; + ble::public_key_coord_t X; + ble::public_key_coord_t Y; + ble::public_key_coord_t secret; +#endif + + static const size_t MAX_RESOLVING_LIST_ENTRIES = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT; + + size_t resolving_list_entry_count; + ble_gap_id_key_t resolving_list[MAX_RESOLVING_LIST_ENTRIES]; +}; + +} // nordic +} // vendor +} // pal +} // ble + +#endif /* NRF5X_PAL_SECURITY_MANAGER_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.cpp new file mode 100644 index 0000000000..e8e463a0c5 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.cpp @@ -0,0 +1,255 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#include "nRF5xn.h" +#include "ble/blecommon.h" +#include "nrf_soc.h" + +#include "btle/btle.h" +#include "btle/custom/custom_helper.h" +#include "nrf_delay.h" + +extern "C" { +#include "nrf_sdh.h" +} + +#include "nRF5xPalGattClient.h" + +/** + * The singleton which represents the nRF51822 transport for the BLE. + */ +static nRF5xn& getDeviceInstance() { + static nRF5xn deviceInstance; + return deviceInstance; +} + + +/** + * BLE-API requires an implementation of the following function in order to + * obtain its transport handle. + */ +BLEInstanceBase * +createBLEInstance(void) +{ + return &nRF5xn::Instance(BLE::DEFAULT_INSTANCE); +} + +nRF5xn& nRF5xn::Instance(BLE::InstanceID_t instanceId) +{ + return getDeviceInstance(); +} + +nRF5xn::nRF5xn(void) : + initialized(false), + instanceID(BLE::DEFAULT_INSTANCE), + gapInstance(), + gattServerInstance(NULL), + gattClient(&(ble::pal::vendor::nordic::nRF5xGattClient::get_client())) +{ +} + +nRF5xn::~nRF5xn(void) +{ +} + +const char *nRF5xn::getVersion(void) +{ + if (!initialized) { + return "INITIALIZATION_INCOMPLETE"; + } + + static char versionString[32]; + static bool versionFetched = false; + + if (!versionFetched) { + ble_version_t version; + if ((sd_ble_version_get(&version) == NRF_SUCCESS) && (version.company_id == 0x0059)) { + switch (version.version_number) { + case 0x07: + case 0x08: + snprintf(versionString, sizeof(versionString), "Nordic BLE4.1 ver:%u fw:%04x", version.version_number, version.subversion_number); + break; + default: + snprintf(versionString, sizeof(versionString), "Nordic (spec unknown) ver:%u fw:%04x", version.version_number, version.subversion_number); + break; + } + versionFetched = true; + } else { + strncpy(versionString, "unknown", sizeof(versionString)); + } + } + + return versionString; +} + +/**************************************************************************/ +/*! + @brief Initialize the BLE stack. + + @returns ble_error_t + + @retval BLE_ERROR_NONE if everything executed properly and + BLE_ERROR_ALREADY_INITIALIZED if the stack has already + been initialized (possibly through a call to nRF5xn::init()). + BLE_ERROR_INTERNAL_STACK_FAILURE is returned if initialization + of the internal stack (SoftDevice) failed. + +*/ +/**************************************************************************/ +ble_error_t nRF5xn::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback) +{ + if (initialized) { + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_ALREADY_INITIALIZED + }; + callback.call(&context); + return BLE_ERROR_ALREADY_INITIALIZED; + } + + this->instanceID = instanceID; + + /* ToDo: Clear memory contents, reset the SD, etc. */ + if (btle_init() != ERROR_NONE) { + return BLE_ERROR_INTERNAL_STACK_FAILURE; + } + + initialized = true; + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_NONE + }; + callback.call(&context); + return BLE_ERROR_NONE; +} + +/**************************************************************************/ +/*! + @brief Purge the BLE stack of GATT and GAP state. + + @returns ble_error_t + + @retval BLE_ERROR_NONE + Everything executed properly + + @note When using S110, GattClient::shutdown() will not be called + since Gatt client features are not supported. +*/ +/**************************************************************************/ +ble_error_t nRF5xn::shutdown(void) +{ + if (!initialized) { + return BLE_ERROR_INITIALIZATION_INCOMPLETE; + } + + /* + * Shutdown the SoftDevice first. This is because we need to disable all + * interrupts. Otherwise if we clear the BLE API and glue code first there + * will be many NULL references and no config information which could lead + * to errors if the shutdown process is interrupted. + */ + #if NRF_SD_BLE_API_VERSION >= 5 + if (nrf_sdh_disable_request() != NRF_SUCCESS) { + return BLE_STACK_BUSY; + } + #else + if (softdevice_handler_sd_disable() != NRF_SUCCESS) { + return BLE_STACK_BUSY; + } + #endif + + /* Shutdown the BLE API and nRF51 glue code */ + ble_error_t error; + + if (gattServerInstance != NULL) { + error = gattServerInstance->reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + } + + /* S110 does not support BLE client features, nothing to reset. */ +#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) + error = getGattClient().reset(); + if (error != BLE_ERROR_NONE) { + return error; + } +#endif + + /* Gap instance is always present */ + error = gapInstance.reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + + custom_reset_128bits_uuid_table(); + + initialized = false; + return BLE_ERROR_NONE; +} + +SecurityManager& nRF5xn::getSecurityManager() +{ + const nRF5xn* self = this; + return const_cast(self->getSecurityManager()); +} + +const SecurityManager& nRF5xn::getSecurityManager() const +{ + ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = + ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager(); + static struct : ble::pal::SigningEventMonitor { + virtual void set_signing_event_handler(EventHandler *signing_event_handler) { } + } dummy_signing_event_monitor; + + static ble::generic::GenericSecurityManager m_instance( + m_pal, + const_cast(getGap()), + dummy_signing_event_monitor + ); + + return m_instance; +} + +void +nRF5xn::waitForEvent(void) +{ + processEvents(); + sd_app_evt_wait(); +} + +void nRF5xn::processEvents() { + core_util_critical_section_enter(); + if (isEventsSignaled) { + isEventsSignaled = false; + core_util_critical_section_exit(); +#if NRF_SD_BLE_API_VERSION >= 5 + // We use the "polling" dispatch model + // http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v14.2.0/group__nrf__sdh.html?cp=4_0_0_6_11_60_20#gab4d7be69304d4f5feefd1d440cc3e6c7 + // This will process any pending events from the Softdevice + nrf_sdh_evts_poll(); +#else + intern_softdevice_events_execute(); +#endif + } else { + core_util_critical_section_exit(); + } +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.h new file mode 100644 index 0000000000..088944faa6 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/nRF5xn.h @@ -0,0 +1,156 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NRF51822_H__ +#define __NRF51822_H__ + +#include "ble/BLE.h" +#include "ble/blecommon.h" +#include "ble/BLEInstanceBase.h" +#include "ble/generic/GenericGattClient.h" +#include "ble/generic/GenericSecurityManager.h" +#include "nRF5xPalSecurityManager.h" + +#include "nRF5xGap.h" +#include "nRF5xGattServer.h" + +#include "btle.h" + +class nRF5xn : public BLEInstanceBase +{ +public: + nRF5xn(void); + virtual ~nRF5xn(void); + + virtual ble_error_t init(BLE::InstanceID_t instanceID, FunctionPointerWithContext callback); + virtual bool hasInitialized(void) const { + return initialized; + } + virtual ble_error_t shutdown(void); + virtual const char *getVersion(void); + + /** + * Accessors to GAP. This function checks whether gapInstance points to an + * object. If if does not, then the gapInstance is updated to + * &_getInstance before returning. + * + * @return A reference to GattServer. + * + * @note Unlike the GattClient, GattServer and SecurityManager, Gap is + * always needed in a BLE application. Therefore it is allocated + * statically. + */ + virtual nRF5xGap &getGap() { + return gapInstance; + }; + + /** + * Accessors to GATT Server. This function checks whether a GattServer + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A reference to GattServer. + */ + virtual GattServer &getGattServer() { + if (gattServerInstance == NULL) { + gattServerInstance = new nRF5xGattServer(); + } + return *gattServerInstance; + }; + + /** + * Accessors to GATT Client. This function checks whether a GattClient + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A reference to GattClient. + */ + virtual GattClient &getGattClient() { + return gattClient; + } + + /** + * @see BLEInstanceBase::getSecurityManager + */ + virtual SecurityManager &getSecurityManager(); + + /** + * @see BLEInstanceBase::getSecurityManager + */ + virtual const SecurityManager &getSecurityManager() const; + + /** + * Accessors to GAP. This function checks whether gapInstance points to an + * object. If if does not, then the gapInstance is updated to + * &_getInstance before returning. + * + * @return A const reference to GattServer. + * + * @note Unlike the GattClient, GattServer and SecurityManager, Gap is + * always needed in a BLE application. Therefore it is allocated + * statically. + * + * @note The accessor is able to modify the object's state because the + * internal pointer has been declared mutable. + */ + virtual const nRF5xGap &getGap() const { + return gapInstance; + }; + + /** + * Accessors to GATT Server. This function checks whether a GattServer + * object was previously instantiated. If such object does not exist, then + * it is created before returning. + * + * @return A const reference to GattServer. + * + * @note The accessor is able to modify the object's state because the + * internal pointer has been declared mutable. + */ + virtual const nRF5xGattServer &getGattServer() const { + if (gattServerInstance == NULL) { + gattServerInstance = new nRF5xGattServer(); + } + return *gattServerInstance; + }; + + virtual void waitForEvent(void); + + virtual void processEvents(); + +public: + static nRF5xn& Instance(BLE::InstanceID_t instanceId = BLE::DEFAULT_INSTANCE); + +private: + bool initialized; + BLE::InstanceID_t instanceID; + +private: + mutable nRF5xGap gapInstance; /**< Gap instance whose reference is returned from a call to + * getGap(). Unlike the GattClient, GattServer and + * SecurityManager, Gap is always needed in a BLE application. */ + +private: + mutable nRF5xGattServer *gattServerInstance; /**< Pointer to the GattServer object instance. + * If NULL, then GattServer has not been initialized. + * The pointer has been declared as 'mutable' so that + * it can be assigned inside a 'const' function. */ + ble::generic::GenericGattClient gattClient; + + +}; + +#endif diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/projectconfig.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/projectconfig.h new file mode 100644 index 0000000000..15959850c4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/projectconfig.h @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PROJECTCONFIG_H_ +#define _PROJECTCONFIG_H_ + +#include "ble/GapAdvertisingData.h" + +/*========================================================================= + MCU & BOARD SELCTION + + CFG_BOARD is one of the value defined in board.h + -----------------------------------------------------------------------*/ + #define CFG_BOARD BOARD_PCA10001 + #define CFG_MCU_STRING "nRF51822" +/*=========================================================================*/ + + +/*========================================================================= + CODE BASE VERSION SETTINGS + + Please do not modify this version number. To set a version number + for your project or firmware, change the values in your 'boards/' + config file. + -----------------------------------------------------------------------*/ + #define CFG_CODEBASE_VERSION_MAJOR 0 + #define CFG_CODEBASE_VERSION_MINOR 1 + #define CFG_CODEBASE_VERSION_REVISION 0 +/*=========================================================================*/ + + +/*========================================================================= + FIRMWARE VERSION SETTINGS + -----------------------------------------------------------------------*/ + #define CFG_FIRMWARE_VERSION_MAJOR 0 + #define CFG_FIRMWARE_VERSION_MINOR 0 + #define CFG_FIRMWARE_VERSION_REVISION 0 +/*=========================================================================*/ + + +/*========================================================================= + DEBUG LEVEL + ----------------------------------------------------------------------- + + CFG_DEBUG Level 3: Full debug output, any failed assert + will produce a breakpoint for the + debugger + Level 2: ATTR_ALWAYS_INLINE is null, ASSERT + has text + Level 1: ATTR_ALWAYS_INLINE is an attribute, + ASSERT has no text + Level 0: No debug information generated + + -----------------------------------------------------------------------*/ + #define CFG_DEBUG (1) + + #if (CFG_DEBUG > 3) || (CFG_DEBUG < 0) + #error "CFG_DEBUG must be a value between 0 (no debug) and 3" + #endif +/*=========================================================================*/ + + +/*========================================================================= + GENERAL NRF51 PERIPHERAL SETTINGS + ----------------------------------------------------------------------- + + CFG_SCHEDULER_ENABLE Set this to 'true' or 'false' depending on + if you use the event scheduler or not + + -----------------------------------------------------------------------*/ + #define CFG_SCHEDULER_ENABLE false + + /*------------------------------- GPIOTE ------------------------------*/ + #define CFG_GPIOTE_MAX_USERS 1 /**< Maximum number of users of the GPIOTE handler. */ + + /*-------------------------------- TIMER ------------------------------*/ + #define CFG_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. freq = (32768/(PRESCALER+1)) */ + #define CFG_TIMER_MAX_INSTANCE 1 /**< Maximum number of simultaneously created timers. */ + #define CFG_TIMER_OPERATION_QUEUE_SIZE 2 /**< Size of timer operation queues. */ +/*=========================================================================*/ + + +/*========================================================================= + BTLE SETTINGS + -----------------------------------------------------------------------*/ + + #define CFG_BLE_TX_POWER_LEVEL 0 /**< in dBm (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ + + /*---------------------------- BOND MANAGER ---------------------------*/ + #define CFG_BLE_BOND_FLASH_PAGE_BOND (BLE_FLASH_PAGE_END-1) /**< Flash page used for bond manager bonding information.*/ + #define CFG_BLE_BOND_FLASH_PAGE_SYS_ATTR (BLE_FLASH_PAGE_END-3) /**< Flash page used for bond manager system attribute information. TODO check if we can use BLE_FLASH_PAGE_END-2*/ + #define CFG_BLE_BOND_DELETE_BUTTON_NUM 0 /**< Button to press to delete bond details during init */ + + /*------------------------------ SECURITY -----------------------------*/ + #define CFG_BLE_SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ + #define CFG_BLE_SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ + #define CFG_BLE_SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ + #define CFG_BLE_SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ + #define CFG_BLE_SEC_PARAM_MAX_KEY_SIZE 16 + + /*--------------------------------- GAP -------------------------------*/ + #define CFG_GAP_APPEARANCE GapAdvertisingData::GENERIC_TAG + #define CFG_GAP_LOCAL_NAME "nRF5x" + + #define CFG_GAP_CONNECTION_MIN_INTERVAL_MS 50 /**< Minimum acceptable connection interval */ + #define CFG_GAP_CONNECTION_MAX_INTERVAL_MS 500 /**< Maximum acceptable connection interval */ + #define CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS 4000 /**< Connection supervisory timeout */ + #define CFG_GAP_CONNECTION_SLAVE_LATENCY 0 /**< Slave Latency in number of connection events. */ + + #define CFG_GAP_ADV_INTERVAL_MS 25 /**< The advertising interval in miliseconds, should be multiply of 0.625 */ + #define CFG_GAP_ADV_TIMEOUT_S 180 /**< The advertising timeout in units of seconds. */ +/*=========================================================================*/ + + +/*========================================================================= + VALIDATION + -----------------------------------------------------------------------*/ + #if CFG_BLE_TX_POWER_LEVEL != -40 && CFG_BLE_TX_POWER_LEVEL != -20 && CFG_BLE_TX_POWER_LEVEL != -16 && CFG_BLE_TX_POWER_LEVEL != -12 && CFG_BLE_TX_POWER_LEVEL != -8 && CFG_BLE_TX_POWER_LEVEL != -4 && CFG_BLE_TX_POWER_LEVEL != 0 && CFG_BLE_TX_POWER_LEVEL != 4 + #error "CFG_BLE_TX_POWER_LEVEL must be -40, -20, -16, -12, -8, -4, 0 or 4" + #endif +/*=========================================================================*/ + +#endif /* _PROJECTCONFIG_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/supress-warnings.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/supress-warnings.cmake new file mode 100644 index 0000000000..60061399da --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/TARGET_NRF52/source/supress-warnings.cmake @@ -0,0 +1,21 @@ +# Copyright 2015 ARM Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +message("suppressing warnings from ble-nrf51822") + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set_target_properties(ble-nrf51822 + PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers" + ) +endif() diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/mbed_lib.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/mbed_lib.json similarity index 100% rename from features/FEATURE_BLE/targets/TARGET_NORDIC/mbed_lib.json rename to features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_SOFTDEVICE/mbed_lib.json diff --git a/targets/targets.json b/targets/targets.json index 79adc2e6b8..2608ffe3ff 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6519,9 +6519,10 @@ "NRF5x", "NRF52", "SDK_14_2", + "SOFTDEVICE_NONE", "CORDIO", "CORDIO_LL", - "SOFTDEVICE_NONE" + "NORDIC_CORDIO" ], "config": { "lf_clock_src": {