From 815d0d5efc09fedf73f1060abf658a807d3024f3 Mon Sep 17 00:00:00 2001 From: Steve Cartmell Date: Thu, 22 Nov 2018 16:34:36 +0000 Subject: [PATCH] feat(pan-cordio): Add cordio-ll libraries and NORDIC implementation --- features/FEATURE_BLE/ble/pal/GapEvents.h | 2 +- .../controller/include/ble/bb_ble_api.h | 487 +++ .../controller/include/ble/bb_ble_api_op.h | 353 ++ .../include/ble/bb_ble_api_pdufilt.h | 188 + .../include/ble/bb_ble_api_periodiclist.h | 120 + .../include/ble/bb_ble_api_reslist.h | 346 ++ .../include/ble/bb_ble_api_whitelist.h | 143 + .../controller/include/ble/lhci_api.h | 90 + .../controller/include/ble/ll_api.h | 3036 +++++++++++++++++ .../controller/include/ble/ll_init_api.h | 104 + .../controller/include/ble/ll_tester_api.h | 320 ++ .../controller/include/ble/sch_api_ble.h | 58 + .../controller/include/common/bb_api.h | 456 +++ .../controller/include/common/cfg_mac.h | 50 + .../controller/include/common/cfg_mac_ble.h | 108 + .../controller/include/common/sch_api.h | 69 + .../controller/sources/ble/bb/bb_ble_int.h | 134 + .../controller/sources/ble/include/lctr_api.h | 167 + .../sources/ble/include/lctr_api_adv_master.h | 109 + .../ble/include/lctr_api_adv_master_ae.h | 171 + .../sources/ble/include/lctr_api_adv_slave.h | 88 + .../ble/include/lctr_api_adv_slave_ae.h | 131 + .../sources/ble/include/lctr_api_conn.h | 286 ++ .../sources/ble/include/lctr_api_conn_cs2.h | 43 + .../ble/include/lctr_api_init_master.h | 72 + .../ble/include/lctr_api_init_master_ae.h | 81 + .../sources/ble/include/lctr_api_phy.h | 45 + .../sources/ble/include/lctr_api_priv.h | 87 + .../sources/ble/include/lctr_api_sc.h | 52 + .../controller/sources/ble/include/lmgr_api.h | 158 + .../sources/ble/include/lmgr_api_adv_master.h | 79 + .../ble/include/lmgr_api_adv_master_ae.h | 63 + .../sources/ble/include/lmgr_api_adv_slave.h | 86 + .../ble/include/lmgr_api_adv_slave_ae.h | 46 + .../sources/ble/include/lmgr_api_conn.h | 79 + .../sources/ble/include/lmgr_api_priv.h | 67 + .../sources/ble/include/lmgr_api_sc.h | 68 + .../controller/sources/ble/lctr/lctr_int.h | 190 ++ .../sources/ble/lctr/lctr_int_adv_master.h | 180 + .../sources/ble/lctr/lctr_int_adv_master_ae.h | 433 +++ .../sources/ble/lctr/lctr_int_adv_slave.h | 148 + .../sources/ble/lctr/lctr_int_adv_slave_ae.h | 324 ++ .../sources/ble/lctr/lctr_int_conn.h | 869 +++++ .../sources/ble/lctr/lctr_int_conn_master.h | 83 + .../sources/ble/lctr/lctr_int_conn_slave.h | 75 + .../sources/ble/lctr/lctr_int_enc_master.h | 48 + .../sources/ble/lctr/lctr_int_enc_slave.h | 90 + .../sources/ble/lctr/lctr_int_init_master.h | 94 + .../ble/lctr/lctr_int_init_master_ae.h | 125 + .../sources/ble/lctr/lctr_int_master_phy.h | 44 + .../sources/ble/lctr/lctr_int_priv.h | 54 + .../sources/ble/lctr/lctr_int_slave_phy.h | 55 + .../sources/ble/lctr/lctr_int_tester.h | 71 + .../sources/ble/lctr/lctr_pdu_adv.h | 89 + .../sources/ble/lctr/lctr_pdu_adv_ae.h | 130 + .../sources/ble/lctr/lctr_pdu_conn.h | 244 ++ .../controller/sources/ble/lhci/lhci_int.h | 502 +++ .../controller/sources/ble/sch/sch_int_rm.h | 86 + .../controller/sources/common/bb/bb_int.h | 68 + .../controller/sources/common/sch/sch_int.h | 120 + .../cordio_stack/libcordio_stack.a | Bin 0 -> 1117152 bytes .../platform/common/include/bb_154_drv.h | 328 ++ .../platform/common/include/bb_ble_drv.h | 443 +++ .../platform/common/include/bb_drv.h | 136 + .../platform/common/include/chci_api.h | 148 + .../platform/common/include/chci_drv.h | 75 + .../platform/common/include/chci_tr.h | 77 + .../platform/common/include/chci_tr_serial.h | 48 + .../platform/common/include/hci_defs.h | 1094 ++++++ .../platform/common/include/ll_defs.h | 351 ++ .../platform/common/include/ll_math.h | 216 ++ .../common/include/platform_154_api.h | 51 + .../platform/common/include/platform_api.h | 283 ++ .../common/include/platform_ble_api.h | 101 + .../platform/common/include/prand.h | 61 + .../platform/common/include/radio_drv.h | 320 ++ .../thirdparty/uecc/LICENSE.txt | 21 + .../thirdparty/uecc/README.txt | 208 ++ .../thirdparty/uecc/asm_arm.inc | 2455 +++++++++++++ .../thirdparty/uecc/uECC_ll.c | 1038 ++++++ .../thirdparty/uecc/uECC_ll.h | 134 + .../TARGET_NORDIC/TARGET_NRF52/CHANGELOG.md | 344 -- .../TARGET_NORDIC/TARGET_NRF52/LICENSE | 6 - .../TARGET_NORDIC/TARGET_NRF52/apache-2.0.txt | 13 - .../TARGET_NORDIC/TARGET_NRF52/module.json | 36 - .../softdevice_nrf51822_licence_agreement.txt | 30 - .../TARGET_NRF52/source/btle/btle.cpp | 453 --- .../TARGET_NRF52/source/btle/btle.h | 74 - .../TARGET_NRF52/source/btle/btle_clock.h | 133 - .../source/btle/custom/custom_helper.cpp | 361 -- .../source/btle/custom/custom_helper.h | 74 - .../TARGET_NRF52/source/common/ansi_escape.h | 103 - .../TARGET_NRF52/source/common/assertion.h | 197 -- .../TARGET_NRF52/source/common/binary.h | 96 - .../TARGET_NRF52/source/common/ble_error.h | 151 - .../TARGET_NRF52/source/common/common.h | 236 -- .../TARGET_NRF52/source/common/compiler.h | 160 - .../TARGET_NRF52/source/nRF5xCrypto.cpp | 190 -- .../TARGET_NRF52/source/nRF5xCrypto.h | 146 - .../TARGET_NRF52/source/nRF5xGap.h | 346 -- .../TARGET_NRF52/source/nRF5xGattServer.cpp | 862 ----- .../TARGET_NRF52/source/nRF5xGattServer.h | 167 - .../source/nRF5xPalGattClient.cpp | 1681 --------- .../TARGET_NRF52/source/nRF5xPalGattClient.h | 257 -- .../source/nRF5xPalSecurityManager.h | 380 --- .../TARGET_NRF52/source/nRF5xn.cpp | 255 -- .../TARGET_NRF52/source/nRF5xn.h | 156 - .../TARGET_NRF52/source/projectconfig.h | 136 - .../source/supress-warnings.cmake | 21 - .../TARGET_NRF5x/NRFCordioHCIDriver.cpp | 324 ++ .../TARGET_NRF5x/NRFCordioHCIDriver.h | 86 + .../NRFCordioHCITransportDriver.cpp | 68 + .../NRFCordioHCITransportDriver.h | 66 + .../TARGET_NORDIC/TARGET_NRF5x/README.md | 17 + .../cordio_stack/libcordio_stack_nordic.a | Bin 0 -> 56836 bytes .../platform/nordic/include/bb_drv_nordic.h | 54 + .../platform/nordic/include/platform_btn.h | 74 + .../platform/nordic/include/platform_nordic.h | 89 + .../nordic/sources/bb/ble/bb_ble_int.h | 48 + .../TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json | 6 + targets/targets.json | 10 +- 121 files changed, 20589 insertions(+), 7069 deletions(-) create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_op.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_pdufilt.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_periodiclist.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_reslist.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_whitelist.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/lhci_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_init_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_tester_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/sch_api_ble.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/bb_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac_ble.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/sch_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/bb/bb_ble_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn_cs2.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_phy.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_priv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_sc.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_conn.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_priv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_sc.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_slave.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_slave.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_master_phy.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_priv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_slave_phy.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_tester.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv_ae.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_conn.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lhci/lhci_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/sch/sch_int_rm.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/bb/bb_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/sch/sch_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/libcordio_stack.a create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_154_drv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_ble_drv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_drv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_drv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr_serial.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/hci_defs.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_defs.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_math.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_154_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_ble_api.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/prand.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/radio_drv.h create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/LICENSE.txt create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/README.txt create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/asm_arm.inc create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.c create mode 100644 features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/CHANGELOG.md delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/LICENSE delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/apache-2.0.txt delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/module.json delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle_clock.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ansi_escape.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/assertion.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/binary.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ble_error.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/common.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/compiler.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.cpp delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/projectconfig.h delete mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/supress-warnings.cmake create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.cpp create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/libcordio_stack_nordic.a create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h create mode 100644 features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json diff --git a/features/FEATURE_BLE/ble/pal/GapEvents.h b/features/FEATURE_BLE/ble/pal/GapEvents.h index 28623eb3f4..8e0bb0dd78 100644 --- a/features/FEATURE_BLE/ble/pal/GapEvents.h +++ b/features/FEATURE_BLE/ble/pal/GapEvents.h @@ -306,7 +306,7 @@ struct GapAdvertisingReportEvent : public GapEvent { struct advertising_t { received_advertising_type_t type; connection_peer_address_type_t address_type; - const address_t& address; + address_t address; ArrayView data; int8_t rssi; }; diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api.h new file mode 100644 index 0000000000..f2a833aceb --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api.h @@ -0,0 +1,487 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_H +#define BB_BLE_API_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE + * \{ */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising packet statistics. */ +typedef struct +{ + uint32_t txAdv; /*!< Number of sent advertising packets. */ + uint32_t rxReq; /*!< Number of successfully received advertising requests. */ + uint32_t rxReqCrc; /*!< Number of received advertising requests with CRC errors. */ + uint32_t rxReqTimeout; /*!< Number of timed out received advertising requests (receive timeout). */ + uint32_t txRsp; /*!< Number of sent response packets. */ + uint32_t errAdv; /*!< Number of advertising transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBleAdvPktStats_t; + +/*! \brief Auxiliary advertising packet statistics. */ +typedef struct +{ + uint32_t txAdv; /*!< Number of sent advertising packets. */ + uint32_t rxReq; /*!< Number of successfully received advertising requests. */ + uint32_t rxReqCrc; /*!< Number of received advertising requests with CRC errors. */ + uint32_t rxReqTimeout; /*!< Number of timed out received advertising requests (receive timeout). */ + uint32_t txRsp; /*!< Number of sent response packets. */ + uint32_t txChain; /*!< Number of sent chain packets. */ + uint32_t errAdv; /*!< Number of advertising transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBleAuxAdvPktStats_t; + +/*! \brief Scan packet statistics. */ +typedef struct +{ + uint32_t rxAdv; /*!< Number of successfully received advertising packets. */ + uint32_t rxAdvCrc; /*!< Number of received advertising packets with CRC errors. */ + uint32_t rxAdvTimeout; /*!< Number of timed out advertising packets (receive timeout). */ + uint32_t txReq; /*!< Number of sent advertising requests. */ + uint32_t rxRsp; /*!< Number of successfully received advertising response packets. */ + uint32_t rxRspCrc; /*!< Number of received advertising response packets with CRC errors. */ + uint32_t rxRspTimeout; /*!< Number of timed out advertising response packets (receive timeout). */ + uint32_t errScan; /*!< Number of scan transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBleScanPktStats_t; + +/*! \brief Scan packet statistics. */ +typedef struct +{ + uint32_t rxAdv; /*!< Number of successfully received advertising packets. */ + uint32_t rxAdvCrc; /*!< Number of received advertising packets with CRC errors. */ + uint32_t rxAdvTimeout; /*!< Number of timed out advertising packets (receive timeout). */ + uint32_t txReq; /*!< Number of sent advertising requests. */ + uint32_t rxRsp; /*!< Number of successfully received advertising response packets. */ + uint32_t rxRspCrc; /*!< Number of received advertising response packets with CRC errors. */ + uint32_t rxRspTimeout; /*!< Number of timed out advertising response packets (receive timeout). */ + uint32_t rxChain; /*!< Number of successfully received chain packets. */ + uint32_t rxChainCrc; /*!< Number of received chain packets with CRC errors. */ + uint32_t rxChainTimeout; /*!< Number of timed out chain packets (receive timeout). */ + uint32_t errScan; /*!< Number of scan transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBleAuxScanPktStats_t; + +/*! \brief Periodic scan packet statistics. */ +typedef struct +{ + uint32_t rxAdv; /*!< Number of successfully received advertising packets. */ + uint32_t rxAdvCrc; /*!< Number of received advertising packets with CRC errors. */ + uint32_t rxAdvTimeout; /*!< Number of timed out advertising packets (receive timeout). */ + uint32_t rxChain; /*!< Number of successfully received chain packets. */ + uint32_t rxChainCrc; /*!< Number of received chain packets with CRC errors. */ + uint32_t rxChainTimeout; /*!< Number of timed out chain packets (receive timeout). */ + uint32_t errScan; /*!< Number of scan transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBlePerScanPktStats_t; + +/*! \brief Data packet statistics. */ +typedef struct +{ + uint32_t rxData; /*!< Number of successfully received data packets. */ + uint32_t rxDataCrc; /*!< Number of received data packets with CRC errors. */ + uint32_t rxDataTimeout; /*!< Number of timed out data packets (receive timeout). */ + uint32_t txData; /*!< Number of sent data packets. */ + uint32_t errData; /*!< Number of data transaction errors. */ + uint16_t rxSetupUsec; /*!< Rx packet setup watermark in microseconds. */ + uint16_t txSetupUsec; /*!< Tx packet setup watermark in microseconds. */ + uint16_t rxIsrUsec; /*!< Rx ISR processing watermark in microseconds. */ + uint16_t txIsrUsec; /*!< Tx ISR processing watermark in microseconds. */ +} BbBleDataPktStats_t; + +/*! \brief PDU filtering statistics. */ +typedef struct +{ + uint16_t failPduTypeFilt; /*!< Number of PDUs failing PDU type filter. */ + uint16_t passPduTypeFilt; /*!< Number of PDUs passing PDU type filter. */ + uint16_t failWlFilt; /*!< Number of PDUs failing whitelist filter. */ + uint16_t passWlFilt; /*!< Number of PDUs passing whitelist filter. */ + uint16_t failPeerAddrMatch; /*!< Number of PDUS failing peer address match. */ + uint16_t passPeerAddrMatch; /*!< Number of PDUs passing peer address match. */ + uint16_t failLocalAddrMatch; /*!< Number of PDUS failing local address match. */ + uint16_t passLocalAddrMatch; /*!< Number of PDUs passing local address match. */ + uint16_t failPeerRpaVerify; /*!< Number of peer RPAs failing verification. */ + uint16_t passPeerRpaVerify; /*!< Number of peer RPAs passing verification. */ + uint16_t failLocalRpaVerify; /*!< Number of local RPAs failing verification. */ + uint16_t passLocalRpaVerify; /*!< Number of local RPAs passing verification. */ + uint16_t failPeerPrivAddrReq; /*!< Number of peer addresses failing requirement to be RPAs. */ + uint16_t failLocalPrivAddrReq; /*!< Number of local addresses failing requirement to be RPAs. */ + uint16_t failPeerAddrResReq; /*!< Number of PDUs failing required peer address resolution. */ + uint16_t passPeerAddrResOpt; /*!< Number of PDUs passing optional peer address resolution. */ + uint16_t passLocalAddrResOpt; /*!< Number of PDUs passing optional local address resolution. */ + uint16_t peerResAddrPend; /*!< Number of peer address resolutions pended. */ + uint16_t localResAddrPend; /*!< Number of local address resolutions pended. */ +} BbBlePduFiltStats_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Initialize the BLE BB. + * + * \return None. + * + * Initialize baseband resources. + */ +/*************************************************************************************************/ +void BbBleInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for scanning master operations. + * + * \return None. + * + * Update the operation table with scanning master operations routines. + */ +/*************************************************************************************************/ +void BbBleScanMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for auxiliary scanning master operations. + * + * \return None. + * + * Update the operation table with auxiliary scanning master operations routines. + */ +/*************************************************************************************************/ +void BbBleAuxScanMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for periodic scanning master operations. + * + * \return None. + * + * Update the operation table with periodic scanning master operations routines. + */ +/*************************************************************************************************/ +void BbBlePerScanMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for connectable master operations. + * + * \return None. + * + * Update the operation table with connectable master operations routines. + */ +/*************************************************************************************************/ +void BbBleConnMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for advertising slave operations. + * + * \return None. + * + * Update the operation table with advertising slave operations routines. + */ +/*************************************************************************************************/ +void BbBleAdvSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for auxiliary advertising slave operations. + * + * \return None. + * + * Update the operation table with auxiliary advertising slave operations routines. + */ +/*************************************************************************************************/ +void BbBleAuxAdvSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for connectable slave operations. + * + * \return None. + * + * Update the operation table with connectable slave operations routines. + */ +/*************************************************************************************************/ +void BbBleConnSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize for test operations. + * + * \return None. + * + * Update the operation table with test operations routines. + */ +/*************************************************************************************************/ +void BbBleTestInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize white list. + * + * \param numEntries Number of white list entries to provide. + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function initializes the white list. + * + * \note This function must be called once before initializing the LL. + */ +/*************************************************************************************************/ +uint16_t BbBleInitWhiteList(uint8_t numEntries, uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Initialize resolving list. + * + * \param numEntries Number of resolving list entries to provide. + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function initializes the resolving list. + * + * \note This function must be called once before initializing the LL. + */ +/*************************************************************************************************/ +uint16_t BbBleInitResolvingList(uint8_t numEntries, uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Initialize periodic list. + * + * \param numEntries Number of periodic list entries to provide. + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function initializes the periodic list. + * + * \note This function must be called once before initializing the LL. + */ +/*************************************************************************************************/ +uint16_t BbBleInitPeriodicList(uint8_t numEntries, uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Get transmit RF path compensation. + * + * \return Transmit RF path compensation (in 1-dBm units). + */ +/*************************************************************************************************/ +int8_t BbBleRfGetTxRfPathComp(void); + +/*************************************************************************************************/ +/*! + * \brief Get receive RF path compensation. + * + * \return Transmit RF path compensation (in 1-dBm units). + */ +/*************************************************************************************************/ +int8_t BbBleRfGetRxRfPathComp(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize RF path compensation. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleInitRfPathComp(void); + +/*************************************************************************************************/ +/*! + * \brief Get advertising packet statistics. + * + * \param pStats Advertising statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetAdvStats(BbBleAdvPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get scan packet statistics. + * + * \param pStats Scan statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetScanStats(BbBleScanPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get auxiliary advertising packet statistics. + * + * \param pStats Auxiliary advertising statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetAuxAdvStats(BbBleAuxAdvPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get auxiliary scan packet statistics. + * + * \param pStats Auxiliary scan statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetAuxScanStats(BbBleAuxScanPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get periodic scan packet statistics. + * + * \param pStats Periodic scan statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetPerScanStats(BbBlePerScanPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get connection packet statistics. + * + * \param pStats Connection data statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetConnStats(BbBleDataPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get test mode packet statistics. + * + * \param pStats Test data statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetTestStats(BbBleDataPktStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get PDU filter statistics. + * + * \param pStats PDU filter statistics. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleGetPduFiltStats(BbBlePduFiltStats_t *pStats); + +/*************************************************************************************************/ +/*! + * \brief Get supported transmit power. + * + * \param pMinTxPwr Return buffer for minimum transmit power (expressed in 1dBm units). + * \param pMaxTxPwr Return buffer for maximum transmit power (expressed in 1dBm units). + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleRfGetSupTxPower(int8_t *pMinTxPwr, int8_t *pMaxTxPwr); + +/*************************************************************************************************/ +/*! + * \brief Read RF path compensation. + * + * \param pTxPathComp Return buffer for RF transmit path compensation value (expressed in 0.1dBm units). + * \param pRxPathComp Return buffer for RF receive path compensation value (expressed in 0.1dBm units). + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleRfReadRfPathComp(int16_t *pTxPathComp, int16_t *pRxPathComp); + +/*************************************************************************************************/ +/*! + * \brief Set RF path compensation. + * + * \param txPathComp RF transmit path compensation value (expressed in 0.1dBm units). + * \param rxPathComp RF receive path compensation value (expressed in 0.1dBm units). + * + * \return TRUE if successful, FALSE otherwise. + */ +/*************************************************************************************************/ +bool_t BbBleRfWriteRfPathComp(int16_t txPathComp, int16_t rxPathComp); + +/*************************************************************************************************/ +/*! + * \brief Get the actual Tx power at the antenna (expressed in 1dBm units). + * + * \param txPwr Tx power provided by the host (expressed in 1dBm units). + * \param compFlag Flag to apply Tx path compensation or not. + * + * \return Actual Tx power at the antenna (expressed in 1dBm units). + * + * Tx path compensation is only used for extended ADV header. + * Compensation is not considered when filling in HCI events. + */ +/*************************************************************************************************/ +int8_t BbBleRfGetActualTxPower(int8_t txPwr, bool_t compFlag); + +/*! \} */ /* BB_API_BLE */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_op.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_op.h new file mode 100644 index 0000000000..82565ba15d --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_op.h @@ -0,0 +1,353 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_OP_H +#define BB_BLE_API_OP_H + +#include "bb_api.h" +#include "bb_ble_drv.h" +#include "bb_ble_api_pdufilt.h" +#include "ll_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE + * \{ */ + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Convert BLE protocol ticks to BB ticks. */ +#define BB_BLE_TO_BB_TICKS(n) BB_US_TO_BB_TICKS((n) * LL_BLE_US_PER_TICK) + +/*! \brief Increment statistics counter. */ +#define BB_INC_STAT(s) s++ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Operation types. */ +enum +{ + BB_BLE_OP_TEST_TX, /*!< Continuous Tx test mode. */ + BB_BLE_OP_TEST_RX, /*!< Continuous Rx test mode. */ + BB_BLE_OP_MST_ADV_EVENT, /*!< Master advertising event. */ + BB_BLE_OP_SLV_ADV_EVENT, /*!< Slave advertising event. */ + BB_BLE_OP_MST_CONN_EVENT, /*!< Master connection event. */ + BB_BLE_OP_SLV_CONN_EVENT, /*!< Slave connection event. */ + BB_BLE_OP_MST_AUX_ADV_EVENT, /*!< Master auxiliary advertising event. */ + BB_BLE_OP_SLV_AUX_ADV_EVENT, /*!< Slave auxiliary advertising event. */ + BB_BLE_OP_SLV_PER_ADV_EVENT, /*!< Slave periodic advertising event. */ + BB_BLE_OP_MST_PER_SCAN_EVENT, /*!< Master periodic scanning event. */ + BB_BLE_OP_NUM /*!< Total number of operations. */ +}; + +/*! \brief Maximum request PDU length (MAX(LL_SCAN_REQ_PDU_LEN, LL_CONN_IND_PDU_LEN)). */ +#define BB_REQ_PDU_MAX_LEN (LL_ADV_HDR_LEN + LL_CONN_IND_PDU_LEN) + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Pre-execute callback signature. */ +typedef void (*BbBlePreExec_t)(BbOpDesc_t *pBod); + +/*! \brief Execute callback signature. */ +typedef void (*BbBleExec_t)(BbOpDesc_t *pBod); + +/*! \brief Cancel callback signature. */ +typedef void (*BbBleCancel_t)(BbOpDesc_t *pBod); + +/*! \brief Advertising PDU transmit setup call signature. */ +typedef void (*BbBleTxAdvSetup_t)(BbOpDesc_t *pBod, uint32_t advTxTime); + +/*! \brief Chain indication PDU transmit setup call signature. */ +typedef uint32_t (*BbBleTxAuxSetup_t)(BbOpDesc_t *pBod, bool_t isChainInd); + +/*! \brief Returns TRUE if an scan request/response required. */ +typedef bool_t (*BbBleAdvComp_t)(BbOpDesc_t *pBod, const uint8_t *pBuf); + +/*! \brief Rx completion post processing call signature. */ +typedef void (*BbBleAdvPost_t)(BbOpDesc_t *pBod, const uint8_t *pBuf); + +/*! \brief Chain indication PDU received call signature. */ +typedef uint32_t (*BbBleRxChain_t)(BbOpDesc_t *pBod, const uint8_t *pBuf); + +/*! \brief Chain indication PDU received post call signature. */ +typedef bool_t (*BbBleRxChainPost_t)(BbOpDesc_t *pBod, const uint8_t *pBuf); + +/*! \brief Data transmit completion callback signature. */ +typedef void (*BbBleTxDataComp_t)(BbOpDesc_t *pBod, uint8_t status); + +/*! \brief Data receive completion callback signature. */ +typedef void (*BbBleRxDataComp_t)(BbOpDesc_t *pBod, uint8_t *pBuf, uint8_t status); + +/*! \brief Test completion callback signature. */ +typedef bool_t (*BbBleTestComp_t)(BbOpDesc_t *pBod, uint8_t status); + +/*! \brief Periodic PDU Rx complete call signature. */ +typedef uint32_t (*BbBlePerComp_t)(BbOpDesc_t *pBod, const uint8_t *pBuf, uint8_t status); + +/*! \brief Periodic PDU Rx complete post call signature. */ +typedef bool_t (*BbBlePerPostComp_t)(BbOpDesc_t *pBod, const uint8_t *pBuf); + +/*! + * \brief Master advertising event operation data (\ref BB_BLE_OP_MST_ADV_EVENT). + * + * \note BB assumes maximum adversing and scan response payload is 39 bytes. + */ +typedef struct +{ + uint8_t *pRxAdvBuf; /*!< Advertising buffer. */ + uint8_t *pTxReqBuf; /*!< Scan request buffer. */ + uint8_t *pRxRspBuf; /*!< Scan response buffer. */ + + BbBlePreExec_t preExecCback; /*!< Pre-execute callback. */ + BbBleAdvComp_t rxAdvCback; /*!< Advertising completion callback. */ + BbBleAdvPost_t rxAdvPostCback; /*!< Advertising completion post processing callback. */ + BbBleAdvComp_t txReqCback; /*!< Scan request completion callback. */ + BbBleAdvComp_t rxRspCback; /*!< Scan response completion callback. */ + + uint8_t txReqLen; /*!< Scan request buffer length. */ + + uint8_t scanChMap; /*!< Scan channel map. */ + + /* Return parameters. */ + int8_t advRssi; /*!< RSSI of advertisement. */ + uint8_t advRxPhyOptions; /*!< Rx PHY options. */ + uint32_t advCrc; /*!< CRC of advertisement. */ + uint32_t advStartTs; /*!< Start of advertising packet timestamp. */ + uint32_t elapsedUsec; /*!< Elapsed time of a single scan window in microseconds. */ + + /* Filter results. */ + bbBlePduFiltResults_t filtResults; /*!< Results from PDU filtering. */ +} BbBleMstAdvEvent_t; + +/*! + * \brief Slave advertising event operation data (\ref BB_BLE_OP_SLV_ADV_EVENT). + * + * \note BB assumes maximum scan request payload is 39 bytes. + */ +typedef struct +{ + uint8_t *pTxAdvBuf; /*!< Advertising buffer. */ + uint8_t *pRxReqBuf; /*!< Scan request buffer (must be size of BB_REQ_PDU_MAX_LEN). */ + uint8_t *pTxRspBuf; /*!< Scan response buffer. */ + + BbBleTxAdvSetup_t txAdvSetupCback; /*!< Adv PDU transmit setup callback. */ + BbBleAdvComp_t rxReqCback; /*!< Scan/Connect request receive completion callback. */ + BbBleAdvPost_t rxReqPostCback; /*!< Scan/Connect request receive post processing callback. */ + + uint8_t txAdvLen; /*!< Advertising buffer length. */ + uint8_t txRspLen; /*!< Scan response buffer length. */ + + uint8_t advChMap; /*!< Advertising channel map. */ + + /* Return parameters. */ + uint32_t reqStartTs; /*!< Start of request packet timestamp. */ + + /* Filter results. */ + bbBlePduFiltResults_t filtResults; /*!< Results from PDU filtering. */ +} BbBleSlvAdvEvent_t; + +/*! \brief Master auxiliary advertising event operation data (\ref BB_BLE_OP_MST_AUX_ADV_EVENT). */ +typedef struct +{ + uint8_t *pTxAuxReqBuf; /*!< Scan request buffer. */ + + BbBleAdvComp_t rxAuxAdvCback; /*!< Advertising completion callback. */ + BbBleAdvComp_t rxAuxRspCback; /*!< Scan response completion callback. */ + BbBleRxChain_t rxAuxChainCback; /*!< Chain completion callback. */ + BbBleRxChainPost_t rxAuxChainPostCback;/*!< Chain completion post callback. */ + + uint8_t txAuxReqLen; /*!< Scan request buffer length. */ + + uint32_t rxSyncDelayUsec; /*!< Receive timeout in microseconds. */ + bool_t isInit; /*!< TRUE if the event is for an initiation. */ + + /* Return parameters. */ + int8_t auxAdvRssi; /*!< RSSI of advertisement. */ + uint8_t auxRxPhyOptions; /*!< Rx PHY options. */ + uint32_t auxAdvCrc; /*!< CRC of advertisement. */ + uint32_t auxStartTs; /*!< Start of auxiliary advertising packet timestamp. */ + + /* Filter results. */ + bbBlePduFiltResults_t filtResults; /*!< Results from PDU filtering. */ +} BbBleMstAuxAdvEvent_t; + +/*! \brief Master periodic scanning event operation data (\ref BB_BLE_OP_MST_PER_SCAN_EVENT). */ +typedef struct +{ + BbBlePerComp_t rxPerAdvCback; /*!< Periodic scanning completion callback. */ + BbBlePerPostComp_t rxPerAdvPostCback; /*!< Periodic scanning completion post callback. */ + uint32_t rxSyncDelayUsec; /*!< Receive timeout in microseconds. */ + + /* Return parameters. */ + uint8_t rxStatus; /*!< RX status. */ + int8_t perAdvRssi; /*!< RSSI of advertisement. */ + uint8_t perRxPhyOptions; /*!< Rx PHY options. */ + uint32_t perAdvCrc; /*!< CRC of advertisement. */ + uint32_t perStartTs; /*!< Start of periodic advertising packet timestamp. */ + bool_t perIsFirstTs; /*!< True if it is the first timestamp for a serial of periodic packets. */ + +} BbBleMstPerScanEvent_t; + +/*! \brief Slave auxiliary advertising event operation data (\ref BB_BLE_OP_SLV_AUX_ADV_EVENT). */ +typedef struct +{ + /* TODO BbBleSlvAuxAdvEvent_t hide buffer descriptors in BB layer. */ + BbBleDrvTxBufDesc_t txAuxAdvPdu[2]; /*!< Advertising PDU descriptor. */ + uint8_t *pRxAuxReqBuf; /*!< Auxiliary request buffer (must be size of BB_REQ_PDU_MAX_LEN). */ + BbBleDrvTxBufDesc_t txAuxRspPdu[2]; /*!< Response PDU descriptor. */ + BbBleDrvTxBufDesc_t txAuxChainPdu[2]; /*!< Auxiliary chain PDU descriptor. */ + + BbBleAdvComp_t rxAuxReqCback; /*!< Auxiliary request receive completion callback. */ + BbBleAdvPost_t rxAuxReqPostCback; /*!< Auxiliary scan/connect request receive post processing callback. */ + BbBleTxAuxSetup_t txAuxSetupCback; /*!< Auxiliary chain indication setup callback. */ + + uint8_t auxAdvCh; /*!< Advertising channel map. */ + + /* Return parameters. */ + uint8_t auxRxPhyOptions; /*!< Rx PHY options. */ + uint32_t auxReqStartTs; /*!< Start of request packet timestamp. */ + + /* Filter results. */ + bbBlePduFiltResults_t filtResults; /*!< Results from PDU filtering. */ +} BbBleSlvAuxAdvEvent_t; + +/*! \brief Connection event operation data (\ref BB_BLE_OP_MST_CONN_EVENT). */ +typedef struct +{ + BbBleExec_t execCback; /*!< Execute callback. */ + BbBleCancel_t cancelCback; /*!< Cancel callback. */ + BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */ + BbBleRxDataComp_t rxDataCback; /*!< Receive completion callback. */ + + /* Return parameters. */ + int8_t rssi; /*!< RSSI of the last received packet. */ + uint8_t rxPhyOptions; /*!< Rx PHY options. */ +} BbBleMstConnEvent_t; + +/*! \brief Connection event operation data (\ref BB_BLE_OP_SLV_CONN_EVENT). */ +typedef struct +{ + uint32_t rxSyncDelayUsec; /*!< Receive timeout in microseconds. */ + BbBleExec_t execCback; /*!< Execute callback. */ + BbBleCancel_t cancelCback; /*!< Cancel callback. */ + BbBleTxDataComp_t txDataCback; /*!< Transmit completion callback. */ + BbBleRxDataComp_t rxDataCback; /*!< Receive completion callback. */ + + /* Return parameters. */ + uint32_t startTs; /*!< Start timestamp of the first received packet. */ + int8_t rssi; /*!< RSSI of the last received packet. */ + uint8_t rxPhyOptions; /*!< Rx PHY options. */ +} BbBleSlvConnEvent_t; + +/*! \brief Continuous transmit operation data (\ref BB_BLE_OP_TEST_TX). */ +typedef struct +{ + BbBleTestComp_t testCback; /*!< Test callback. */ + + uint8_t *pTxBuf; /*!< Transmit data buffer. */ + uint16_t txLen; /*!< Transmit data buffer length. */ + uint16_t pktInterUsec; /*!< Transmit packet interval. */ +} BbBleTestTx_t; + +/*! \brief Continuous receive operation data (\ref BB_BLE_OP_TEST_RX). */ +typedef struct +{ + uint32_t rxSyncDelayUsec; /*!< Synchronization delay in microseconds. */ + BbBleTestComp_t testCback; /*!< Test callback. */ + + uint8_t *pRxBuf; /*!< Receive data buffer. */ + uint16_t rxLen; /*!< Receive data buffer length. */ +} BbBleTestRx_t; + +/*! \brief Bluetooth Low Energy protocol specific operation parameters. */ +typedef struct BbBleData_tag +{ + BbBleDrvChan_t chan; /*!< Channelization parameters. */ + bbBlePduFiltParams_t pduFilt; /*!< PDU filter parameters. */ + + union + { + BbBleMstAdvEvent_t mstAdv; /*!< Master advertising event data. */ + BbBleSlvAdvEvent_t slvAdv; /*!< Slave advertising event data. */ + BbBleMstAuxAdvEvent_t mstAuxAdv; /*!< Master auxiliary advertising event data. */ + BbBleSlvAuxAdvEvent_t slvAuxAdv; /*!< Slave auxiliary advertising event data. */ + BbBleSlvAuxAdvEvent_t slvPerAdv; /*!< Slave periodic advertising event data. */ + BbBleMstConnEvent_t mstConn; /*!< Master connection event data. */ + BbBleMstPerScanEvent_t mstPerScan; /*!< Master periodic scanning event data. */ + BbBleSlvConnEvent_t slvConn; /*!< Slave connection event data. */ + BbBleTestTx_t testTx; /*!< Transmit test data. */ + BbBleTestRx_t testRx; /*!< Receive test data. */ + } op; /*!< Operation specific data. */ +} BbBleData_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Transmit data PDU at next transmit slot. + * + * \param descs Array of transmit buffer descriptor. + * \param cnt Number of descriptors. + * + * \return None. + * + * \note This function is expected to be called during the call context of + * \ref BbBleSlvConnEvent_t::rxDataCback callback routine. + */ +/*************************************************************************************************/ +void BbBleTxData(BbBleDrvTxBufDesc_t descs[], uint8_t cnt); + +/*************************************************************************************************/ +/*! + * \brief Set receive data buffer for next receive slot. + * + * \param pBuf Receive data buffer. + * \param len Maximum length of data buffer. + * + * \return None. + * + * \note This function is expected to be called during the call context of + * \ref BbBleSlvConnEvent_t::rxDataCback callback routine. + * + * \note BB must always call the BbSlvConnEvent_t::rxDataCback callback routine of the + * currently executing BOD with the given buffer. + */ +/*************************************************************************************************/ +void BbBleRxData(uint8_t *pBuf, uint16_t len); + +/*! \} */ /* BB_API_BLE */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_OP_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_pdufilt.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_pdufilt.h new file mode 100644 index 0000000000..74aeabff7a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_pdufilt.h @@ -0,0 +1,188 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband PDU filtering interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_PDUFILT_H +#define BB_BLE_API_PDUFILT_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE_PDU_FILT + * \{ */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Check whether a flag is set. */ +#define BB_BLE_PDU_FILT_FLAG_IS_SET(pFilt, flag) (((pFilt)->flags & BB_BLE_PDU_FILT_FLAG_##flag) != 0) + +/*! \brief Check whether a flag is clear. */ +#define BB_BLE_PDU_FILT_SET_FLAG(pFilt, flag) (pFilt)->flags |= BB_BLE_PDU_FILT_FLAG_##flag; + +/*! \brief PDU filtering flags. */ +enum +{ + /* Common flags. */ + BB_BLE_PDU_FILT_FLAG_LOCAL_ADDR_MATCH_ENA = (1 << 0), /*!< Local address should be matched. */ + BB_BLE_PDU_FILT_FLAG_LOCAL_ADDR_MATCH_RAND = (1 << 1), /*!< Local address to match is a random address. */ + BB_BLE_PDU_FILT_FLAG_PEER_ADDR_MATCH_ENA = (1 << 2), /*!< Peer address should be matched. */ + BB_BLE_PDU_FILT_FLAG_PEER_ADDR_MATCH_RAND = (1 << 3), /*!< Peer address to match is a random address. */ + + /* Privacy flags. */ + BB_BLE_PDU_FILT_FLAG_LOCAL_ADDR_RES_ENA = (1 << 4), /*!< Local address resolution is enabled. */ + BB_BLE_PDU_FILT_FLAG_LOCAL_ADDR_RES_OPT = (1 << 5), /*!< Local address resolution is optional. */ + BB_BLE_PDU_FILT_FLAG_PEER_ADDR_RES_ENA = (1 << 6), /*!< Peer address resolution is enabled. */ +}; + +/*! \brief Periodic PDU filtering parameters. */ +typedef struct +{ + uint8_t filterPolicy; /*!< Filter policy. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint64_t advAddr; /*!< Advertiser Address. */ +} bbBlePerPduFiltParams_t; + +/*! \brief PDU filtering parameters. */ +typedef struct +{ + uint16_t pduTypeFilt; /*!< Bit map of the PDUs the BB should allow. */ + uint16_t wlPduTypeFilt; /*!< Bit map of the PDUs the BB should pass through the whitelist. */ + uint32_t flags; /*!< Flags for PDU filtering. */ + uint64_t localAddrMatch; /*!< Local address to match. */ + uint64_t peerAddrMatch; /*!< Peer address to match. */ +} bbBlePduFiltParams_t; + +/*! \brief Extended PDU filtering parameters. */ +typedef struct +{ + uint64_t peerAddr; /*!< Peer address. */ + uint64_t localAddr; /*!< Local address. */ + uint8_t pduType; /*!< PDU type. */ + uint8_t extHdrFlags; /*!< Extended header flags. */ + bool_t peerAddrRand; /*!< TRUE if peer address is random, FALSE otherwise. */ + bool_t localAddrRand; /*!< TRUE if local address is random, FALSE otherwise. */ +} bbBlePduExtFiltParams_t; + +/*! \brief PDU filtering results. */ +typedef struct +{ + uint64_t peerAddr; /*!< Peer address. */ + uint64_t peerIdAddr; /*!< Peer ID address. */ + uint8_t pduType; /*!< PDU type. */ + uint8_t pduLen; /*!< PDU length. */ + bool_t peerAddrRand; /*!< TRUE if peer address is random. */ + bool_t peerIdAddrRand; /*!< TRUE if peer ID address is random. */ + bool_t peerMatch; /*!< TRUE if peer address was resolved or matched. */ + bool_t localMatch; /*!< TRUE if local address was resolved or matched. */ +} bbBlePduFiltResults_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Check if PDU is allowed, i.e., should not be ignored. + * + * \param pBuf PDU buffer. + * \param pFiltParams Filter parameters. + * \param forceRes TRUE if address resolution should be forced. + * \param pFiltResults Storage for filter results. + * + * \return TRUE if PDU is allowed, FALSE if PDU should be ignored. + */ +/*************************************************************************************************/ +bool_t BbBlePduFiltCheck(const uint8_t *pBuf, const bbBlePduFiltParams_t *pFiltParams, + bool_t forceRes, bbBlePduFiltResults_t *pFiltResults); + +/*************************************************************************************************/ +/*! + * \brief Check if PDU is allowed, i.e., should not be ignored. + * + * \param pExtFiltParams Extended filter parameters. + * \param pFiltParams Filter parameters. + * \param forceRes TRUE if address resolution should be forced. + * \param pFiltResults Storage for filter results. + * + * \return TRUE if PDU is allowed, FALSE if PDU should be ignored. + */ +/*************************************************************************************************/ +bool_t BbBleExtPduFiltCheck(const bbBlePduExtFiltParams_t *pExtFiltParams, + const bbBlePduFiltParams_t *pFiltParams, + bool_t forceRes, bbBlePduFiltResults_t *pFiltResults); + +/*************************************************************************************************/ +/*! + * \brief Get the peer ID address. + * + * \param pFiltResults Filter results. + * \param pPeerIdAddr Storage for peer ID address. + * \param pPeerIdAddrType Storage for peer ID address type; + * + * \return None. + */ +/*************************************************************************************************/ +static inline void BbBlePduFiltResultsGetPeerIdAddr(const bbBlePduFiltResults_t *pFiltResults, uint64_t *pPeerIdAddr, uint8_t *pPeerIdAddrType) +{ + const unsigned int addrIdBit = 1 << 1; + + *pPeerIdAddrType = pFiltResults->peerIdAddrRand; + if ((pFiltResults->peerIdAddrRand != pFiltResults->peerAddrRand) || + (pFiltResults->peerIdAddr != pFiltResults->peerAddr)) + { + *pPeerIdAddrType |= addrIdBit; + } + *pPeerIdAddr = pFiltResults->peerIdAddr; +} + +/*************************************************************************************************/ +/*! + * \brief Get the peer RPA. + * + * \param pFiltResults Filter results. + * \param pPeerRpa Storage for peer RPA or 0. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void BbBlePduFiltResultsGetPeerRpa(const bbBlePduFiltResults_t *pFiltResults, uint64_t *pPeerRpa) +{ + *pPeerRpa = 0; + if ((pFiltResults->peerIdAddrRand != pFiltResults->peerAddrRand) || + (pFiltResults->peerIdAddr != pFiltResults->peerAddr)) + { + *pPeerRpa = pFiltResults->peerAddr; + } +} + +/*! \} */ /* BB_API_BLE_PDU_FILT */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_PDUFILT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_periodiclist.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_periodiclist.h new file mode 100644 index 0000000000..fd69538772 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_periodiclist.h @@ -0,0 +1,120 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband periodiclist interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_PERIODICLIST_H +#define BB_BLE_API_PERIODICLIST_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE_WL + * \{ */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Check if address is periodic listed. + * + * \param addrType Address type. + * \param addr Bluetooth device address. + * \param SID Set ID. + * + * \return TRUE if white listed, FALSE otherwise. + */ +/*************************************************************************************************/ +bool_t BbBlePeriodicListCheckAddr(uint8_t addrType, uint64_t addr, uint8_t SID); + +/*************************************************************************************************/ +/*! + * \brief Get periodic list size. + * + * \return Total number of periodic list entries. + * + * Read the periodic list capacity supported by the BB. + */ +/*************************************************************************************************/ +uint8_t BbBlePeriodicListGetSize(void); + +/*************************************************************************************************/ +/*! + * \brief Clear all periodic list entries. + * + * \return None. + * + * Clear all periodic list entries stored in the BB. + * + * \note No resource synchronization is required to modify the periodic list resource as + * the LL modifies the periodic list only when advertising events are disabled. + */ +/*************************************************************************************************/ +void BbBlePeriodicListClear(void); + +/*************************************************************************************************/ +/*! + * \brief Add device to the periodic list. + * + * \param addrType Address type. + * \param addr Bluetooth device address. + * \param SID Set ID. + * + * \return TRUE if successful, FALSE if list full. + * + * Adds the given address to the periodic list stored in the BB. + * + * \note No resource synchronization is required to modify the periodic list resource as + * the LL modifies the periodic list only when advertising events are disabled. + */ +/*************************************************************************************************/ +bool_t BbBlePeriodicListAdd(uint8_t addrType, uint64_t addr, uint8_t SID); + +/*************************************************************************************************/ +/*! + * \brief Remove device from the periodic list. + * + * \param randAddr TRUE if random address, FALSE if public. + * \param addr Bluetooth device address. + * \param SID Set ID. + * + * + * \return TRUE if successful, FALSE if address not in the list. + * + * Removes the given address from the periodic list stored in the BB. + * + * \note No resource synchronization is required to modify the white list resource as + * the LL modifies the white list only when advertising events are disabled. + */ +/*************************************************************************************************/ +bool_t BbBlePeriodicListRemove(bool_t randAddr, uint64_t addr, uint8_t SID); + +/*! \} */ /* BB_API_BLE_WL */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_WHITELIST_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_reslist.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_reslist.h new file mode 100644 index 0000000000..a4f4fe98a9 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_reslist.h @@ -0,0 +1,346 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband resolving list interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_RESLIST_H +#define BB_BLE_API_RESLIST_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE_RL + * \{ */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Resolvable address status. */ +enum +{ + BB_BLE_RESLIST_STATUS_ID_ADDR_NOT_IN_LIST, /*!< Identity address is not in list. */ + BB_BLE_RESLIST_STATUS_ZERO_IRK, /*!< IRK is zero for address. */ + BB_BLE_RESLIST_STATUS_RES_ADDR_UNASSIGNED, /*!< Resolvable address is unassigned. */ + BB_BLE_RESLIST_STATUS_RES_ADDR_ASSIGNED /*!< Resolvable address is assigned. */ +}; + +/*! \brief Privacy modes. */ +enum +{ + BB_BLE_RESLIST_PRIV_MODE_NETWORK = 0, /*!< Network privacy mode. */ + BB_BLE_RESLIST_PRIV_MODE_DEVICE = 1, /*!< Device privacy mode. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Address resolution needed callback signature. */ +typedef void (*bbBleResListAddrResNeeded_t)(uint64_t rpa, bool_t peer, uint8_t peerAddrType, uint64_t peerIdentityAddr); + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Set address resolution needed callback. + * + * \param cback Callback. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleResListSetAddrResNeededCback(bbBleResListAddrResNeeded_t cback); + +/*************************************************************************************************/ +/*! + * \brief Get resolving list size. + * + * \return Total number of resolving list entries. + * + * Get the resolving list capacity supported by the BB. + */ +/*************************************************************************************************/ +uint8_t BbBleResListGetSize(void); + +/*************************************************************************************************/ +/*! + * \brief Clear resolving list. + * + * \return None. + * + * Clear all resolving list entries stored in the BB. + */ +/*************************************************************************************************/ +void BbBleResListClear(void); + +/*************************************************************************************************/ +/*! + * \brief Add device to resolving list. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pPeerIrk Peer IRK. + * \param pLocalIrk Local IRK. + * + * \return TRUE if successful, FALSE if list full. + * + * Add device to resolving list. + */ +/*************************************************************************************************/ +bool_t BbBleResListAdd(uint8_t peerAddrType, uint64_t peerIdentityAddr, const uint8_t *pPeerIrk, + const uint8_t *pLocalIrk); + +/*************************************************************************************************/ +/*! + * \brief Remove device from resolving list. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * + * \return TRUE if successful, FALSE if address not in the list. + * + * Remove device from resolving list. + */ +/*************************************************************************************************/ +bool_t BbBleResListRemove(uint8_t peerAddrType, uint64_t peerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Set privacy mode of a device. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param privMode Privacy mode. + * + * \return TRUE if successful, FALSE if address not in the list. + * + * Set privacy mode of a device. + */ +/*************************************************************************************************/ +bool_t BbBleResListSetPrivacyMode(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint8_t privMode); + +/*************************************************************************************************/ +/*! + * \brief Get privacy mode of a device. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pPrivMode Storage for privacy mode. + * + * \return TRUE if successful, FALSE if address not in the list. + * + * Get privacy mode of a device. + */ +/*************************************************************************************************/ +bool_t BbBleResListGetPrivacyMode(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint8_t *pPrivMode); + +/*************************************************************************************************/ +/*! + * \brief Read peer resolvable address. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pRpa Storage for peer resolvable private address + * + * \return TRUE if successful, FALSE if address not in list. + * + * Get the peer resolvable private address that is currently being used for the peer identity + * address. + */ +/*************************************************************************************************/ +bool_t BbBleResListReadPeer(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint64_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Read local resolvable address. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pRpa Storage for peer resolvable private address + * + * \return TRUE if successful, FALSE if address not in list. + * + * Get the local resolvable private address that is currently being used for the peer identity + * address. + */ +/*************************************************************************************************/ +bool_t BbBleResListReadLocal(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint64_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Update local resolvable address. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pRpa Storage for local resolvable private address + * + * \return TRUE if successful, FALSE if address not in list. + * + * Update the local resolvable private address that is currently being used for the peer identity + * address. + */ +/*************************************************************************************************/ +bool_t BbBleResListUpdateLocal(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint64_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Generate peer resolvable address. + * + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * \param pRpa Storage for peer resolvable private address. + * + * \return TRUE if successful, FALSE if address not in list or peer IRK is zero. + * + * Generate a peer resolvable address for a peer. + */ +/*************************************************************************************************/ +bool_t BbBleResListGeneratePeer(uint8_t peerAddrType, uint64_t peerIdentityAddr, uint64_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Check whether a peer address has been resolved. + * + * \param rpa Peer resolvable private address + * \param pPeerAddrType Storage for peer identity address type. + * \param pPeerIdentityAddr Storage for peer identity address. + * + * \return TRUE if successful, FALSE if address has not been resolved. + * + * Check whether a peer address has been resolved. Because of timing constraints, addresses should + * not be resolved in this function; instead, the resolution callback should be invoked to schedule + * the operation later. + */ +/*************************************************************************************************/ +bool_t BbBleResListCheckResolvePeer(uint64_t rpa, uint8_t *pPeerAddrType, uint64_t *pPeerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Check whether a local address has been resolved. + * + * \param rpa Local resolvable private address + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * + * \return TRUE if successful, FALSE if address has not been resolved. + * + * Check whether a local address has been resolved. Because of timing constraints, addresses should + * not be resolved in this function; instead, the resolution callback should be invoked to schedule + * the operation later. + */ +/*************************************************************************************************/ +bool_t BbBleResListCheckResolveLocal(uint64_t rpa, uint8_t peerAddrType, uint64_t peerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Check whether a local address has been resolved. + * + * \param rpa Local resolvable private address + * \param peerAddrType Peer identity address type. + * \param peerIdentityAddr Peer identity address. + * + * \return TRUE if successful, FALSE if address has not been resolved. + * + */ +/*************************************************************************************************/ +bool_t BbBleResListIsLocalResolved(uint64_t rpa, uint8_t peerAddrType, uint64_t peerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Resolve peer resolvable address. + * + * \param rpa Peer resolvable private address + * \param pPeerAddrType Storage for peer identity address type. + * \param pPeerIdentityAddr Storage for peer identity address. + * + * \return TRUE if successful, FALSE if address could not be resolved. + * + * Resolve a peer resolvable address. + */ +/*************************************************************************************************/ +bool_t BbBleResListResolvePeer(uint64_t rpa, uint8_t *pPeerAddrType, uint64_t *pPeerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Resolve local resolvable address. + * + * \param rpa Local resolvable private address + * \param pPeerAddrType Storage for peer identity address type. + * \param pPeerIdentityAddr Storage for peer identity address. + * + * \return TRUE if successful, FALSE if address could not be resolved. + * + * Resolve a local resolvable address. + */ +/*************************************************************************************************/ +bool_t BbBleResListResolveLocal(uint64_t rpa, uint8_t *pPeerAddrType, uint64_t *pPeerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Get status of peer address in resolving list. + * + * \param peerAddrRand TRUE if peer identity address is random. + * \param peerIdentityAddr Peer identity address. + * + * \return Peer address status. + * + * Get the peer resolvable private address status + */ +/*************************************************************************************************/ +uint8_t BbBleResListPeerStatus(bool_t peerAddrRand, uint64_t peerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Get status of local address in resolving list. + * + * \param peerAddrRand TRUE if peer identity address is random. + * \param peerIdentityAddr Peer identity address. + * + * \return Local address status. + * + * Get the peer resolvable private address status + */ +/*************************************************************************************************/ +uint8_t BbBleResListLocalStatus(bool_t peerAddrRand, uint64_t peerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Handle timeout of local resolvable addresses. + * + * \return None. + * + * A new local resolvable address will be generated for each entry in the resolving list. + */ +/*************************************************************************************************/ +void BbBleResListHandleTimeout(void); + +/*! \} */ /* BB_API_BLE_RL */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_RESLIST_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_whitelist.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_whitelist.h new file mode 100644 index 0000000000..30de90dcc3 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/bb_ble_api_whitelist.h @@ -0,0 +1,143 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE baseband whitelist interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_API_WHITELIST_H +#define BB_BLE_API_WHITELIST_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup BB_API_BLE_WL + * \{ */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Check if address is white listed. + * + * \param randAddr TRUE if random address, FALSE if public. + * \param addr Bluetooth device address. + * + * \return TRUE if white listed, FALSE otherwise. + */ +/*************************************************************************************************/ +bool_t BbBleWhiteListCheckAddr(bool_t randAddr, uint64_t addr); + +/*************************************************************************************************/ +/*! + * \brief Get white list size. + * + * \return Total number of white list entries. + * + * Read the white list capacity supported by the BB. + */ +/*************************************************************************************************/ +uint8_t BbBleWhiteListGetSize(void); + +/*************************************************************************************************/ +/*! + * \brief Clear all white list entries. + * + * \return None. + * + * Clear all white list entries stored in the BB. + * + * \note No resource synchronization is required to modify the white list resource as + * the LL modifies the white list only when advertising events are disabled. + */ +/*************************************************************************************************/ +void BbBleWhiteListClear(void); + +/*************************************************************************************************/ +/*! + * \brief Add device to the white list. + * + * \param randAddr TRUE if random address, FALSE if public. + * \param addr Bluetooth device address. + * + * \return TRUE if successful, FALSE if list full. + * + * Adds the given address to the white list stored in the BB. + * + * \note No resource synchronization is required to modify the white list resource as + * the LL modifies the white list only when advertising events are disabled. + */ +/*************************************************************************************************/ +bool_t BbBleWhiteListAdd(bool_t randAddr, uint64_t addr); + +/*************************************************************************************************/ +/*! + * \brief Remove device from the white list. + * + * \param randAddr TRUE if random address, FALSE if public. + * \param addr Bluetooth device address. + * + * \return TRUE if successful, FALSE if address not in the list. + * + * Removes the given address from the white list stored in the BB. + * + * \note No resource synchronization is required to modify the white list resource as + * the LL modifies the white list only when advertising events are disabled. + */ +/*************************************************************************************************/ +bool_t BbBleWhiteListRemove(bool_t randAddr, uint64_t addr); + +/*************************************************************************************************/ +/*! + * \brief Add anonymous device to the white list. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleWhiteListAddAnonymous(void); + +/*************************************************************************************************/ +/*! + * \brief Remove anonymous device from the white list. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleWhiteListRemoveAnonymous(void); + +/*************************************************************************************************/ +/*! + * \brief Check if anonymous peer is allowed. + * + * \return TRUE if anonymous allowed, FALSE if disallowed. + */ +/*************************************************************************************************/ +bool_t BbBleWhiteListIsAnonymousAllowed(void); + +/*! \} */ /* BB_API_BLE_WL */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_API_WHITELIST_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/lhci_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/lhci_api.h new file mode 100644 index 0000000000..2a958554c0 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/lhci_api.h @@ -0,0 +1,90 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer HCI subsystem API. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LHCI_API_H +#define LHCI_API_H + +#include "wsf_types.h" +#include "wsf_os.h" +#include "cfg_mac_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief HCI header */ +typedef struct +{ + uint16_t opCode; /*!< OpCode command field. */ + uint8_t len; /*!< Parameter length. */ +} LhciHdr_t; + +/*! \brief Command handler call signature. */ +typedef bool_t (*lhciCmdHandler_t)(LhciHdr_t *pHdr, uint8_t *pBuf); + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LhciScanMasterInit(void); +void LhciExtScanMasterInit(void); +void LhciAdvSlaveInit(void); +void LhciExtAdvSlaveInit(void); +void LhciEncMasterInit(void); +void LhciEncSlaveInit(void); +void LhciPrivAdvInit(void); +void LhciPrivConnInit(void); +void LhciConnInit(void); +void LhciConnMasterInit(void); +void LhciExtConnMasterInit(void); +void LhciScInit(void); +void LhciPhyInit(void); +void LhciChannelSelection2Init(void); +void LhciVsExtInit(lhciCmdHandler_t decodeCmd); +void LhciHandlerInit(wsfHandlerId_t handlerId); +void LhciHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); +#if (LL_ENABLE_TESTER) +void LhciTesterInit(void); +#endif + +/* Command processing */ +uint8_t LhciPackCmdStatusEvt(uint8_t *pBuf, uint8_t status, uint16_t opCode); +uint8_t LhciPackCmdCompleteEvt(uint8_t *pBuf, uint16_t opCode); +uint8_t LhciPackCmdCompleteEvtStatus(uint8_t *pBuf, uint8_t status); +uint8_t LhciPackVsEvt(uint8_t *pBuf, uint16_t vsEvtCode); +void LhciSendEvent(uint8_t *pBuf); +bool_t LhciIsEventPending(void); +uint8_t LhciPackEvtHdr(uint8_t *pBuf, uint8_t evtCode, uint8_t paramLen); + +/* Event processing */ +void LhciVsEncodeTraceMsgEvtPkt(uint8_t *pBuf, uint8_t len); + +#ifdef __cplusplus +}; +#endif + +#endif /* LHCI_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_api.h new file mode 100644 index 0000000000..d2c88126c2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_api.h @@ -0,0 +1,3036 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LL_API_H +#define LL_API_H + +#include "wsf_types.h" +#include "wsf_os.h" +#include "util/bda.h" +#include "cfg_mac_ble.h" +#include "ll_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief The following status values are used in the LL API. */ +enum +{ + LL_SUCCESS = 0x00, + LL_ERROR_CODE_UNKNOWN_HCI_CMD = 0x01, + LL_ERROR_CODE_UNKNOWN_CONN_ID = 0x02, + LL_ERROR_CODE_HW_FAILURE = 0x03, + LL_ERROR_CODE_PAGE_TIMEOUT = 0x04, + LL_ERROR_CODE_AUTH_FAILURE = 0x05, + LL_ERROR_CODE_PIN_KEY_MISSING = 0x06, + LL_ERROR_CODE_MEM_CAP_EXCEEDED = 0x07, + LL_ERROR_CODE_CONN_TIMEOUT = 0x08, + LL_ERROR_CODE_CONN_LIMIT_EXCEEDED = 0x09, + LL_ERROR_CODE_SYNCH_CONN_LIMIT_EXCEEDED = 0x0A, + LL_ERROR_CODE_ACL_CONN_ALREADY_EXISTS = 0x0B, + LL_ERROR_CODE_CMD_DISALLOWED = 0x0C, + LL_ERROR_CODE_CONN_REJ_LIMITED_RESOURCES = 0x0D, + LL_ERROR_CODE_CONN_REJECTED_SECURITY_REASONS = 0x0E, + LL_ERROR_CODE_CONN_REJECTED_UNACCEPTABLE_BDADDR = 0x0F, + LL_ERROR_CODE_CONN_ACCEPT_TIMEOUT_EXCEEDED = 0x10, + LL_ERROR_CODE_UNSUPPORTED_FEATURE_PARAM_VALUE = 0x11, + LL_ERROR_CODE_INVALID_HCI_CMD_PARAMS = 0x12, + LL_ERROR_CODE_REMOTE_USER_TERM_CONN = 0x13, + LL_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_LOW_RESOURCES = 0x14, + LL_ERROR_CODE_REMOTE_DEVICE_TERM_CONN_POWER_OFF = 0x15, + LL_ERROR_CODE_CONN_TERM_BY_LOCAL_HOST = 0x16, + LL_ERROR_CODE_REPEATED_ATTEMPTS = 0x17, + LL_ERROR_CODE_PAIRING_NOT_ALLOWED = 0x18, + LL_ERROR_CODE_UNKNOWN_LMP_PDU = 0x19, + LL_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE = 0x1A, + LL_ERROR_CODE_SCO_OFFSET_REJ = 0x1B, + LL_ERROR_CODE_SCO_INTERVAL_REJ = 0x1C, + LL_ERROR_CODE_SCO_AIR_MODE_REJ = 0x1D, + LL_ERROR_CODE_INVALID_LMP_PARAMS = 0x1E, + LL_ERROR_CODE_UNSPECIFIED_ERROR = 0x1F, + LL_ERROR_CODE_UNSUPPORTED_LMP_PARAM_VAL = 0x20, + LL_ERROR_CODE_ROLE_CHANGE_NOT_ALLOWED = 0x21, + LL_ERROR_CODE_LMP_LL_RESP_TIMEOUT = 0x22, + LL_ERROR_CODE_LMP_ERR_TRANSACTION_COLLISION = 0x23, + LL_ERROR_CODE_LMP_PDU_NOT_ALLOWED = 0x24, + LL_ERROR_CODE_ENCRYPT_MODE_NOT_ACCEPTABLE = 0x25, + LL_ERROR_CODE_LINK_KEY_CAN_NOT_BE_CHANGED = 0x26, + LL_ERROR_CODE_REQ_QOS_NOT_SUPPORTED = 0x27, + LL_ERROR_CODE_INSTANT_PASSED = 0x28, + LL_ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29, + LL_ERROR_CODE_DIFFERENT_TRANSACTION_COLLISION = 0x2A, + LL_ERROR_CODE_RESERVED1 = 0x2B, + LL_ERROR_CODE_QOS_UNACCEPTABLE_PARAM = 0x2C, + LL_ERROR_CODE_QOS_REJ = 0x2D, + LL_ERROR_CODE_CHAN_ASSESSMENT_NOT_SUPPORTED = 0x2E, + LL_ERROR_CODE_INSUFFICIENT_SECURITY = 0x2F, + LL_ERROR_CODE_PARAM_OUT_OF_MANDATORY_RANGE = 0x30, + LL_ERROR_CODE_RESERVED2 = 0x31, + LL_ERROR_CODE_ROLE_SWITCH_PENDING = 0x32, + LL_ERROR_CODE_RESERVED3 = 0x33, + LL_ERROR_CODE_RESERVED_SLOT_VIOLATION = 0x34, + LL_ERROR_CODE_ROLE_SWITCH_FAILED = 0x35, + LL_ERROR_CODE_EXTENDED_INQUIRY_RESP_TOO_LARGE = 0x36, + LL_ERROR_CODE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST = 0x37, + LL_ERROR_CODE_HOST_BUSY_PAIRING = 0x38, + LL_ERROR_CODE_CONN_REJ_NO_SUITABLE_CHAN_FOUND = 0x39, + LL_ERROR_CODE_CONTROLLER_BUSY = 0x3A, + LL_ERROR_CODE_UNACCEPTABLE_CONN_INTERVAL = 0x3B, + LL_ERROR_CODE_ADV_TIMEOUT = 0x3C, + LL_ERROR_CODE_CONN_TERM_MIC_FAILURE = 0x3D, + LL_ERROR_CODE_CONN_FAILED_TO_ESTABLISH = 0x3E, + LL_ERROR_CODE_MAC_CONN_FAILED = 0x3F, + LL_ERROR_CODE_COARSE_CLK_ADJ_REJ = 0x40, + LL_ERROR_CODE_TYPE0_SUBMAP_NOT_DEF = 0x41, + LL_ERROR_CODE_UNKNOWN_ADV_ID = 0x42, + LL_ERROR_CODE_LIMIT_REACHED = 0x43, + LL_ERROR_CODE_OP_CANCELLED_BY_HOST = 0x44 +}; + +/*! \addtogroup LL_API_INIT + * \{ */ + +/*! \brief LL runtime configuration parameters. */ +typedef struct +{ + /* Device */ + uint16_t compId; /*!< Company ID (default to ARM Ltd. ID). */ + uint16_t implRev; /*!< Implementation revision number. */ + uint8_t btVer; /*!< Core specification implementation level (LL_VER_BT_CORE_SPEC_4_2). */ + uint32_t _align32; /*!< Unused. Align next field to word boundary. */ + /* Advertiser */ + uint8_t maxAdvSets; /*!< Maximum number of advertising sets. */ + uint8_t maxAdvReports; /*!< Maximum number of pending legacy or extended advertising reports. */ + uint16_t maxExtAdvDataLen; /*!< Maximum extended advertising data size. */ + uint8_t defExtAdvDataFrag; /*!< Default extended advertising data fragmentation size. */ + uint32_t auxDelayUsec; /*!< Auxiliary Offset delay above T_MAFS in microseconds. */ + /* Scanner */ + uint8_t maxScanReqRcvdEvt; /*!< Maximum scan request received events. */ + uint16_t maxExtScanDataLen; /*!< Maximum extended scan data size. */ + /* Connection */ + uint8_t maxConn; /*!< Maximum number of connections. */ + uint8_t numTxBufs; /*!< Default number of transmit buffers. */ + uint8_t numRxBufs; /*!< Default number of receive buffers. */ + uint16_t maxAclLen; /*!< Maximum ACL buffer size. */ + int8_t defTxPwrLvl; /*!< Default Tx power level for connections. */ + uint8_t ceJitterUsec; /*!< Allowable CE jitter on a slave (account for master's sleep clock resolution). */ + /* DTM */ + uint16_t dtmRxSyncMs; /*!< DTM Rx synchronization window in milliseconds. */ + /* PHY */ + bool_t phy2mSup; /*!< 2M PHY supported. */ + bool_t phyCodedSup; /*!< Coded PHY supported. */ + bool_t stableModIdxTxSup; /*!< Tx stable modulation index supported. */ + bool_t stableModIdxRxSup; /*!< Rx stable modulation index supported. */ +} LlRtCfg_t; + +/*! \} */ /* LL_API_INIT */ + +/*! \addtogroup LL_API_DEVICE + * \{ */ + +/* The supported state bitmask indicates the LE states supported by the LL. */ +#define LL_SUP_STATE_NON_CONN_ADV (UINT64_C(1) << 0) /*!< Non-connectable Advertising State supported. */ +#define LL_SUP_STATE_SCAN_ADV (UINT64_C(1) << 1) /*!< Scannable Advertising State supported. */ +#define LL_SUP_STATE_CONN_ADV (UINT64_C(1) << 2) /*!< Connectable Advertising State supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV (UINT64_C(1) << 3) /*!< High Duty Cycle Directed Advertising State supported. */ +#define LL_SUP_STATE_PASS_SCAN (UINT64_C(1) << 4) /*!< Passive Scanning State supported. */ +#define LL_SUP_STATE_ACT_SCAN (UINT64_C(1) << 5) /*!< Active Scanning State supported. */ +#define LL_SUP_STATE_INIT (UINT64_C(1) << 6) /*!< Initiating State supported. Connection State in the Master Role supported is also supported. */ +#define LL_SUP_STATE_CONN_SLV (UINT64_C(1) << 7) /*!< Connection State in the Slave Role supported. */ +#define LL_SUP_STATE_NON_CONN_ADV_AND_PASS_SCAN (UINT64_C(1) << 8) /*!< Non-connectable Advertising State and Passive Scanning State combination supported. */ +#define LL_SUP_STATE_SCAN_ADV_AND_PASS_SCAN (UINT64_C(1) << 9) /*!< Scannable Advertising State and Passive Scanning State combination supported. */ +#define LL_SUP_STATE_CONN_ADV_AND_PASS_SCAN (UINT64_C(1) << 10) /*!< Connectable Advertising State and Passive Scanning State combination supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV_AND_PASS_SCAN (UINT64_C(1) << 11) /*!< Directed Advertising State and Passive Scanning State combination supported. */ +#define LL_SUP_STATE_NON_CONN_ADV_AND_ACT_SCAN (UINT64_C(1) << 12) /*!< Non-connectable Advertising State and Active Scanning State combination supported. */ +#define LL_SUP_STATE_SCAN_ADV_AND_ACT_SCAN (UINT64_C(1) << 13) /*!< Scannable Advertising State and Active Scanning State combination supported. */ +#define LL_SUP_STATE_CONN_ADV_AND_ACT_SCAN (UINT64_C(1) << 14) /*!< Connectable Advertising State and Active Scanning State combination supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV_ACT_SCAN (UINT64_C(1) << 15) /*!< Directed Advertising State and Active Scanning State combination supported. */ +#define LL_SUP_STATE_NON_CONN_ADV_AND_INIT (UINT64_C(1) << 16) /*!< Non-connectable Advertising State and Initiating State combination supported. */ +#define LL_SUP_STATE_SCAN_ADV_AND_INIT (UINT64_C(1) << 17) /*!< Scannable Advertising State and Initiating State combination supported */ +#define LL_SUP_STATE_NON_CONN_ADV_MST (UINT64_C(1) << 18) /*!< Non-connectable Advertising State and Master Role combination supported. */ +#define LL_SUP_STATE_SCAN_ADV_MST (UINT64_C(1) << 19) /*!< Scannable Advertising State and Master Role combination supported. */ +#define LL_SUP_STATE_NON_CONN_ADV_SLV (UINT64_C(1) << 20) /*!< Non-connectable Advertising State and Slave Role combination supported. */ +#define LL_SUP_STATE_SCAN_ADV_SLV (UINT64_C(1) << 21) /*!< Scannable Advertising State and Slave Role combination supported. */ +#define LL_SUP_STATE_PASS_SCAN_AND_INIT (UINT64_C(1) << 22) /*!< Passive Scanning State and Initiating State combination supported. */ +#define LL_SUP_STATE_ACT_SCAN_AND_INIT (UINT64_C(1) << 23) /*!< Active Scanning State and Initiating State combination supported. */ +#define LL_SUP_STATE_PASS_SCAN_MST (UINT64_C(1) << 24) /*!< Passive Scanning State and Master Role combination supported. */ +#define LL_SUP_STATE_ACT_SCAN_MST (UINT64_C(1) << 25) /*!< Active Scanning State and Master Role combination supported. */ +#define LL_SUP_STATE_PASS_SCAN_SLV (UINT64_C(1) << 26) /*!< Passive Scanning state and Slave Role combination supported. */ +#define LL_SUP_STATE_ACT_SCAN_SLV (UINT64_C(1) << 27) /*!< Active Scanning state and Slave Role combination supported. */ +#define LL_SUP_STATE_INIT_MST (UINT64_C(1) << 28) /*!< Initiating State and Master Role combination supported. Master Role and Master Role combination is also supported. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV (UINT64_C(1) << 29) /*!< Low Duty Cycle Directed Advertising State. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV_AND_PASS_SCAN (UINT64_C(1) << 30) /*!< Low Duty Cycle Directed Advertising and Passive Scanning State combination supported. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV_AND_ACT_SCAN (UINT64_C(1) << 31) /*!< Low Duty Cycle Directed Advertising and Active Scanning State combination supported. */ +#define LL_SUP_STATE_CONN_ADV_AND_INIT (UINT64_C(1) << 32) /*!< Connectable Advertising State and Initiating State combination supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV_AND_INIT (UINT64_C(1) << 33) /*!< High Duty Cycle Directed Advertising and Initiating combination supported. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV_AND_INIT (UINT64_C(1) << 34) /*!< Low Duty Cycle Directed Advertising and Initiating combination supported. */ +#define LL_SUP_STATE_CONN_ADV_MST (UINT64_C(1) << 35) /*!< Connectable Advertising State and Master Role combination supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV_MST (UINT64_C(1) << 36) /*!< High Duty Cycle Directed Advertising and Master Role combination supported. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV_MST (UINT64_C(1) << 37) /*!< Low Duty Cycle Directed Advertising and Master Role combination supported. */ +#define LL_SUP_STATE_CONN_ADV_SLV (UINT64_C(1) << 38) /*!< Connectable Advertising State and Slave Role combination supported. */ +#define LL_SUP_STATE_HI_DUTY_DIR_ADV_SLV (UINT64_C(1) << 39) /*!< High Duty Cycle Directed Advertising and Slave Role combination supported. */ +#define LL_SUP_STATE_LO_DUTY_DIR_ADV_SLV (UINT64_C(1) << 40) /*!< Low Duty Cycle Directed Advertising and Slave Role combination supported. */ +#define LL_SUP_STATE_INIT_SLV (UINT64_C(1) << 41) /*!< Initiating State and Slave Role combination. */ + +/*! \brief The features bitmask indicates the LE features supported by the LL. */ +enum +{ + /* --- Core Spec 4.0 --- */ + LL_FEAT_ENCRYPTION = (1 << 0), /*!< Encryption supported. */ + /* --- Core Spec 4.2 --- */ + LL_FEAT_CONN_PARAM_REQ_PROC = (1 << 1), /*!< Connection Parameters Request Procedure supported. */ + LL_FEAT_EXT_REJECT_IND = (1 << 2), /*!< Extended Reject Indication supported. */ + LL_FEAT_SLV_INIT_FEAT_EXCH = (1 << 3), /*!< Slave-Initiated Features Exchange supported. */ + LL_FEAT_LE_PING = (1 << 4), /*!< LE Ping supported. */ + LL_FEAT_DATA_LEN_EXT = (1 << 5), /*!< Data Length Extension supported. */ + LL_FEAT_PRIVACY = (1 << 6), /*!< LL Privacy supported. */ + LL_FEAT_EXT_SCAN_FILT_POLICY = (1 << 7), /*!< Extended Scan Filter Policy supported. */ + /* --- Core Spec 5.0 --- */ + LL_FEAT_LE_2M_PHY = (1 << 8), /*!< LE 2M PHY supported. */ + LL_FEAT_STABLE_MOD_IDX_TRANSMITTER = (1 << 9), /*!< Stable Modulation Index - Transmitter supported. */ + LL_FEAT_STABLE_MOD_IDX_RECEIVER = (1 << 10), /*!< Stable Modulation Index - Receiver supported. */ + LL_FEAT_LE_CODED_PHY = (1 << 11), /*!< LE Coded PHY supported. */ + LL_FEAT_LE_EXT_ADV = (1 << 12), /*!< LE Extended Advertising supported. */ + LL_FEAT_LE_PER_ADV = (1 << 13), /*!< LE Periodic Advertising supported. */ + LL_FEAT_CH_SEL_2 = (1 << 14), /*!< Channel Selection Algorithm #2 supported. */ + LL_FEAT_LE_POWER_CLASS_1 = (1 << 15), /*!< LE Power Class 1 supported. */ + LL_FEAT_MIN_NUM_USED_CHAN = (1 << 16), /*!< Minimum Number of Used Channels supported. */ + /* --- */ + LL_FEAT_ALL_MASK = 0x1FFFF /*!< All feature mask, need to be updated when new features are added. */ +}; + +/*! \brief This parameter identifies the device role. */ +enum +{ + LL_ROLE_MASTER = 0, /*!< Role is master. */ + LL_ROLE_SLAVE = 1 /*!< Role is slave. */ +}; + +/*! \brief Operational mode flags. */ +enum +{ + LL_OP_MODE_FLAG_ENA_VER_LLCP_STARTUP = (1 << 0), /*!< Perform version exchange LLCP at connection establishment. */ + LL_OP_MODE_FLAG_SLV_REQ_IMMED_ACK = (1 << 1), /*!< MD bit set if data transmitted. */ + LL_OP_MODE_FLAG_BYPASS_CE_GUARD = (1 << 2), /*!< Bypass end of CE guard. */ + LL_OP_MODE_FLAG_MST_RETX_AFTER_RX_NACK = (1 << 3), /*!< Master retransmits after receiving NACK. */ + LL_OP_MODE_FLAG_MST_IGNORE_CP_RSP = (1 << 4), /*!< Master ignores LL_CONNECTION_PARAM_RSP. */ + LL_OP_MODE_FLAG_MST_UNCOND_CP_RSP = (1 << 5), /*!< Master unconditionally accepts LL_CONNECTION_PARAM_RSP. */ + /*!< (LL_OP_MODE_FLAG_MST_IGNORE_CP_RSP must be cleared). */ + LL_OP_MODE_FLAG_ENA_LEN_LLCP_STARTUP = (1 << 6), /*!< Perform data length update LLCP at connection establishment. */ + LL_OP_MODE_FLAG_REQ_SYM_PHY = (1 << 7), /*!< Require symmetric PHYs for connection. */ + LL_OP_MODE_FLAG_ENA_FEAT_LLCP_STARTUP = (1 << 8), /*!< Perform feature exchange LLCP at connection establishment. */ + LL_OP_MODE_FLAG_SLV_DELAY_LLCP_STARTUP = (1 << 9), /*!< Slave delays LLCP startup procedures. */ + /* diagnostics only */ + LL_OP_MODE_FLAG_ENA_ADV_DLY = (1 << 16), /*!< Enable advertising delay. */ + LL_OP_MODE_FLAG_ENA_SCAN_BACKOFF = (1 << 17), /*!< Enable scan backoff. */ + LL_OP_MODE_FLAG_ENA_WW = (1 << 18), /*!< Enable window widening. */ + LL_OP_MODE_FLAG_ENA_SLV_LATENCY = (1 << 19), /*!< Enable slave latency. */ + LL_OP_MODE_FLAG_ENA_LLCP_TIMER = (1 << 20) /*!< Enable LLCP timer. */ +}; + +/*! \} */ /* LL_API_DEVICE */ + +/*! \addtogroup LL_API_BROADCAST + * \{ */ + +/*! \brief The advertising type indicates the connectable and discoverable nature of the advertising packets transmitted by a device. */ +enum +{ + LL_ADV_CONN_UNDIRECT = 0, /*!< Connectable undirected advertising. Peer devices can scan and connect to this device. */ + LL_ADV_CONN_DIRECT_HIGH_DUTY = 1, /*!< Connectable directed advertising, high duty cycle. Only a specified peer device can connect to this device. */ + LL_ADV_SCAN_UNDIRECT = 2, /*!< Scannable undirected advertising. Peer devices can scan this device but cannot connect. */ + LL_ADV_NONCONN_UNDIRECT = 3, /*!< Non-connectable undirected advertising. Peer devices cannot scan or connect to this device. */ + LL_ADV_CONN_DIRECT_LOW_DUTY = 4 /*!< Connectable directed advertising, low duty cycle. Only a specified peer device can connect to this device. */ +}; + +/*! \brief The address type indicates whether an address is public or random. */ +enum +{ + LL_ADDR_PUBLIC = 0, /*!< Public address. */ + LL_ADDR_RANDOM = 1, /*!< Random address. */ + LL_ADDR_PUBLIC_IDENTITY = 2, /*!< Public identity address. */ + LL_ADDR_RANDOM_IDENTITY = 3, /*!< Random (static) identity address. */ + LL_ADDR_RANDOM_UNRESOLVABLE = 0xFE, /*!< Un-resolvable random address. */ + LL_ADDR_ANONYMOUS = 0xFF /*!< Anonymous advertiser. */ +}; + +#define LL_ADDR_RANDOM_BIT LL_ADDR_RANDOM /*!< Address type random or public bit. */ +#define LL_ADDR_IDENTITY_BIT LL_ADDR_PUBLIC_IDENTITY /*!< Address type identity bit. */ + +/*! \brief Advertising channel bit. */ +enum +{ + LL_ADV_CHAN_37_BIT = (1 << 0), /*!< Advertising channel 37. */ + LL_ADV_CHAN_38_BIT = (1 << 1), /*!< Advertising channel 38. */ + LL_ADV_CHAN_39_BIT = (1 << 2), /*!< Advertising channel 39. */ + LL_ADV_CHAN_ALL = 0x7, /*!< All advertising channels. */ +}; + +/*! \brief Advertising filter policy. */ +enum +{ + LL_ADV_FILTER_NONE = 0, /*!< Scan from any device. */ + LL_ADV_FILTER_SCAN_WL_BIT = 1, /*!< Scan from White List only. */ + LL_ADV_FILTER_CONN_WL_BIT = 2, /*!< Connect from While List only. */ + LL_ADV_FILTER_WL_ONLY = 3 /*!< Scan and connect from While List only. */ +}; + +/*! \brief Advertising event properties. */ +enum +{ + LL_ADV_EVT_PROP_CONN_ADV_BIT = (1 << 0), /*!< Connectable advertising. */ + LL_ADV_EVT_PROP_SCAN_ADV_BIT = (1 << 1), /*!< Scannable advertising. */ + LL_ADV_EVT_PROP_DIRECT_ADV_BIT = (1 << 2), /*!< Directed advertising. */ + LL_ADV_EVT_PROP_HIGH_DUTY_ADV_BIT = (1 << 3), /*!< High Duty Cycle advertising. */ + LL_ADV_EVT_PROP_LEGACY_ADV_BIT = (1 << 4), /*!< Use legacy advertising PDUs. */ + LL_ADV_EVT_PROP_OMIT_AA_BIT = (1 << 5), /*!< Omit advertiser's address from all PDUs (anonymous advertising). */ + LL_ADV_EVT_PROP_TX_PWR_BIT = (1 << 6) /*!< Include TxPower in the advertising PDU. */ +}; + +#define LL_ADV_EVT_PROP_NON_CONN_NON_SCAN 0 /*!< Non-connectable and non-scannable advertising. */ + +/*! \brief Extended advertising parameters. */ +typedef struct +{ + uint16_t advEventProp; /*!< Advertising Event Properties. */ + uint32_t priAdvInterMin; /*!< Primary Advertising Interval Minimum. */ + uint32_t priAdvInterMax; /*!< Primary Advertising Interval Maximum. */ + uint8_t priAdvChanMap; /*!< Primary Advertising Channel Map. */ + uint8_t ownAddrType; /*!< Own Address Type. */ + uint8_t peerAddrType; /*!< Peer Address Type. */ + uint8_t *pPeerAddr; /*!< Peer Address. */ + uint8_t advFiltPolicy; /*!< Advertising Filter Policy. */ + int8_t advTxPwr; /*!< Advertising Tx Power. */ + uint8_t priAdvPhy; /*!< Primary Advertising PHY. */ + uint8_t secAdvMaxSkip; /*!< Secondary Advertising Maximum Skip. */ + uint8_t secAdvPhy; /*!< Secondary Advertising PHY. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t scanReqNotifEna; /*!< Scan Request Notification Enable. */ +} LlExtAdvParam_t; + +/*! \brief Extended advertising enable parameters. */ +typedef struct +{ + uint8_t handle; /*!< Advertising handle. */ + uint16_t duration; /*!< Duration. */ + uint8_t numEvents; /*!< Maximum number of extended advertising events. */ +} LlExtAdvEnableParam_t; + +/*! \brief Periodic advertising parameters. */ +typedef struct +{ + uint16_t perAdvInterMin; /*!< Periodic Advertising Interval Minimum. */ + uint16_t perAdvInterMax; /*!< Periodic Advertising Interval Maximum. */ + uint16_t perAdvProp; /*!< Periodic Advertising Properties. */ +} LlPerAdvParam_t; + +/*! \brief Advertising data operation. */ +enum +{ + LL_ADV_DATA_OP_FRAG_INTER = 0, /*!< Intermediate fragment. */ + LL_ADV_DATA_OP_FRAG_FIRST = 1, /*!< First fragment. */ + LL_ADV_DATA_OP_FRAG_LAST = 2, /*!< Last fragment. */ + LL_ADV_DATA_OP_COMP = 3, /*!< Complete extended advertising data. */ + LL_ADV_DATA_OP_UNCHANGED = 4 /*!< Unchanged data (just update the Advertising DID). */ +}; + +/*! \brief Advertising data fragment preference. */ +enum +{ + LL_ADV_DATA_FRAG_ALLOW = 0, /*!< Controller may fragment all Host advertising data. */ + LL_ADV_DATA_FRAG_DISALLOW = 1 /*!< Controller should not fragment nor minimize fragmentation of Host advertising data. */ +}; + +/*! \} */ /* LL_API_BROADCAST */ + +/*! \addtogroup LL_API_OBSERVER + * \{ */ + +/*! \brief Type of scan. */ +enum +{ + LL_SCAN_PASSIVE = 0, /*!< Passive scanning. */ + LL_SCAN_ACTIVE = 1 /*!< Active scanning. */ +}; + +/*! \brief Scan filter policy. */ +enum +{ + LL_SCAN_FILTER_NONE = 0, /*!< Accept all advertising packets. */ + LL_SCAN_FILTER_WL_BIT = 1, /*!< Accept from While List only. */ + LL_SCAN_FILTER_RES_INIT_BIT = 2, /*!< Accept directed advertisements with RPAs. */ + LL_SCAN_FILTER_WL_OR_RES_INIT = 3 /*!< Accept from White List or directed advertisements with RPAs. */ +}; + +/*! \brief Periodic scan filter policy. */ +enum +{ + LL_PER_SCAN_FILTER_NONE = 0, /*!< Use advSID, advAddrType and advAddr to filter. */ + LL_PER_SCAN_FILTER_PL_BIT = 1, /*!< Use the periodic advertiser list. */ +}; + +/*! \brief Scan parameters. */ +typedef struct +{ + uint16_t scanInterval; /*!< Scan interval. */ + uint16_t scanWindow; /*!< Scan window. */ + uint8_t scanType; /*!< Scan type. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t scanFiltPolicy; /*!< Scan filter policy. */ +} LlScanParam_t; + +/*! \brief Extended scan parameters. */ +typedef struct +{ + uint16_t scanInterval; /*!< Scan interval. */ + uint16_t scanWindow; /*!< Scan window. */ + uint8_t scanType; /*!< Scan type. */ +} LlExtScanParam_t; + +/*! \brief Scan filter modes for duplicate report. */ +enum +{ + LL_SCAN_FILTER_DUP_DISABLE = 0x00, /*!< Duplicate filtering disabled. */ + LL_SCAN_FILTER_DUP_ENABLE_ONCE = 0x01, /*!< Duplicate filtering enabled. */ + LL_SCAN_FILTER_DUP_ENABLE_PERIODIC = 0x02 /*!< Duplicate filtering enabled, reset for each scan period. */ +}; + +/*! \brief Advertising report event types. */ +enum +{ + LL_RPT_TYPE_ADV_IND = 0x00, /*!< Connectable undirected advertising (ADV_IND). */ + LL_RPT_TYPE_ADV_DIRECT_IND = 0x01, /*!< Connectable directed advertising (ADV_DIRECT_IND). */ + LL_RPT_TYPE_ADV_SCAN_IND = 0x02, /*!< Scannable undirected advertising (ADV_SCAN_IND). */ + LL_RPT_TYPE_ADV_NONCONN_IND = 0x03, /*!< Non connectable undirected advertising (ADV_NONCONN_IND). */ + LL_RPT_TYPE_SCAN_RSP = 0x04 /*!< Scan Response (SCAN_RSP). */ +}; + +/*! \brief Periodic advertising create sync command. */ +typedef struct +{ + uint8_t filterPolicy; /*!< Filter Policy. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint8_t *pAdvAddr; /*!< Advertiser Address. */ + uint16_t skip; /*!< Skip. */ + uint16_t syncTimeOut; /*!< Synchronization Timeout. */ +} LlPerAdvCreateSyncCmd_t; + +/*! \brief Device in periodic advertiser list */ +typedef struct +{ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint8_t *pAdvAddr; /*!< Advertiser Address. */ + uint8_t advSID; /*!< Advertising SID. */ +} LlDevicePerAdvList_t; + +/*! \} */ /* LL_API_OBSERVER */ + +/*! \addtogroup LL_API_CONN + * \{ */ + +/*! \brief Master clock accuracy. */ +enum +{ + LL_MCA_500_PPM = 0x00, /*!< 500 ppm */ + LL_MCA_250_PPM = 0x01, /*!< 250 ppm */ + LL_MCA_150_PPM = 0x02, /*!< 150 ppm */ + LL_MCA_100_PPM = 0x03, /*!< 100 ppm */ + LL_MCA_75_PPM = 0x04, /*!< 75 ppm */ + LL_MCA_50_PPM = 0x05, /*!< 50 ppm */ + LL_MCA_30_PPM = 0x06, /*!< 30 ppm */ + LL_MCA_20_PPM = 0x07 /*!< 20 ppm */ +}; + +/*! \brief PHYS specification. */ +enum +{ + LL_PHYS_NONE = 0, /*!< No selected PHY. */ + LL_PHYS_LE_1M_BIT = (1 << 0), /*!< LE 1M PHY. */ + LL_PHYS_LE_2M_BIT = (1 << 1), /*!< LE 2M PHY. */ + LL_PHYS_LE_CODED_BIT = (1 << 2), /*!< LE Coded PHY. */ +}; + +/*! \brief All PHYs preference. */ +enum +{ + LL_ALL_PHY_ALL_PREFERENCES = 0, /*!< All PHY preferences. */ + LL_ALL_PHY_TX_PREFERENCE_BIT = (1 << 0), /*!< Set if no Tx PHY preference. */ + LL_ALL_PHY_RX_PREFERENCE_BIT = (1 << 1) /*!< Set if no Rx PHY preference. */ +}; + +/*! \brief PHY options. */ +enum +{ + LL_PHY_OPTIONS_NONE = 0, /*!< No preferences. */ + LL_PHY_OPTIONS_S2_PREFERRED = 1, /*!< S=2 coding preferred when transmitting on LE Coded PHY. */ + LL_PHY_OPTIONS_S8_PREFERRED = 2, /*!< S=8 coding preferred when transmitting on LE Coded PHY. */ +}; + +/*! \brief PHY types. */ +enum +{ + LL_PHY_NONE = 0, /*!< PHY not selected. */ + LL_PHY_LE_1M = 1, /*!< LE 1M PHY. */ + LL_PHY_LE_2M = 2, /*!< LE 2M PHY. */ + LL_PHY_LE_CODED = 3 /*!< LE Coded PHY. */ +}; + +/*! \brief Privacy modes. */ +enum +{ + LL_PRIV_MODE_NETWORK = 0, /*!< Network privacy mode. */ + LL_PRIV_MODE_DEVICE = 1, /*!< Device privacy mode. */ +}; + +/*! \brief Initiating parameters (\a LlExtCreateConn()). */ +typedef struct +{ + uint16_t scanInterval; /*!< Scan interval. */ + uint16_t scanWindow; /*!< Scan window. */ + uint8_t filterPolicy; /*!< Scan filter policy. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t peerAddrType; /*!< Address type used for peer device. */ + const uint8_t *pPeerAddr; /*!< Address of peer device. */ +} LlInitParam_t; + +/*! \brief Initiating parameters (\a LlExtCreateConn()). */ +typedef struct +{ + uint8_t filterPolicy; /*!< Scan filter policy. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t peerAddrType; /*!< Address type used for peer device. */ + const uint8_t *pPeerAddr; /*!< Address of peer device. */ + uint8_t initPhys; /*!< Initiating PHYs. */ +} LlExtInitParam_t; + +/*! \brief Initiating scan parameters (\a LlExtCreateConn()). */ +typedef struct +{ + uint16_t scanInterval; /*!< Scan interval. */ + uint16_t scanWindow; /*!< Scan window. */ +} LlExtInitScanParam_t; + +/*! \brief Connection specification (\a LlCreateConn(), \a LlConnUpdate() and \a LlExtCreateConn()). */ +typedef struct +{ + uint16_t connIntervalMin; /*!< Minimum connection interval. */ + uint16_t connIntervalMax; /*!< Maximum connection interval. */ + uint16_t connLatency; /*!< Connection latency. */ + uint16_t supTimeout; /*!< Supervision timeout. */ + uint16_t minCeLen; /*!< Minimum CE length. */ + uint16_t maxCeLen; /*!< Maximum CE length. */ +} LlConnSpec_t; + +/*! \brief Channel selection algorithm methods. */ +enum +{ + LL_CH_SEL_1 = 0, /*!< Channel selection #1. */ + LL_CH_SEL_2 = 1 /*!< Channel selection #2. */ +}; + +/*! \brief Tx power level type. */ +enum +{ + LL_TX_PWR_LVL_TYPE_CURRENT = 0x00, /*!< Current transmit power level. */ + LL_TX_PWR_LVL_TYPE_MAX = 0x01 /*!< Maximum transmit power level. */ +}; + +/*! \} */ /* LL_API_CONN */ + +/*! \addtogroup LL_API_ENCRYPT + * \{ */ + +/*! \brief Nonce mode. */ +enum +{ + LL_NONCE_MODE_PKT_CNTR = 0x00, /*!< Packet counter nonce mode (default). */ + LL_NONCE_MODE_EVT_CNTR = 0x01 /*!< Connection event counter mode. */ +}; + +/*! \brief Encryption mode data structure used in LlGetEncMode() and LlSetEncMode(). */ +typedef struct +{ + bool_t enaAuth; /*!< Enable authentication. */ + bool_t nonceMode; /*!< Nonce mode. */ +} LlEncMode_t; + +/*! \} */ /* LL_API_ENCRYPT */ + +/*! \addtogroup LL_API_TEST + * \{ */ + +/*! \brief Test packet payload type. */ +enum +{ + LL_TEST_PKT_TYPE_PRBS9 = 0x00, /*!< Pseudo-Random bit sequence 9. */ + LL_TEST_PKT_TYPE_0F = 0x01, /*!< 00001111'b packet payload type. */ + LL_TEST_PKT_TYPE_55 = 0x02, /*!< 01010101'b packet payload type. */ + LL_TEST_PKT_TYPE_PRBS15 = 0x03, /*!< Pseudo-Random bit sequence 15. */ + LL_TEST_PKT_TYPE_FF = 0x04, /*!< 11111111'b packet payload type. */ + LL_TEST_PKT_TYPE_00 = 0x05, /*!< 00000000'b packet payload type. */ + LL_TEST_PKT_TYPE_F0 = 0x06, /*!< 11110000'b packet payload type. */ + LL_TEST_PKT_TYPE_AA = 0x07 /*!< 10101010'b packet payload type. */ +}; + +/*! \brief Test PHY type. */ +enum +{ + LL_TEST_PHY_LE_1M = 0x01, /*!< LE 1M PHY. */ + LL_TEST_PHY_LE_2M = 0x02, /*!< LE 2M PHY. */ + LL_TEST_PHY_LE_CODED = 0x03, /*!< LE Coded PHY (data coding unspecified). */ + LL_TEST_PHY_LE_CODED_S8 = 0x03, /*!< LE Coded PHY with S=8 data coding. */ + LL_TEST_PHY_LE_CODED_S2 = 0x04 /*!< LE Coded PHY with S=2 data coding. */ +}; + +/*! \brief Test modulation index. */ +enum +{ + LL_TEST_MOD_IDX_STANDARD = 0x00, /*!< Standard modulation index. */ + LL_TEST_MOD_IDX_STABLE = 0x01 /*!< Stable modulation index. */ +}; + +/*! \brief Test report data. */ +typedef struct +{ + uint16_t numTx; /*!< Total transmit packet count. */ + uint16_t numRxSuccess; /*!< Successfully received packet count. */ + uint16_t numRxCrcError; /*!< CRC failed packet count. */ + uint16_t numRxTimeout; /*!< Receive timeout count. */ +} LlTestReport_t; + +/*! \} */ /* LL_API_TEST */ + +/*! \addtogroup LL_API_EVENT + * \{ */ + +/*! \brief Link control callback interface events */ +enum +{ + LL_ERROR_IND, /*!< Unrecoverable LL or radio error occurred (vendor specific). */ + /* --- Core Spec 4.0 --- */ + LL_RESET_CNF, /*!< Reset complete. */ + LL_ADV_REPORT_IND, /*!< Advertising report. */ + LL_ADV_ENABLE_CNF, /*!< Advertising enable/disable complete. */ + LL_SCAN_ENABLE_CNF, /*!< Scan enable/disable complete. */ + LL_CONN_IND, /*!< Connection complete. */ + LL_DISCONNECT_IND, /*!< Disconnect complete. */ + LL_CONN_UPDATE_IND, /*!< Connection update complete. */ + LL_CREATE_CONN_CANCEL_CNF, /*!< Create connection cancel status. */ + LL_READ_REMOTE_VER_INFO_CNF, /*!< Read remote version information complete. */ + LL_READ_REMOTE_FEAT_CNF, /*!< Read remote features complete. */ + LL_ENC_CHANGE_IND, /*!< Encryption change. */ + LL_ENC_KEY_REFRESH_IND, /*!< Key refresh. */ + LL_LTK_REQ_IND, /*!< LTK request. */ + LL_LTK_REQ_NEG_REPLY_CNF, /*!< LTK request negative reply status. */ + LL_LTK_REQ_REPLY_CNF, /*!< LTK request reply status. */ + /* --- Core Spec 4.2 --- */ + LL_REM_CONN_PARAM_IND, /*!< Remote connection parameter change. */ + LL_AUTH_PAYLOAD_TIMEOUT_IND, /*!< Authentication payload timeout expired. */ + LL_DATA_LEN_CHANGE_IND, /*!< Data length changed. */ + LL_READ_LOCAL_P256_PUB_KEY_CMPL_IND, /*!< Read local P-256 public key complete. */ + LL_GENERATE_DHKEY_CMPL_IND, /*!< Generate Diffie-Hellman key complete. */ + LL_SCAN_REPORT_IND, /*!< Legacy scan report (vendor specific). */ + /* --- Core Spec 5.0 --- */ + LL_PHY_UPDATE_IND, /*!< LE PHY update complete. */ + LL_EXT_ADV_REPORT_IND, /*!< Extended advertising report. */ + LL_EXT_SCAN_ENABLE_CNF, /*!< Extended scan enable/disable complete. */ + LL_SCAN_TIMEOUT_IND, /*!< Scan timeout. */ + LL_SCAN_REQ_RCVD_IND, /*!< Scan request received. */ + LL_EXT_ADV_ENABLE_CNF, /*!< Extended advertising enable/disable complete. */ + LL_ADV_SET_TERM_IND, /*!< Advertising set terminated complete. */ + LL_PER_ADV_ENABLE_CNF, /*!< Periodic advertising enable/disable complete. */ + LL_PER_ADV_SYNC_ESTD_IND, /*!< Periodic scanning synchronization established. */ + LL_PER_ADV_SYNC_LOST_IND, /*!< Periodic scanning synchronization lost. */ + LL_PER_ADV_REPORT_IND, /*!< Periodic scanning report. */ + LL_CH_SEL_ALGO_IND /*!< Channel selection algorithm. */ +}; + +/*! \brief Advertising report indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t *pData; /*!< Data buffer. */ + uint8_t len; /*!< Data buffer length. */ + int8_t rssi; /*!< RSSI. */ + uint8_t eventType; /*!< Event type. */ + uint8_t addrType; /*!< Address type. */ + bdAddr_t addr; /*!< Address. */ + /* --- direct fields --- */ + uint8_t directAddrType; /*!< Direct address type. */ + bdAddr_t directAddr; /*!< Direct address. */ +} LlAdvReportInd_t; + +/*! \brief Connect indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t role; /*!< Role of this device. */ + uint8_t addrType; /*!< Address type. */ + bdAddr_t peerAddr; /*!< Peer address. */ + uint16_t connInterval; /*!< Connection interval. */ + uint16_t connLatency; /*!< Connection latency. */ + uint16_t supTimeout; /*!< Supervision timeout. */ + uint8_t clockAccuracy; /*!< Clock accuracy. */ + /* --- enhanced fields --- */ + bdAddr_t localRpa; /*!< Local resolvable private address. */ + bdAddr_t peerRpa; /*!< Peer resolvable private address. */ +} LlConnInd_t; + +/*! \brief Disconnect indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t reason; /*!< Reason code. */ +} LlDisconnectInd_t; + +/*! \brief Connect update indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint16_t connInterval; /*!< Connection interval. */ + uint16_t connLatency; /*!< Connection latency. */ + uint16_t supTimeout; /*!< Supervision timeout. */ +} LlConnUpdateInd_t; + +/*! \brief Connection parameter change indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t handle; /*!< Connection handle. */ + uint16_t connIntervalMin;/*!< Minimum connection interval. */ + uint16_t connIntervalMax;/*!< Maximum connection interval. */ + uint16_t connLatency; /*!< Connection latency. */ + uint16_t supTimeout; /*!< Supervision timeout. */ +} LlRemConnParamInd_t; + +/*! \brief Create connection cancel confirm */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ +} LlCreateConnCancelCnf_t; + +/*! \brief Read remote version information confirm */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t version; /*!< Bluetooth specification version. */ + uint16_t mfrName; /*!< Manufacturer ID. */ + uint16_t subversion; /*!< Subversion. */ +} LlReadRemoteVerInfoCnf_t; + +#define LL_FEAT_LEN 8 /*!< Length of features byte array */ + +/*! \brief Read remote feature confirm */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t features[LL_FEAT_LEN]; /*!< Features. */ +} LlReadRemoteFeatCnf_t; + +/*! \brief Encryption change indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + bool_t enabled; /*!< Encryption enabled. */ +} LlEncChangeInd_t; + +/*! \brief Key refresh indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ +} LlEncKeyRefreshInd_t; + +/*! \brief LTK request indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t randNum[LL_RAND_LEN]; /*!< Random number. */ + uint16_t encDiversifier; /*!< Encryption diversifier. */ +} LlLtkReqInd_t; + +/*! \brief LTK request reply confirm */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ +} LlLtkReqReplyCnf_t; + +/*! \brief LTK request negative reply */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ +} LlLtkReqNegReplyCnf_t; + +/*! \brief Authentication payload timeout expired indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t handle; /*!< Connection handle. */ +} LlAuthPayloadTimeoutInd_t; + +/*! \brief Data length change */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t handle; /*!< Connection handle. */ + uint16_t maxTxLen; /*!< Maximum transmit length. */ + uint16_t maxTxTime; /*!< Maximum transmit time in microseconds. */ + uint16_t maxRxLen; /*!< Maximum receive length. */ + uint16_t maxRxTime; /*!< Maximum receive time in microseconds. */ +} LlDataLenChangeInd_t; + +/*! \brief Read local P-256 key pair complete */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint8_t pubKey_x[LL_ECC_KEY_LEN]; /*!< Public key x-coordinate. */ + uint8_t pubKey_y[LL_ECC_KEY_LEN]; /*!< Public key y-coordinate. */ +} LlReadLocalP256PubKeyInd_t; + +/*! \brief Generate Diffie-Hellman key complete */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint8_t dhKey[LL_ECC_KEY_LEN]; /*!< Diffie-Hellman key. */ +} LlGenerateDhKeyInd_t; + +/*! \brief PHY update complete. */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t txPhy; /*!< Transceiver PHY. */ + uint8_t rxPhy; /*!< Receiver PHY. */ +} LlPhyUpdateInd_t; + +/*! \brief HW error */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t code; /*!< Code. */ +} LlHwErrorInd_t; + +/*! \brief Scan report */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t peerAddrType; /*!< Peer address type. */ + uint64_t peerAddr; /*!< Peer address. */ + uint64_t peerRpa; /*!< Peer RPA. */ +} LlScanReportInd_t; + +/*! \brief Extended advertising enable */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint8_t handle; /*!< Advertising handle. */ +} LlExtAdvEnableCnf_t; + +/*! \brief Periodic advertising enable */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint8_t handle; /*!< Advertising handle. */ +} LlPerAdvEnableCnf_t; + +/*! \brief Extended advertising report event types. */ +enum +{ + LL_RPT_EVT_CONN_ADV_BIT = (1 << 0), /*!< Connectable advertising event bit. */ + LL_RPT_EVT_SCAN_ADV_BIT = (1 << 1), /*!< Scannable advertising event bit. */ + LL_RPT_EVT_DIRECT_ADV_BIT = (1 << 2), /*!< Directed advertising event bit. */ + LL_RPT_EVT_SCAN_RSP_BIT = (1 << 3), /*!< Scan response event bit. */ + LL_RPT_EVT_LEGACY_ADV_BIT = (1 << 4), /*!< Legacy advertising PDU event bit. */ +}; + +/*! \brief Extended advertising report data status. */ +enum +{ + LL_RPT_DATA_CMPL = 0x00, /*!< Data complete. */ + LL_RPT_DATA_INC_MORE = 0x01, /*!< Data incomplete, more date to come. */ + LL_RPT_DATA_INC_TRUNC = 0x02 /*!< Data incomplete, data truncated, no more date to come. */ +}; + +/*! \brief Special SID values. */ +enum +{ + LL_SID_NO_ADI = 0xFF /*!< No ADI field in the PDU. */ +}; + +/*! \brief Extended advertising report */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t eventType; /*!< Event type. */ + uint8_t addrType; /*!< Address type. */ + bdAddr_t addr; /*!< Address. */ + uint8_t priPhy; /*!< Primary PHY. */ + uint8_t secPhy; /*!< Secondary PHY. */ + uint8_t advSID; /*!< Advertising SID. */ + int8_t txPwr; /*!< Tx Power. */ + int8_t rssi; /*!< RSSI. */ + int16_t perAdvInter; /*!< Periodic advertising interval. */ + uint8_t directAddrType; /*!< Direct address type. */ + bdAddr_t directAddr; /*!< Direct address. */ + uint16_t len; /*!< Data buffer length. */ + const uint8_t *pData; /*!< Data buffer. */ +} LlExtAdvReportInd_t; + +/*! \brief Extended scan enable confirm */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ +} LlExtScanEnableCnf_t; + +/*! \brief Advertising set terminated */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint8_t advHandle; /*!< Advertising handle. */ + uint16_t connHandle; /*!< Connection handle. */ + uint8_t numCmplAdvEvt; /*!< Number of completed advertising events. */ +} LlAdvSetTermInd_t; + +/*! \brief Scan request received */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t handle; /*!< Advertising handle. */ + uint8_t scanAddrType; /*!< Scanner address type. */ + bdAddr_t scanAddr; /*!< Scanner address. */ +} LlScanReqRcvdInd_t; + +/*! \brief Used channel selection indication */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t handle; /*!< Connection handle. */ + uint8_t usedChSel; /*!< Used channel selection. */ +} LlChSelInd_t; + +/*! \brief LE periodic advertising synchronization established */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint8_t status; /*!< Status. */ + uint16_t syncHandle; /*!< Sync handle. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t addrType; /*!< Advertiser address type. */ + bdAddr_t addr; /*!< Advertiser address. */ + uint8_t advPhy; /*!< Advertiser PHY. */ + uint16_t perAdvInterval; /*!< Periodic advertising interval. */ + uint8_t advClkAccuracy; /*!< Advertiser clock accuracy. */ +} LlPerAdvSyncEstdCnf_t; + +/*! \brief LE periodic advertising report */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t syncHandle; /*!< Sync handle. */ + int8_t txPwr; /*!< Tx Power. */ + int8_t rssi; /*!< RSSI. */ + uint8_t unused; /*!< Future use. */ + uint8_t dataStatus; /*!< Data status. */ + uint16_t len; /*!< Data buffer length. */ + const uint8_t *pData; /*!< Data buffer. */ +} LlPerAdvReportInd_t; + +/*! \brief LE periodic advertising sync lost */ +typedef struct +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + uint16_t syncHandle; /*!< Sync handle. */ +} LlPerAdvSyncLostInd_t; + +/*! \brief Union of all event types */ +typedef union +{ + wsfMsgHdr_t hdr; /*!< Event header. */ + LlHwErrorInd_t hwErrorInd; /*!< Unrecoverable LL or radio error occurred. */ + /* --- Core Spec 4.0 --- */ + LlAdvReportInd_t advReportInd; /*!< LE advertising report. */ + LlConnInd_t connInd; /*!< LE connection complete. */ + LlDisconnectInd_t disconnectInd; /*!< LE disconnect complete. */ + LlConnUpdateInd_t connUpdateInd; /*!< LE connection update complete. */ + LlCreateConnCancelCnf_t createConnCancelCnf; /*!< LE create connection cancel status. */ + LlReadRemoteVerInfoCnf_t readRemoteVerInfoCnf; /*!< Read remote version information complete. */ + LlReadRemoteFeatCnf_t readRemoteFeatCnf; /*!< LE read remote features complete. */ + LlEncChangeInd_t encChangeInd; /*!< Encryption change. */ + LlEncKeyRefreshInd_t keyRefreshInd; /*!< Key refresh. */ + LlLtkReqInd_t ltkReqInd; /*!< LE LTK request. */ + LlLtkReqNegReplyCnf_t ltkReqNegReplyCnf; /*!< LTK request negative reply status. */ + LlLtkReqReplyCnf_t ltkReqReplyCnf; /*!< LTK request reply status. */ + /* --- Core Spec 4.2 --- */ + LlRemConnParamInd_t remConnParamInd; /*!< LE remote connection parameter request. */ + LlAuthPayloadTimeoutInd_t authPayloadTimeoutInd; /*!< Authentication payload timeout. */ + LlDataLenChangeInd_t dataLenChangeInd; /*!< Data length changed. */ + LlReadLocalP256PubKeyInd_t readLocalP256PubKeyInd; /*!< Read local P-256 public key complete. */ + LlGenerateDhKeyInd_t generateDhKeyInd; /*!< Generate Diffie-Hellman key complete. */ + LlScanReportInd_t scanReportInd; /*!< Scan report. */ + /* --- Core Spec 5.0 --- */ + LlPhyUpdateInd_t phyUpdateInd; /*!< PHY update complete. */ + LlExtAdvReportInd_t extAdvReportInd; /*!< LE extended advertising report. */ + LlExtScanEnableCnf_t extScanEnableCnf; /*!< LE extended scan enable completed. */ + LlScanReqRcvdInd_t scanReqRcvdInd; /*!< LE scan request received. */ + LlExtAdvEnableCnf_t extAdvEnableCnf; /*!< LE extended advertising enable complete. */ + LlAdvSetTermInd_t advSetTermInd; /*!< LE advertising set terminated. */ + LlChSelInd_t usedChSelInd; /*!< Used channel selection. */ + LlPerAdvEnableCnf_t perAdvEnableCnf; /*!< LE periodic advertising enable complete. */ + LlPerAdvSyncEstdCnf_t perAdvSyncEstdCnf; /*!< LE periodic advertising sync established. */ + LlPerAdvReportInd_t perAdvReportInd; /*!< LE periodic advertising report. */ + LlPerAdvSyncLostInd_t perAdvSyncLostInd; /*!< LE periodic advertising sync lost. */ + +} LlEvt_t; + +/*! \brief Event callback */ +typedef bool_t (*llEvtCback_t)(LlEvt_t *pEvent); + +/*! \brief ACL callback */ +typedef void (*llAclCback_t)(uint16_t handle, uint8_t numBufs); + +/*! \} */ /* LL_API_EVENT */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*! \addtogroup LL_API_INIT + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Get default runtime configuration values. + * + * \param pCfg Pointer to runtime configuration parameters. + * + * \return None. + * + * This function returns default value for the LL subsystem's runtime configurations. + */ +/*************************************************************************************************/ +void LlGetDefaultRunTimeCfg(LlRtCfg_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Initialize runtime configuration. + * + * \param pCfg Pointer to runtime configuration parameters (data must be static). + * + * \return None. + * + * This function initializes the LL subsystem's runtime configuration. + * + * \note This routine must be called only once before any other initialization routines. + */ +/*************************************************************************************************/ +void LlInitRunTimeCfg(const LlRtCfg_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Initialize memory for connections. + * + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function allocates memory for connections. + * + * \note This routine must be called after LlInitRunTimeCfg() but only once before any + * other initialization routines. + */ +/*************************************************************************************************/ +uint16_t LlInitConnMem(uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Initialize memory for extended advertising. + * + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function allocates memory for extended advertising. + * + * \note This routine must be called after LlInitRunTimeCfg() but only once before any + * other initialization routines. + */ +/*************************************************************************************************/ +uint16_t LlInitExtAdvMem(uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Initialize memory for extended scanning. + * + * \param pFreeMem Pointer to free memory. + * \param freeMemSize Size of pFreeMem. + * + * \return Amount of free memory consumed. + * + * This function allocates memory for extended scanning. + * + * \note This routine must be called after LlInitRunTimeCfg() but only once before any + * other initialization routines. + */ +/*************************************************************************************************/ +uint16_t LlInitExtScanMem(uint8_t *pFreeMem, uint32_t freeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as an advertising slave. + * + * \return None. + * + * This function initializes the LL subsystem for use as an advertising slave. + */ +/*************************************************************************************************/ +void LlAdvSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation for extended advertising slave. + * + * \return None. + * + * This function initializes the LL subsystem for use as an extended advertising slave. + */ +/*************************************************************************************************/ +void LlExtAdvSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as a connectable slave. + * + * \return None. + * + * This function initializes the LL subsystem for use as an advertising and connectable slave. + */ +/*************************************************************************************************/ +void LlConnSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as a encryptable connectable slave. + * + * \return None. + * + * This function initializes the LL subsystem for use as an advertising and encryptable + * connectable slave. + */ +/*************************************************************************************************/ +void LlEncConnSlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as a scanning master. + * + * \return None. + * + * This function initializes the LL subsystem for use as a scanning master. + */ +/*************************************************************************************************/ +void LlScanMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation for extended scanning master. + * + * \return None. + * + * This function initializes the LL subsystem for use as an extended scanning master. + */ +/*************************************************************************************************/ +void LlExtScanMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as an initiating master. + * + * \return None. + * + * This function initializes the LL subsystem for use as an initiating master. + */ +/*************************************************************************************************/ +void LlInitMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as an extended initiating master. + * + * \return None. + * + * This function initializes the LL subsystem for use as an initiating master. + */ +/*************************************************************************************************/ +void LlExtInitMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as a connectable master. + * + * \return None. + * + * This function initializes the LL subsystem for use as a scanning and initiating master. + */ +/*************************************************************************************************/ +void LlConnMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation as a encryptable connectable slave. + * + * \return None. + * + * This function initializes the LL subsystem for use as an advertising and encryptable + * connectable slave. + */ +/*************************************************************************************************/ +void LlEncConnMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for operation with privacy. + * + * \return None. + * + * This function initializes the LL subsystem for use with privacy. + */ +/*************************************************************************************************/ +void LlPrivInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for secure connections. + * + * \return None. + * + * This function initializes the LL subsystem for secure connections. + */ +/*************************************************************************************************/ +void LlScInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for PHY features (slave). + * + * \return None. + * + * This function initializes the LL subsystem for slave PHY features. + */ +/*************************************************************************************************/ +void LlPhySlaveInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for PHY features (master). + * + * \return None. + * + * This function initializes the LL subsystem for master PHY features. + */ +/*************************************************************************************************/ +void LlPhyMasterInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for secure connections. + * + * \return None. + * + * This function initializes the LL subsystem for secure connections. + */ +/*************************************************************************************************/ +void LlChannelSelection2Init(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem for test modes. + * + * \return None. + * + * This function initializes the LL subsystem for test modes. + */ +/*************************************************************************************************/ +void LlTestInit(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize LL subsystem with task handler. + * + * \param handlerId WSF handler ID. + * + * \return None. + * + * This function initializes the LL subsystem. It is called once upon system initialization. + * It must be called before any other function in the LL API is called. + */ +/*************************************************************************************************/ +void LlHandlerInit(wsfHandlerId_t handlerId); + +/*************************************************************************************************/ +/*! + * \brief LL message dispatch handler. + * + * \param event WSF event. + * \param pMsg WSF message. + * + * \return None. + */ +/*************************************************************************************************/ +void LlHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); + +/*************************************************************************************************/ +/*! + * \brief Reset LL subsystem. + * + * \return None. + * + * Reset the LL subsystem. All active connections are closed and all radio procedures such as + * scanning or advertising are terminated. + */ +/*************************************************************************************************/ +void LlReset(void); + +/*************************************************************************************************/ +/*! + * \brief Register LL event handler. + * + * \param evtCback Client callback function. + * + * \return None. + * + * This function is called by a client to register for LL events. + */ +/*************************************************************************************************/ +void LlEvtRegister(llEvtCback_t evtCback); + +/*************************************************************************************************/ +/*! + * \brief Register ACL handler. + * + * \param sendCompCback Client ACL send complete callback function. + * \param recvPendCback Client ACL receive pending callback function. + * + * \return None. + * + * This function is called by a client to register for ACL data. + */ +/*************************************************************************************************/ +void LlAclRegister(llAclCback_t sendCompCback, llAclCback_t recvPendCback); + +/*! \} */ /* LL_API_INIT */ + +/*! \addtogroup LL_API_DEVICE + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Set Bluetooth device address + * + * \param pAddr Bluetooth device address. + * + * \return None. + * + * Set the BD address to be used by LL. + */ +/*************************************************************************************************/ +void LlSetBdAddr(const uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Get Bluetooth device address + * + * \param pAddr Bluetooth device address. + * + * \return None. + * + * Get the BD address currently used by LL or all zeros if address is not set. + */ +/*************************************************************************************************/ +void LlGetBdAddr(uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Set random device address. + * + * \param pAddr Random Bluetooth device address. + * + * \return Status. + * + * Set the random address to be used by LL. + */ +/*************************************************************************************************/ +uint8_t LlSetRandAddr(const uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Get random device address. + * + * \param pAddr Random Bluetooth device address. + * + * \return Status error code. + * + * Get the random address currently used by LL or all zeros if address is not set. + */ +/*************************************************************************************************/ +uint8_t LlGetRandAddr(uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Get versions + * + * \param pCompId Company ID. + * \param pBtVer Bluetooth version. + * \param pImplRev Implementation revision. + * + * \return None. + */ +/*************************************************************************************************/ +void LlGetVersion(uint16_t *pCompId, uint8_t *pBtVer, uint16_t *pImplRev); + +/*************************************************************************************************/ +/*! + * \brief Get supported states. + * + * \param pStates Supported states bitmask. + * + * \return None. + * + * Return the states supported by the LL. + */ +/*************************************************************************************************/ +void LlGetSupStates(uint8_t *pStates); + +/*************************************************************************************************/ +/*! + * \brief Get features. + * + * \param pFeatures Supported features bitmask. + * + * \return None. + * + * Return the LE features supported by the LL. + */ +/*************************************************************************************************/ +void LlGetFeatures(uint8_t *pFeatures); + +/*************************************************************************************************/ +/*! + * \brief Set features. + * + * \param pFeatures Supported features bitmask. + * + * \return Status error code. + * + * \note This function must only be called when controller is not connected to another + * device. + * + * Set the LE features supported by the LL. + */ +/*************************************************************************************************/ +uint8_t LlSetFeatures(const uint8_t *pFeatures); + +/*************************************************************************************************/ +/*! + * \brief Get random number. + * + * \param pRandNum Buffer to store 8 bytes random data. + * + * \return Status error code. + * + * Request the LL to generate a random number. + */ +/*************************************************************************************************/ +uint8_t LlGetRandNum(uint8_t *pRandNum); + +/*************************************************************************************************/ +/*! + * \brief Get white list size. + * + * \return Total number of white list entries. + * + * Read the white list capacity supported by the LL. + */ +/*************************************************************************************************/ +uint8_t LlGetWhitelistSize(void); + +/*************************************************************************************************/ +/*! + * \brief Clear all white list entries. + * + * \return Status error code. + * + * Clear all white list entries stored in the LL. + * + * \note This function must only be called when advertising or scan is disabled + * and not initiating. + */ +/*************************************************************************************************/ +uint8_t LlClearWhitelist(void); + +/*************************************************************************************************/ +/*! + * \brief Add device to the white list. + * + * \param addrType Address type. + * \param pAddr Bluetooth device address. + * + * \return Status error code. + * + * Adds the given address to the white list stored in the LL. + * + * \note This function must only be called when advertising or scan is disabled + * and not initiating. + */ +/*************************************************************************************************/ +uint8_t LlAddDeviceToWhitelist(uint8_t addrType, bdAddr_t pAddr); + +/*************************************************************************************************/ +/*! + * \brief Remove device from the white list. + * + * \param addrType Address type. + * \param pAddr Bluetooth device address. + * + * \return Status error code. + * + * Removes the given address from the white list stored in the LL. + * + * \note This function must only be called when advertising or scan is disabled + * and not initiating. + */ +/*************************************************************************************************/ +uint8_t LlRemoveDeviceFromWhitelist(uint8_t addrType, bdAddr_t pAddr); + +/*************************************************************************************************/ +/*! + * \brief Add device to resolving list. + * + * \param peerAddrType Peer identity address type. + * \param pPeerIdentityAddr Peer identity address. + * \param pPeerIrk Peer IRK. + * \param pLocalIrk Local IRK. + * + * \return Status error code. + * + * Add device to resolving list. + */ +/*************************************************************************************************/ +uint8_t LlAddDeviceToResolvingList(uint8_t peerAddrType, const uint8_t *pPeerIdentityAddr, const uint8_t *pPeerIrk, const uint8_t *pLocalIrk); + +/*************************************************************************************************/ +/*! + * \brief Remove device from resolving list. + * + * \param peerAddrType Peer identity address type. + * \param pPeerIdentityAddr Peer identity address. + * + * \return Status error code. + * + * Remove device from resolving list. + */ +/*************************************************************************************************/ +uint8_t LlRemoveDeviceFromResolvingList(uint8_t peerAddrType, const uint8_t *pPeerIdentityAddr); + +/*************************************************************************************************/ +/*! + * \brief Clear resolving list. + * + * \return Status error code. + * + * Clear resolving list. + */ +/*************************************************************************************************/ +uint8_t LlClearResolvingList(void); + +/*************************************************************************************************/ +/*! + * \brief Read resolving list size. + * + * \param pSize Storage for resolving list size. + * + * \return Status error code. + * + * Read number of address translation entries that can be stored in the resolving list. + */ +/*************************************************************************************************/ +uint8_t LlReadResolvingListSize(uint8_t *pSize); + +/*************************************************************************************************/ +/*! + * \brief Read peer resolvable address. + * + * \param addrType Peer identity address type. + * \param pIdentityAddr Peer identity address. + * \param pRpa Storage for peer resolvable private address + * + * \return Status error code. + * + * Get the peer resolvable private address that is currently being used for the peer identity + * address. + */ +/*************************************************************************************************/ +uint8_t LlReadPeerResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Read local resolvable address. + * + * \param addrType Peer identity address type. + * \param pIdentityAddr Peer identity address. + * \param pRpa Storage for peer resolvable private address + * + * \return Status error code. + * + * Get the local resolvable private address that is currently being used for the peer identity + * address. + */ +/*************************************************************************************************/ +uint8_t LlReadLocalResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t *pRpa); + +/*************************************************************************************************/ +/*! + * \brief Enable or disable address resolution. + * + * \param enable Set to TRUE to enable address resolution or FALSE to disable address + * resolution. + * + * \return Status error code. + * + * Enable or disable address resolution so that received local or peer resolvable private + * addresses are resolved. + */ +/*************************************************************************************************/ +uint8_t LlSetAddrResolutionEnable(uint8_t enable); + +/*************************************************************************************************/ +/*! + * \brief Set resolvable private address timeout. + * + * \param rpaTimeout Timeout measured in seconds. + * + * \return Status error code. + * + * Set the time period between automatic generation of new resolvable private addresses. + */ +/*************************************************************************************************/ +uint8_t LlSetResolvablePrivateAddrTimeout(uint16_t rpaTimeout); + +/*************************************************************************************************/ +/*! + * \brief Set privacy mode. + * + * \param peerAddrType Peer identity address type. + * \param pPeerIdentityAddr Peer identity address. + * \param privMode Privacy mode. + * + * \return Status error code. + * + * Allow the host to specify the privacy mode to be used for a given entry on the resolving list. + */ +/*************************************************************************************************/ +uint8_t LlSetPrivacyMode(uint8_t peerAddrType, const uint8_t *pPeerIdentityAddr, uint8_t privMode); + +/*************************************************************************************************/ +/*! + * \brief Generate a P-256 public/private key pair. + * + * \return Status error code. + * + * Generate a P-256 public/private key pair. If another ECC operation (P-256 key pair or Diffie- + * Hellman key generation) is ongoing, an error will be returned. + */ +/*************************************************************************************************/ +uint8_t LlGenerateP256KeyPair(void); + +/*************************************************************************************************/ +/*! + * \brief Generate a Diffie-Hellman key. + * + * \param pubKey_x Remote public key x-coordinate. + * \param pubKey_y Remote public key y-coordinate. + * + * \return Status error code. + * + * Generate a Diffie-Hellman key from a remote public key and the local private key. If another + * ECC operation (P-256 key pair or Diffie-Hellman key generation) is ongoing, an error will be + * returned. + */ +/*************************************************************************************************/ +uint8_t LlGenerateDhKey(const uint8_t pubKey_x[LL_ECC_KEY_LEN], const uint8_t pubKey_y[LL_ECC_KEY_LEN]); + +/*************************************************************************************************/ +/*! + * \brief Set P-256 private key for debug purposes. + * + * \param privKey Private key, or all zeros to clear set private key. + * + * \return Status error code. + * + * Set P-256 private key or clear set private key. The private key will be used for generate key + * pairs and Diffie-Hellman keys until cleared. + */ +/*************************************************************************************************/ +uint8_t LlSetP256PrivateKey(const uint8_t privKey[LL_ECC_KEY_LEN]); + +/*************************************************************************************************/ +/*! + * \brief Set channel class. + * + * \param pChanMap Channel map (0=bad, 1=usable). + * + * \return Status error code. + * + * Set the channel class. At least 2 bits must be set. + */ +/*************************************************************************************************/ +uint8_t LlSetChannelClass(const uint8_t *pChanMap); + +/*************************************************************************************************/ +/*! + * \brief Set operational mode flags. + * + * \param flags Flags. + * \param enable TRUE to set flags or FALSE to clear flags. + * + * \return Status error code. + * + * Set mode flags governing LL operations. + */ +/*************************************************************************************************/ +uint8_t LlSetOpFlags(uint32_t flags, bool_t enable); + +/*************************************************************************************************/ +/*! + * \brief Set the default Ext adv TX PHY options. + * + * \param phyOptions PHY options. + * + * \return None. + * + * Set the default TX PHY options for extended adv slave primary and secondary channel. + */ +/*************************************************************************************************/ +void LlSetDefaultExtAdvTxPhyOptions(const uint8_t phyOptions); + +/*! \} */ /* LL_API_DEVICE */ + +/*! \addtogroup LL_API_BROADCAST + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Set advertising transmit power. + * + * \param advTxPwr Advertising transmit power level. + * + * \return None. + * + * Set the advertising transmit power. + */ +/*************************************************************************************************/ +void LlSetAdvTxPower(int8_t advTxPwr); + +/*************************************************************************************************/ +/*! + * \brief Get advertising transmit power. + * + * \param pAdvTxPwr Advertising transmit power level. + * + * \return Status error code. + * + * Return the advertising transmit power. + */ +/*************************************************************************************************/ +uint8_t LlGetAdvTxPower(int8_t *pAdvTxPwr); + +/*************************************************************************************************/ +/*! + * \brief Set advertising parameter. + * + * \param advIntervalMin Minimum advertising interval. + * \param advIntervalMax Maximum advertising interval. + * \param advType Advertising type. + * \param ownAddrType Address type used by this device. + * \param peerAddrType Address type of peer device. Only used for directed advertising. + * \param pPeerAddr Address of peer device. Only used for directed advertising. + * \param advChanMap Advertising channel map. + * \param advFiltPolicy Advertising filter policy. + * + * \return Status error code. + * + * Set advertising parameters. + * + * \note This function must only be called when advertising is disabled. + */ +/*************************************************************************************************/ +uint8_t LlSetAdvParam(uint16_t advIntervalMin, uint16_t advIntervalMax, uint8_t advType, + uint8_t ownAddrType, uint8_t peerAddrType, const uint8_t *pPeerAddr, + uint8_t advChanMap, uint8_t advFiltPolicy); + +/*************************************************************************************************/ +/*! + * \brief Set advertising data. + * + * \param len Data buffer length. + * \param pData Advertising data buffer. + * + * \return Status error code. + * + * Set advertising data data. + */ +/*************************************************************************************************/ +uint8_t LlSetAdvData(uint8_t len, const uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Set scan response data. + * + * \param len Data buffer length. + * \param pData Scan response data buffer. + * + * \return Status error code. + * + * Set scan response data. + */ +/*************************************************************************************************/ +uint8_t LlSetScanRespData(uint8_t len, const uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Advertising enable. + * + * \param enable Set to TRUE to enable advertising, FALSE to disable advertising. + * + * \return None. + + * Enable or disable advertising. + */ +/*************************************************************************************************/ +void LlAdvEnable(uint8_t enable); + +/*************************************************************************************************/ +/*! + * \brief Set advertising set random device address. + * + * \param handle Advertising handle. + * \param pAddr Random Bluetooth device address. + * + * \return Status error code. + * + * Set the random address to be used by a advertising set. + */ +/*************************************************************************************************/ +uint8_t LlSetAdvSetRandAddr(uint8_t handle, const uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Get advertising set random device address. + * + * \param handle Advertising handle. + * \param pAddr Random Bluetooth device address. + * + * \return Status error code. + * + * Get the random address to be used by a advertising set. + */ +/*************************************************************************************************/ +uint8_t LlGetAdvSetRandAddr(uint8_t handle, uint8_t *pAddr); + +/*************************************************************************************************/ +/*! + * \brief Set extended advertising parameters. + * + * \param handle Advertising handle. + * \param pExtAdvParam Extended advertising parameters. + * + * \return Status error code. + * + * Set extended advertising parameters. + * + * \note This function must only be called when advertising for this set is disabled. + */ +/*************************************************************************************************/ +uint8_t LlSetExtAdvParam(uint8_t handle, LlExtAdvParam_t *pExtAdvParam); + +/*************************************************************************************************/ +/*! + * \brief Get extended advertising TX power level. + * + * \param handle Advertising handle. + * \param pLevel Transmit power level. + * + * \return Status error code. + * + * Get the TX power of an advertising set. + */ +/*************************************************************************************************/ +uint8_t LlGetExtAdvTxPowerLevel(uint16_t handle, int8_t *pLevel); + +/*************************************************************************************************/ +/*! + * \brief Set extended advertising data. + * + * \param handle Advertising handle. + * \param op Operation. + * \param fragPref Fragment preference. + * \param len Data buffer length. + * \param pData Advertising data buffer. + * + * \return Status error code. + * + * Set extended advertising data data. + */ +/*************************************************************************************************/ +uint8_t LlSetExtAdvData(uint8_t handle, uint8_t op, uint8_t fragPref, uint8_t len, const uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Set extended scan response data. + * + * \param handle Advertising handle. + * \param op Operation. + * \param fragPref Fragment preference. + * \param len Data buffer length. + * \param pData Scan response data buffer. + * + * \return Status error code. + * + * Set extended scan response data. + */ +/*************************************************************************************************/ +uint8_t LlSetExtScanRespData(uint8_t handle, uint8_t op, uint8_t fragPref, uint8_t len, const uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Extended advertising enable. + * + * \param enable Set to TRUE to enable advertising, FALSE to disable advertising. + * \param numAdvSets Number of elements in enaParam[]. + * \param enaParam Enable parameter table. + * + * \return None. + * + * Enable or disable extended advertising. + */ +/*************************************************************************************************/ +void LlExtAdvEnable(uint8_t enable, uint8_t numAdvSets, LlExtAdvEnableParam_t enaParam[]); + +/*************************************************************************************************/ +/*! + * \brief Read maximum advertising data length. + * + * \param pLen Return buffer for Maximum data length. + * + * \return Status error code. + * + * Read maximum advertising data length. + */ +/*************************************************************************************************/ +uint8_t LlReadMaxAdvDataLen(uint16_t *pLen); + +/*************************************************************************************************/ +/*! + * \brief Read number of supported advertising sets. + * + * \param pNumSets Return buffer for number of advertising sets. + * + * \return Status error code. + * + * Read number of supported advertising sets. + */ +/*************************************************************************************************/ +uint8_t LlReadNumSupAdvSets(uint8_t *pNumSets); + +/*************************************************************************************************/ +/*! + * \brief Remove advertising set. + * + * \param handle Advertising handle. + * + * \return Status error code. + * + * Removes the an advertising set from the LL. + */ +/*************************************************************************************************/ +uint8_t LlRemoveAdvSet(uint8_t handle); + +/*************************************************************************************************/ +/*! + * \brief Clear advertising sets. + * + * \return Status error code. + * + * Remove all existing advertising sets from the LL. + */ +/*************************************************************************************************/ +uint8_t LlClearAdvSets(void); + +/*************************************************************************************************/ +/*! + * \brief Set periodic advertising parameters. + * + * \param handle Advertising handle. + * \param pPerAdvParam Periodic advertising parameters. + * + * \return Status error code. + * + * Set periodic advertising parameters. + * + * \note This function must only be called when advertising handle exists. + */ +/*************************************************************************************************/ +uint8_t LlSetPeriodicAdvParam(uint8_t handle, LlPerAdvParam_t *pPerAdvParam); + +/*************************************************************************************************/ +/*! + * \brief Set periodic advertising data. + * + * \param handle Advertising handle. + * \param op Operation. + * \param len Data buffer length. + * \param pData Advertising data buffer. + * + * \return Status error code. + * + * Set periodic advertising data. + */ +/*************************************************************************************************/ +uint8_t LlSetPeriodicAdvData(uint8_t handle, uint8_t op, uint8_t len, const uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Set periodic advertising enable. + * + * \param enable TRUE to enable advertising, FALSE to disable advertising. + * \param handle Advertising handle. + * + * \return Status error code. + * + * Enable or disable periodic advertising. + */ +/*************************************************************************************************/ +void LlSetPeriodicAdvEnable(uint8_t enable, uint8_t handle); + +/*************************************************************************************************/ +/*! + * \brief Set auxiliary packet offset delay. + * + * \param handle Advertising handle. + * \param delayUsec Additional time in microseconds. "0" to disable. + * + * \return Status error code. + * + * Additional delay given to auxiliary packets specified by AuxPtr. Offset values are + * limited by the advertising interval. + */ +/*************************************************************************************************/ +uint8_t LlSetAuxOffsetDelay(uint8_t handle, uint32_t delayUsec); + +/*************************************************************************************************/ +/*! + * \brief Set extended advertising data fragmentation length. + * + * \param handle Advertising handle. + * \param fragLen Fragmentation length. + * + * \return Status error code. + * + * Fragmentation size for Advertising Data and Scan Response Data when selected by the host. + */ +/*************************************************************************************************/ +uint8_t LlSetExtAdvDataFragLen(uint8_t handle, uint8_t fragLen); + +/*************************************************************************************************/ +/*! + * \brief Set extended advertising transmit PHY options. + * + * \param handle Advertising handle. + * \param priPhyOpts Primary advertising channel PHY options. + * \param secPhyOpts Secondary advertising channel PHY options. + * + * \return Status error code. + * + * PHY options for extended advertising transmissions. New values are applied dynamically. + */ +/*************************************************************************************************/ +uint8_t LlSetExtAdvTxPhyOptions(uint8_t handle, uint8_t priPhyOpts, uint8_t secPhyOpts); + +/*************************************************************************************************/ +/*! + * \brief Read supported transmit power. + * + * \param pMinTxPwr Return buffer for minimum transmit power. + * \param pMaxTxPwr Return buffer for maximum transmit power. + * + * \return None. + * + * Read the minimum and maximum transmit powers supported by the LL. + */ +/*************************************************************************************************/ +void LlReadSupTxPower(int8_t *pMinTxPwr, int8_t *pMaxTxPwr); + +/*************************************************************************************************/ +/*! + * \brief Read RF path compensation. + * + * \param pTxPathComp Return buffer for RF transmit path compensation value. + * \param pRxPathComp Return buffer for RF receive path compensation value. + * + * \return None. + * + * Read the RF Path Compensation Values parameter used in the Tx Power Level and RSSI calculation. + */ +/*************************************************************************************************/ +void LlReadRfPathComp(int16_t *pTxPathComp, int16_t *pRxPathComp); + +/*************************************************************************************************/ +/*! + * \brief Write RF path compensation. + * + * \param txPathComp RF transmit path compensation value. + * \param rxPathComp RF receive path compensation value. + * + * \return Status error code. + * + * Indicate the RF path gain or loss between the RF transceiver and the antenna contributed by + * intermediate components. + */ +/*************************************************************************************************/ +uint8_t LlWriteRfPathComp(int16_t txPathComp, int16_t rxPathComp); + +/*************************************************************************************************/ +/*! + * \brief Scan report enable. + * + * \param enable Set to TRUE to enable scan reports, FALSE to disable scan reports. + * + * \return None. + * + * Enable or disable reports about the scanners from which an advertiser receives scan requests. + */ +/*************************************************************************************************/ +void LlScanReportEnable(uint8_t enable); + +/*! \} */ /* LL_API_BROADCAST */ + +/*! \addtogroup LL_API_OBSERVER + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Set scan channel map. + * + * \param chanMap Scan channel map. + * + * \return Status error code. + * + * Set scan channel map. + * + * \note This function must only be called when scanning is disabled. + */ +/*************************************************************************************************/ +uint8_t LlSetSetScanChanMap(uint8_t chanMap); + +/*************************************************************************************************/ +/*! + * \brief Set scan parameters. + * + * \param pParam Scan parameters. + * + * \return Status error code. + * + * Set scan parameters. + * + * \note This function must only be called when scanning is disabled. + */ +/*************************************************************************************************/ +uint8_t LlSetScanParam(const LlScanParam_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Scan enable. + * + * \param enable Set to TRUE to enable scanning, FALSE to disable scanning. + * \param filterDup Set to TRUE to filter duplicates. + * + * \return None. + * + * Enable or disable scanning. This function is only used when operating in master role. + */ +/*************************************************************************************************/ +void LlScanEnable(uint8_t enable, uint8_t filterDup); + +/*************************************************************************************************/ +/*! + * \brief Set extended scanning parameters. + * + * \param ownAddrType Address type used by this device. + * \param scanFiltPolicy Scan filter policy. + * \param scanPhys Scanning PHYs bitmask. + * \param param Scanning parameter table indexed by PHY. + * + * \return Status error code. + * + * Set the extended scan parameters to be used on the primary advertising channel. + */ +/*************************************************************************************************/ +uint8_t LlSetExtScanParam(uint8_t ownAddrType, uint8_t scanFiltPolicy, uint8_t scanPhys, const LlExtScanParam_t param[]); + +/*************************************************************************************************/ +/*! + * \brief Extended scan enable. + * + * \param enable Set to TRUE to enable scanning, FALSE to disable scanning. + * \param filterDup Set to TRUE to filter duplicates. + * \param duration Duration. + * \param period Period. + * + * \return None. + * + * Enable or disable extended scanning. + */ +/*************************************************************************************************/ +void LlExtScanEnable(uint8_t enable, uint8_t filterDup, uint16_t duration, uint16_t period); + +/*************************************************************************************************/ +/*! + * \brief Create synchronization of periodic advertising. + * + * \param pParam Create sync parameters. + * + * \return Status error code. + * + * Create synchronization of periodic advertising. + */ +/*************************************************************************************************/ +uint8_t LlPeriodicAdvCreateSync(const LlPerAdvCreateSyncCmd_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Cancel pending synchronization of periodic advertising. + * + * \return Status error code. + * + * Cancel pending synchronization of periodic advertising. + */ +/*************************************************************************************************/ +uint8_t LlPeriodicAdvCreateSyncCancel(void); + +/*************************************************************************************************/ +/*! + * \brief Stop synchronization of periodic advertising. + * + * \param syncHandle Sync handle. + * + * \return Status error code. + * + * Stop synchronization of periodic advertising. + */ +/*************************************************************************************************/ +uint8_t LlPeriodicAdvTerminateSync(uint16_t syncHandle); + +/*************************************************************************************************/ +/*! + * \brief Add device to periodic advertiser list. + * + * \param pParam Add to periodic list parameters. + * + * \return Status error code. + * + * Add device to periodic advertiser list. + */ +/*************************************************************************************************/ +uint8_t LlAddDeviceToPeriodicAdvList(const LlDevicePerAdvList_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Remove device from periodic advertiser list command. + * + * \param pParam Remove from periodic list parameters. + * + * \return Status error code. + * + * + */ +/*************************************************************************************************/ +uint8_t LlRemoveDeviceFromPeriodicAdvList(const LlDevicePerAdvList_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Clear all devices in periodic advertiser list command. + * + * \return Status error code. + * + * Clear all devices in periodic advertiser list command. + */ +/*************************************************************************************************/ +uint8_t LlClearPeriodicAdvList(void); + +/*************************************************************************************************/ +/*! + * \brief Read total number of devices in periodic advertiser list command. + * + * \param pListSize Return size value of periodic advertiser list + * + * \return Status error code. + * + * Read total number of devices in periodic advertiser list command. + */ +/*************************************************************************************************/ +uint8_t LlReadPeriodicAdvListSize(uint8_t *pListSize); + +/*! \} */ /* LL_API_OBSERVER */ + +/*! \addtogroup LL_API_CONN + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Disconnect a connection. + * + * \param handle Connection handle. + * \param reason Disconnect reason. + * + * \return Status error code. + * + * Disconnect a connection. + */ +/*************************************************************************************************/ +uint8_t LlDisconnect(uint16_t handle, uint8_t reason); + +/*************************************************************************************************/ +/*! + * \brief Set connection's operational mode flags. + * + * \param handle Connection handle. + * \param flags Flags. + * \param enable TRUE to set flags or FALSE to clear flags. + * + * \return Status error code. + * + * Set connection's operational mode flags governing LL operations. + */ +/*************************************************************************************************/ +uint8_t LlSetConnOpFlags(uint16_t handle, uint32_t flags, bool_t enable); + +/*************************************************************************************************/ +/*! + * \brief Read remote features. + * + * \param handle Connection handle. + * + * \return Status error code. + * + * Read the link layer features of the remote device. + */ +/*************************************************************************************************/ +uint8_t LlReadRemoteFeat(uint16_t handle); + +/*************************************************************************************************/ +/*! + * \brief Read remote version information. + * + * \param handle Connection handle. + * + * \return Status error code. + * + * Read the version information of the remote device. + */ +/*************************************************************************************************/ +uint8_t LlReadRemoteVerInfo(uint16_t handle); + +/*************************************************************************************************/ +/*! + * \brief Get RSSI of a connection. + * + * \param handle Connection handle. + * \param pRssi RSSI value. + * + * \return Status error code. + * + * Get the current RSSI of a connection. + */ +/*************************************************************************************************/ +uint8_t LlGetRssi(uint16_t handle, int8_t *pRssi); + +/*************************************************************************************************/ +/*! + * \brief Get connection's TX power level. + * + * \param handle Connection handle. + * \param type Power level type. + * \param pLevel Transmit power level. + * + * \return Status error code. + * + * Get the TX power of a connection. + */ +/*************************************************************************************************/ +uint8_t LlGetTxPowerLevel(uint16_t handle, uint8_t type, int8_t *pLevel); + +/*************************************************************************************************/ +/*! + * \brief Set connection's TX power level. + * + * \param handle Connection handle. + * \param level Transmit power level. + * + * \return Status error code. + * + * Set the TX power of a connection. + */ +/*************************************************************************************************/ +uint8_t LlSetTxPowerLevel(uint16_t handle, int8_t level); + +/*************************************************************************************************/ +/*! + * \brief Update connection parameters. + * + * \param handle Connection handle. + * \param pConnSpec New connection specification. + * + * \return Status error code. + * + * Update the connection parameters of a connection. + */ +/*************************************************************************************************/ +uint8_t LlConnUpdate(uint16_t handle, const LlConnSpec_t *pConnSpec); + +/*************************************************************************************************/ +/*! + * \brief Remote connection parameter request reply. + * + * \param handle Connection handle. + * \param pConnSpec New connection specification. + * + * \return Status error code. + * + * Reply to a connection parameter request. + */ +/*************************************************************************************************/ +uint8_t LlRemoteConnParamReqReply(uint16_t handle, const LlConnSpec_t *pConnSpec); + +/*************************************************************************************************/ +/*! + * \brief Remote connection parameter request negative reply. + * + * \param handle Connection handle. + * \param reason Reason code. + * + * \return None. + * + * Negative reply to a connection parameter request. + */ +/*************************************************************************************************/ +uint8_t LlRemoteConnParamReqNegReply(uint16_t handle, uint8_t reason); + +/*************************************************************************************************/ +/*! + * \brief Set connection's channel map. + * + * \param handle Connection handle. + * \param pChanMap Channel map. + * + * \return Status error code. + * + * Set the channel map of a connection. + */ +/*************************************************************************************************/ +uint8_t LlSetChannelMap(uint16_t handle, const uint8_t *pChanMap); + +/*************************************************************************************************/ +/*! + * \brief Get connection's channel map. + * + * \param handle Connection handle. + * \param pChanMap Channel map. + * + * \return Status error code. + * + * Get the current channel map of a connection. + */ +/*************************************************************************************************/ +uint8_t LlGetChannelMap(uint16_t handle, uint8_t *pChanMap); + +/*************************************************************************************************/ +/*! + * \brief Set data length. + * + * \param handle Connection handle. + * \param txLen Maximum number of payload bytes for a Data PDU + * \param txTime Maximum microseconds for a Data PDU + * + * \return Status error code. + * + * Preferred maximum microseconds that the local Controller should use to transmit a + * single Link Layer Data Channel PDU. + */ +/*************************************************************************************************/ +uint8_t LlSetDataLen(uint16_t handle, uint16_t txLen, uint16_t txTime); + +/*************************************************************************************************/ +/*! + * \brief Read default data length. + * + * \param pMaxTxLen Maximum number of payload bytes for a Data PDU + * \param pMaxTxTime Maximum microseconds for a Data PDU + * + * \return None. + * + * Suggested length and microseconds that the local Controller should use to transmit a + * single Link Layer Data Channel PDU. + */ +/*************************************************************************************************/ +void LlReadDefaultDataLen(uint16_t *pMaxTxLen, uint16_t *pMaxTxTime); + +/*************************************************************************************************/ +/*! + * \brief Write default data length. + * + * \param maxTxLen Maximum number of payload bytes for a Data PDU + * \param maxTxTime Maximum microseconds for a Data PDU + * + * \return Status error code. + * + * Suggested length and microseconds that the local Controller should use to transmit a + * single Link Layer Data Channel PDU. + */ +/*************************************************************************************************/ +uint8_t LlWriteDefaultDataLen(uint16_t maxTxLen, uint16_t maxTxTime); + +/*************************************************************************************************/ +/*! + * \brief Read maximum data length. + * + * \param pMaxTxLen Maximum number of payload bytes for a Tx Data PDU + * \param pMaxTxTime Maximum microseconds for a Tx Data PDU + * \param pMaxRxLen Maximum number of payload bytes for a Rx Data PDU + * \param pMaxRxTime Maximum microseconds for a Rx Data PDU + * + * \return None. + * + * Read the Controller's maximum supported payload octets and packet duration times for + * transmission and reception. + */ +/*************************************************************************************************/ +void LlReadMaximumDataLen(uint16_t *pMaxTxLen, uint16_t *pMaxTxTime, uint16_t *pMaxRxLen, uint16_t *pMaxRxTime); + +/*************************************************************************************************/ +/*! + * \brief Read current transmitter PHY and receive PHY. + * + * \param handle Connection handle. + * \param pTxPhy Storage for transmitter PHY. + * \param pRxPhy Storage for receiver PHY. + * + * \return Status error code. + * + * Read current transmitter PHY and receive PHY. + */ +/*************************************************************************************************/ +uint8_t LlReadPhy(uint16_t handle, uint8_t *pTxPhy, uint8_t *pRxPhy); + +/*************************************************************************************************/ +/*! + * \brief Set default PHYs. + * + * \param allPhys All PHYs preferences. + * \param txPhys Preferred transmitter PHYs. + * \param rxPhys Preferred receiver PHYs. + * + * \return Status error code. + * + * Specify the preferred values for the transmitter PHY and receiver PHY to be used for all + * subsequent connections over the LE transport. + */ +/*************************************************************************************************/ +uint8_t LlSetDefaultPhy(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys); + +/*************************************************************************************************/ +/*! + * \brief Set PHY for a connection. + * + * \param handle Connection handle. + * \param allPhys All PHYs preferences. + * \param txPhys Preferred transmitter PHYs. + * \param rxPhys Preferred receiver PHYs. + * \param phyOptions PHY options. + * + * \return Status error code. + * + * Set PHY preferences for a given connection. The controller might not be able to make the + * change (e.g., because the peer does not support the requested PHY) or may decide that the + * current PHY is preferable. + */ +/*************************************************************************************************/ +uint8_t LlSetPhy(uint16_t handle, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions); + +/*************************************************************************************************/ +/*! + * \brief Set local minimum number of used channels. + * + * \param phys Bitmask for the PHYs. + * \param pwrThres Power threshold. + * \param minUsedCh Minimum number of used channels. + * + * \return Status error code. + * + * Set local minimum number of used channels. + */ +/*************************************************************************************************/ +uint8_t LlSetLocalMinUsedChan(uint8_t phys, int8_t pwrThres, uint8_t minUsedCh); + +/*************************************************************************************************/ +/*! + * \brief Get peer minimum number of used channels. + * + * \param handle Connection handle. + * \param pPeerMinUsedChan Storage for the peer minimum number of used channels. + * + * \return Status error code. + * + * Get peer minimum number of used channels. + */ +/*************************************************************************************************/ +uint8_t LlGetPeerMinUsedChan(uint16_t handle, uint8_t *pPeerMinUsedChan); + +/*! \} */ /* LL_API_CONN */ + +/*! \addtogroup LL_API_CENTRAL + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Create connection. + * + * \param pInitParam Initiating parameters. + * \param pConnSpec Connection specification. + * + * \return Status error code. + * + * Create a connection to the specified peer address with the specified connection parameters. + * This function is only when operating in master role. + */ +/*************************************************************************************************/ +uint8_t LlCreateConn(const LlInitParam_t *pInitParam, const LlConnSpec_t *pConnSpec); + +/*************************************************************************************************/ +/*! + * \brief Extended create connection. + * + * \param pInitParam Initiating parameters. + * \param scanParam Scan parameters table indexed by PHY. + * \param connSpec Connection specification table indexed by PHY. + * + * \return Status error code. + * + * Create a connection to the specified peer address with the specified connection parameters. + * This function is only when operating in master role. + */ +/*************************************************************************************************/ +uint8_t LlExtCreateConn(const LlExtInitParam_t *pInitParam, const LlExtInitScanParam_t scanParam[], const LlConnSpec_t connSpec[]); + +/*************************************************************************************************/ +/*! + * \brief Cancel a create connection operation. + * + * \return None. + * + * Cancel a connection before it is established. This function is only used when operating + * in master role. + */ +/*************************************************************************************************/ +void LlCreateConnCancel(void); + +/*! \} */ /* LL_API_CENTRAL */ + +/*! \addtogroup LL_API_ENCRYPT + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Encrypt data. + * + * \param pKey Encryption key. + * \param pData 16 bytes of plain text data. + * + * \return Status error code. + * + * Request the LL to encryption a block of data in place. + */ +/*************************************************************************************************/ +uint8_t LlEncrypt(uint8_t *pKey, uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Start encryption. + * + * \param handle Connection handle. + * \param pRand Pointer to the random number. + * \param diversifier Diversifier value. + * \param pKey Pointer to the encryption key. + * + * \return Status error code. + * + * Start or restart link layer encryption on a connection. This function is only used when + * operating in master role. + */ +/*************************************************************************************************/ +uint8_t LlStartEncryption(uint16_t handle, const uint8_t *pRand, uint16_t diversifier, const uint8_t *pKey); + +/*************************************************************************************************/ +/*! + * \brief Reply to a LTK request. + * + * \param handle Connection handle. + * \param pKey Pointer to new key. + * + * \return Status error code. + * + * Provide the requested LTK encryption key. This function is only used when operating in + * slave mode. + */ +/*************************************************************************************************/ +uint8_t LlLtkReqReply(uint16_t handle, const uint8_t *pKey); + +/*************************************************************************************************/ +/*! + * \brief Negative reply to a LTK request. + * + * \param handle Connection handle. + * + * \return Status error code. + * + * Requested LTK encryption key not available. This function is only used when operating in + * slave mode. + */ +/*************************************************************************************************/ +uint8_t LlLtkReqNegReply(uint16_t handle); + +/*************************************************************************************************/ +/*! + * \brief Read authenticated payload timeout value. + * + * \param handle Connection handle. + * \param pTimeout Pointer to timeout value. + * + * \return Status error code. + * + * Read authenticated payload timeout value for the given handle. + */ +/*************************************************************************************************/ +uint8_t LlReadAuthPayloadTimeout(uint16_t handle, uint16_t *pTimeout); + +/*************************************************************************************************/ +/*! + * \brief Write authenticated payload timeout value. + * + * \param handle Connection handle. + * \param timeout New timeout value. + * + * \return Status error code. + * + * Write new authenticated payload timeout value for the given handle. + */ +/*************************************************************************************************/ +uint8_t LlWriteAuthPayloadTimeout(uint16_t handle, uint16_t timeout); + +/*************************************************************************************************/ +/*! + * \brief Get encryption mode used in a connection. + * + * \param handle Connection handle. + * \param pMode Storage for encryption mode. + * + * \return Status error code. + * + * Get the encryption mode used by a connection. + */ +/*************************************************************************************************/ +uint8_t LlGetEncMode(uint16_t handle, LlEncMode_t *pMode); + +/*************************************************************************************************/ +/*! + * \brief Set encryption mode used in a connection. + * + * \param handle Connection handle. + * \param pMode New encryption mode. + * + * \return Status error code. + * + * Set the encryption mode used by a connection. Must be called before encryption is started or + * when encryption is paused. + */ +/*************************************************************************************************/ +uint8_t LlSetEncMode(uint16_t handle, const LlEncMode_t *pMode); + +/*! \} */ /* LL_API_ENCRYPT */ + +/*! \addtogroup LL_API_DATA + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Get the maximum ACL buffers size. + * + * \return Maximum buffers size in bytes. + */ +/*************************************************************************************************/ +uint16_t LlGetAclMaxSize(void); + +/*************************************************************************************************/ +/*! + * \brief Get the number of buffers in the LL ACL transmit queue. + * + * \return Number of buffers. + */ +/*************************************************************************************************/ +uint8_t LlGetAclTxBufs(void); + +/*************************************************************************************************/ +/*! + * \brief Get the number of buffers in the LL ACL receive queue. + * + * \return Number of buffers. + */ +/*************************************************************************************************/ +uint8_t LlGetAclRxBufs(void); + +/*************************************************************************************************/ +/*! + * \brief Send an ACL data packet. + * + * \param pData Data buffer + * + * \return None. + * + * Send an ACL data packet. pData points to an ACL buffer formatted according to [1]; the host + * must set the connection handle, flags, and length fields in the buffer. + */ +/*************************************************************************************************/ +void LlSendAclData(uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Receive an ACL data packet + * + * \return Data buffer. + * + * Receive an ACL data packet. This function returns a pointer to an ACL buffer formatted + * according to [1]. The host must parse the header to determine the connection handle, flags, + * and length fields. If no ACL buffers are available this function returns NULL. + * + * The host must deallocate the buffer by calling WsfMsgFree() and call LlRecvBufCmpl() to + * update LL accounting. + */ +/*************************************************************************************************/ +uint8_t *LlRecvAclData(void); + +/*************************************************************************************************/ +/*! + * \brief Indicate that received ACL data buffer has been deallocated + * + * \param numBufs Number of completed packets. + * + * \return None. + * + * Indicate that received ACL data buffer has been deallocated. + */ +/*************************************************************************************************/ +void LlRecvAclDataComplete(uint8_t numBufs); + +/*! \} */ /* LL_API_DATA */ + +/*! \addtogroup LL_API_TEST + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Enter transmit test mode. + * + * \param rfChan RF channel number, i.e. "rfChan = (F - 2402) / 2)". + * \param len Length of test data. + * \param pktType Test packet payload type. + * \param numPkt Auto terminate after number of packets, 0 for infinite. + * + * \return Status error code. + * + * Start the transmit test mode on the given channel. + */ +/*************************************************************************************************/ +uint8_t LlTxTest(uint8_t rfChan, uint8_t len, uint8_t pktType, uint16_t numPkt); + +/*************************************************************************************************/ +/*! + * \brief Enter receive test mode. + * + * \param rfChan RF channel number, i.e. "rfChan = (F - 2402) / 2)". + * \param numPkt Auto terminate after number of successful packets, 0 for infinite. + * + * \return Status error code. + * + * Start the receive test mode on the given channel. + */ +/*************************************************************************************************/ +uint8_t LlRxTest(uint8_t rfChan, uint16_t numPkt); + +/*************************************************************************************************/ +/*! + * \brief Enter enhanced transmit test mode. + * + * \param rfChan RF channel number, i.e. "rfChan = (F - 2402) / 2)". + * \param len Length of test data. + * \param pktType Test packet payload type. + * \param phy Transmitter PHY. + * \param numPkt Auto terminate after number of packets, 0 for infinite. + * + * \return Status error code. + * + * Start the transmit test mode on the given channel. + */ +/*************************************************************************************************/ +uint8_t LlEnhancedTxTest(uint8_t rfChan, uint8_t len, uint8_t pktType, uint8_t phy, uint16_t numPkt); + +/*************************************************************************************************/ +/*! + * \brief Enter enhanced receive test mode. + * + * \param rfChan RF channel number, i.e. "rfChan = (F - 2402) / 2)". + * \param phy Receiver PHY. + * \param modIdx Modulation index. + * \param numPkt Auto terminate after number of successful packets, 0 for infinite. + * + * \return Status error code. + * + * Start the receive test mode on the given channel. + */ +/*************************************************************************************************/ +uint8_t LlEnhancedRxTest(uint8_t rfChan, uint8_t phy, uint8_t modIdx, uint16_t numPkt); + +/*************************************************************************************************/ +/*! + * \brief End test mode. + * + * \param pRpt Report return buffer. + * + * \return Status error code. + * + * End test mode and return the report. + */ +/*************************************************************************************************/ +uint8_t LlEndTest(LlTestReport_t *pRpt); + +/*************************************************************************************************/ +/*! + * \brief Set pattern of errors for Tx test mode. + * + * \param pattern Error pattern (1s = no error; 0s = CRC failure). + * + * \return Status error code. + * + * Set pattern of errors for Tx test mode. + * + * \note The error pattern must be set after the Tx test is started. + */ +/*************************************************************************************************/ +uint8_t LlSetTxTestErrorPattern(uint32_t pattern); + +/*! \} */ /* LL_API_TEST */ + +/*! \addtogroup LL_API_DIAG + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Get advertising set context size. + * + * \param pMaxAdvSets Buffer to return the maximum number of advertising sets. + * \param pAdvSetCtxSize Buffer to return the size in bytes of the advertising set context. + * + * Return the advertising set context sizes. + */ +/*************************************************************************************************/ +void LlGetAdvSetContextSize(uint8_t *pMaxAdvSets, uint16_t *pAdvSetCtxSize); + +/*************************************************************************************************/ +/*! + * \brief Get connection context size. + * + * \param pMaxConn Buffer to return the maximum number of connections. + * \param pConnCtxSize Buffer to return the size in bytes of the connection context. + * + * Return the connection context sizes. + */ +/*************************************************************************************************/ +void LlGetConnContextSize(uint8_t *pMaxConn, uint16_t *pConnCtxSize); + +/*************************************************************************************************/ +/*! + * \brief Get the LL handler watermark level. + * + * \return Watermark level in microseconds. + */ +/*************************************************************************************************/ +uint16_t LlStatsGetHandlerWatermarkUsec(void); + +/*! \} */ /* LL_API_DIAG */ + + +#ifdef __cplusplus +}; +#endif + +#endif /* LL_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_init_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_init_api.h new file mode 100644 index 0000000000..7762e50dad --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_init_api.h @@ -0,0 +1,104 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief LL initialization implementation file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Initialization conditional compilation are used to control LL initialization options. + * Define one or more of the following to enable roles and features. + * + * - INIT_BROADCASTER (default) + * - INIT_OBSERVER + * - INIT_PERIPHERAL + * - INIT_CENTRAL + * - INIT_ENCRYPTED + * + * \note Each feature may require additional \ref LlRtCfg_t requirements. + */ +/*************************************************************************************************/ + +#ifndef LL_INIT_API_H +#define LL_INIT_API_H + +#include "wsf_types.h" +#include "bb_api.h" +#include "ll_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_INIT_API + * \{ + */ + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +#ifndef INIT_BROADCASTER +/*! \brief Initialize broadcaster feature. */ +#define INIT_BROADCASTER +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Runtime configuration parameters. */ +typedef struct +{ + const BbRtCfg_t *pBbRtCfg; /*!< BB runtime configuration. */ + const uint8_t wlSizeCfg; /*!< Whitelist size configuration. */ + const uint8_t rlSizeCfg; /*!< Resolving list size configuration. */ + const uint8_t plSizeCfg; /*!< Periodic list size configuration. */ + const LlRtCfg_t *pLlRtCfg; /*!< LL runtime configuration. */ + uint8_t *pFreeMem; /*!< Pointer to free memory, returns adjusted location of free memory. */ + uint32_t freeMemAvail; /*!< Amount of free memory available, returns adjusted amount of free memory. */ +} LlInitRtCfg_t; + +/************************************************************************************************** + Functions Declarations +**************************************************************************************************/ + +/* System initializers. */ +uint32_t LlInitStdInit(LlInitRtCfg_t *pCfg); +uint32_t LlInitExtInit(LlInitRtCfg_t *pCfg); +uint32_t LlInitControllerInit(LlInitRtCfg_t *pCfg); +uint32_t LlInitControllerExtInit(LlInitRtCfg_t *pCfg); + +/* Intermediate initializers. */ +uint32_t LlInitSetBbRtCfg(const BbRtCfg_t *pBbRtCfg, const uint8_t wlSizeCfg, const uint8_t rlSizeCfg, + const uint8_t plSizeCfg, uint8_t *pFreeMem, uint32_t freeMemAvail); +uint32_t LlInitSetLlRtCfg(const LlRtCfg_t *pLlRtCfg, uint8_t *pFreeMem, uint32_t freeMemAvail); +void LlInitBbInit(void); +void LlInitBbAuxInit(void); +void LlInitSchInit(void); +void LlInitLlInit(bool_t initHandler); +void LlInitChciTrInit(void); +void LlInitLhciInit(void); +void LlMathSetSeed(const uint32_t *pSeed); + +/*! \} */ /* LL_INIT_API */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LL_INIT_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_tester_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_tester_api.h new file mode 100644 index 0000000000..fd96db7db7 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/ll_tester_api.h @@ -0,0 +1,320 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer tester interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LL_TESTER_API_H +#define LL_TESTER_API_H + +#include "wsf_types.h" +#include "ll_api.h" +#include "lctr_api.h" + +/* Access internal definitions. */ +#include "../../sources/ble/lctr/lctr_pdu_conn.h" + +/* Require compile time directive. */ +#if (LL_ENABLE_TESTER != TRUE) +#error "LL_ENABLE_TESTER compilation directive must be set to 1." +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Tester acknowledgement mode. */ +enum +{ + LL_TESTER_ACK_MODE_NORMAL = 0, /*!< Ack packets according to normal acknowledgement/flow control scheme. */ + LL_TESTER_ACK_MODE_NO_RX_ACK = 1, /*!< Do not acknowledge Rx packets. */ + LL_TESTER_ACK_MODE_IGNORE_TX_ACK = 2 /*!< Ignore acknowledgements of Tx packets. */ +}; + +#define LL_TESTER_TRIGGER_NONEMPTY 0xFE /*!< Trigger only on non-empty packets. */ +#define LL_TESTER_TRIGGER_ALWAYS 0xFF /*!< Always trigger. */ + +#define LL_TESTER_ADVB_MAX_LEN LL_ADVB_MAX_LEN + 4 /*!< Maximum allowed ADVB length. */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Link layer tester control block */ +typedef struct +{ + /* Advertising channel override values. */ + /* Place here to 32-bit align. */ + uint8_t txAdvPdu[LL_TESTER_ADVB_MAX_LEN]; /*!< Advertising PDU override buffer. */ + uint32_t advAccessAddrRx; /*!< Advertising access address override (Rx). */ + uint32_t advAccessAddrTx; /*!< Advertising access address override (Tx). */ + /* Place here to 32-bit align. */ + uint8_t txScanReqPdu[LL_TESTER_ADVB_MAX_LEN]; /*!< Scan request PDU override buffer. */ + uint32_t advCrcInitRx; /*!< Advertising CRC value override (Rx). */ + uint32_t advCrcInitTx; /*!< Advertising CRC value override (Tx). */ + /* Place here to 32-bit align. */ + uint8_t txScanRspPdu[LL_TESTER_ADVB_MAX_LEN]; /*!< Scan response PDU override buffer. */ + bool_t txAdvPduLen; /*!< Advertising PDU override buffer length, 0 to disable. */ + bool_t txScanReqPduLen; /*!< Scan request PDU override buffer length, 0 to disable. */ + bool_t txScanRspPduLen; /*!< Scan response PDU override buffer length, 0 to disable. */ + + /* Extended advertising channel override values. */ + uint32_t auxAccessAddrRx; /*!< Auxiliary advertising access address override (Rx). */ + uint32_t auxAccessAddrTx; /*!< Auxiliary advertising access address override (Tx). */ + uint32_t auxCrcInitRx; /*!< Advertising CRC value override (Rx). */ + uint32_t auxCrcInitTx; /*!< Advertising CRC value override (Tx). */ + struct + { + uint8_t pduMatch; /*!< PDU type to override. */ + uint8_t len; /*!< Length of override buffer. */ + uint8_t buf[LL_CONN_IND_PDU_LEN]; + /*!< Override request buffer. */ + } auxReq; /*!< Auxiliary request buffer override parameters. */ + struct + { + uint16_t pduMatchMask; /*!< Enable override bitmask of PDU types. */ + uint8_t modifyMask; /*!< Enable extended header field override bitmask. */ + uint64_t AdvA; /*!< AdvA override value. */ + uint64_t TargetA; /*!< TargetA override value. */ + uint8_t SuppInfo; /*!< SuppInfo override value. */ + uint16_t ADI; /*!< ADI override value. */ + int8_t TxPower; /*!< TxPower override value. */ + } extHdr; /*!< Extended header override values. */ + + /* Data channel override values. */ + uint32_t dataAccessAddrRx; /*!< Data channel access address override (Rx). */ + uint32_t dataAccessAddrTx; /*!< Data channel access address override (Tx). */ + uint32_t dataCrcInitRx; /*!< Data channel CRC value override (Rx). */ + uint32_t dataCrcInitTx; /*!< Data channel CRC value override (Tx). */ + + /* Connection parameter override values. */ + bool_t connIndEnabled; /*!< Connection indication override packet enabled. */ + lctrConnInd_t connInd; /*!< Connection indication override packet. */ + bool_t connUpdIndEnabled; /*!< Connection update indication override packet enabled. */ + lctrConnUpdInd_t connUpdInd; /*!< Connection update indication override packet. */ + bool_t connParamReqEnabled;/*!< Connection parameter request override packet enabled. */ + lctrConnParam_t connParamReq; /*!< Connection parameter request override packet. */ + + /* Data length override values. */ + bool_t dataLenReqEnabled; /*!< Local Data PDU parameters enabled. */ + lctrDataLen_t dataLenReq; /*!< Local Data PDU parameters. */ + + uint32_t connIntervalUs; /*!< Connection interval override. */ + uint16_t eventCounterOffset; /*!< Event counter offset value. */ + + uint32_t txLlcpFilter; /*!< Filter for LLCP Tx. */ + uint32_t rxLlcpFilter; /*!< Filter for LLCP Rx. */ + bool_t dataTriggerEnabled; /*!< Trigger is enabled. */ + uint8_t dataTriggerPdu; /*!< PDU on which to trigger data. */ + bool_t dataTriggerAfter; /*!< Data sent after PDU. */ + + /* Packet override values. */ + uint32_t pktMic; /*!< Packet MIC override XOR value. */ + uint8_t pktLlId; /*!< Packet LLID override XOR value. */ + + /* LLCP handling. */ + bool_t llcpForwardEnabled; /*!< LLCP packet to host enable. */ + bool_t llcpLlcpIntercept; /*!< LLCP intercept enable. */ + + /* Acknowledgement/flow control. */ + uint8_t ackMode; /*!< Acknowledgement mode. */ + uint8_t ackTrigger; /*!< Rx datum or condition on which to trigger special ack handling. */ +} llTesterCtrlBlock_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern llTesterCtrlBlock_t llTesterCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*! \addtogroup LL_TESTER_API_INIT + * \{ */ + +void LlTesterInit(void); + +/* \} */ + +/*! \addtogroup LL_TESTER_API_ADV_CHAN + * \{ */ + +/* Advertising channel override */ +void LlTesterSetAdvAccessAddr(uint32_t accessAddr, bool_t forRx); +void LlTesterSetAdvCrcInit(uint32_t crcInit, bool_t forRx); + +/* Advertising data exchange */ +uint8_t LlTesterSetTxAdvPdu(uint8_t *pBuf, uint8_t len); +uint8_t LlTesterSetTxScanReqPdu(uint8_t *pBuf, uint8_t len); +uint8_t LlTesterSetTxScanRspPdu(uint8_t *pBuf, uint8_t len); + +/* Extended advertising override */ +void LlTesterSetAuxAccessAddr(uint32_t accessAddr, bool_t forRx); +void LlTesterSetAuxCrcInit(uint32_t crcInit, bool_t forRx); +void LlTesterSetTxAuxReqPdu(uint8_t pduMatch, uint8_t *pBuf, uint8_t len); +void LlTesterSetExtAdvHdrFields(uint16_t pduMatchMask, uint8_t modifyMask, + uint8_t *pAdvA, uint8_t *pTargetA, uint8_t SuppInfo, uint16_t ADI, int8_t TxPower); + +/* \} */ + +/*! \addtogroup LL_TESTER_API_DATA_CHAN + * \{ */ + +/* Data channel override */ +void LlTesterSetDataAccessAddr(uint32_t accessAddr, bool_t forRx); +uint8_t LlTesterGetDataAccessAddr(uint16_t handle, uint32_t *pAccessAddr); +void LlTesterSetDataCrcInit(uint32_t crcInit, bool_t forRx); +uint8_t LlTesterGetDataCrcInit(uint16_t handle, uint32_t *pCrcInit); + +/* Data control override */ +void LlTesterSetConnInd(uint32_t accessAddr, uint32_t crcInit, uint8_t txWinSize, uint16_t txWinOffset, + uint16_t interval, uint16_t latency, uint16_t timeout, uint64_t chanMask, + uint8_t hopInc, uint8_t masterSca); +void LlTesterAdjConnInterval(uint32_t intervalUs); + +/* Data packet override */ +void LlTesterSetPktLlId(uint8_t id); +void LlTesterSetPktMic(uint32_t mic); + +/* Acknowledgement/flow control override */ +void LlTesterSetAckMode(uint8_t ackMode, uint8_t ackTrigger); + +/* Data exchange */ +uint8_t LlTesterTxDataPdu(uint16_t handle, uint8_t *pBuf, uint8_t len); + +/* \} */ + +/*! \addtogroup LL_TESTER_API_LLCP + * \{ */ + +void LlTesterForwardLlcpToHost(bool_t enable, bool_t intercept); +void LlTesterSetEventCounterOffset(uint16_t offset); +uint8_t LlTesterSendConnUpdInd(uint16_t handle, + uint8_t txWinSize, uint16_t txWinOffset, + uint16_t interval, uint16_t latency, uint16_t timeout); +uint8_t LlTesterSendConnParamReq(uint16_t handle, + uint16_t connIntervalMin, uint16_t connIntervalMax, + uint16_t connLatency, uint16_t supTimeout, uint8_t prefPeriod, + uint16_t refConnEvtCnt, uint16_t *pOffset); +uint8_t LlTesterSendDataLen(uint16_t handle, + uint16_t rxLen, uint16_t rxTime, + uint16_t txLen, uint16_t txTime); +uint8_t LlTesterSendPhyReq(uint16_t handle, uint8_t txPhys, uint8_t rxPhys); +uint8_t LlTesterSendPhyUpdateInd(uint16_t handle, uint8_t mToSPhy, uint8_t sToMPhy); +void LlTesterEnableRxFlowControl(bool_t enable); +void LlTesterSetTxLlcpFilter(uint32_t filter); +void LlTesterSetRxLlcpFilter(uint32_t filter); +void LlTesterSetDataTrigger(uint8_t pdu, bool_t enable, bool_t after); + +/* \} */ + +/*! \addtogroup LL_TESTER_API_BB + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Adjust Tx TIFS timing value. + * + * \param adjNs Adjustment value in nanoseconds. + * + * \return None. + * + * Adjust the TIFS timing of transmit by the given signed value of timer ticks. + * If adjustment value is out of range, maximum allowed value is used. + */ +/*************************************************************************************************/ +void BbTesterAdjTxTifsNs(int16_t adjNs); + +/*************************************************************************************************/ +/*! + * \brief Trigger channel modifications on matching Tx packet header. + * + * \param hdrMask Header mask. + * \param hdrValue Match value. + * + * \return None. + * + * Modify the transmit channel parameters of a packet only when the Tx packet header matches + * the given parameters. This applies to the modification parameter provided by the following + * routines: + * + * - \ref BbTesterSetInvalidCrcInit() + * - \ref BbTesterSetInvalidAccessAddress() + */ +/*************************************************************************************************/ +void BbTesterSetModifyTxPktTrigger(uint16_t hdrMask, uint16_t hdrValue); + +/*************************************************************************************************/ +/*! + * \brief Invalidate CRC initialization value. + * + * \param chanMask Invalidate channel mask. + * \param adjMask Number of adjustments (0 to disable). + * \param forRx TRUE for Rx, FALSE for Tx. + * + * \return None. + * + * Force the receiver to receive a packet with CRC error if the receive channel is in + * \b chanMask while stepping through the invalid pattern in \b invalidMask. + */ +/*************************************************************************************************/ +void BbTesterSetInvalidCrcInit(uint64_t chanMask, uint32_t adjMask, bool_t forRx); + +/*************************************************************************************************/ +/*! + * \brief Invalidate access address value. + * + * \param chanMask Invalidate channel mask. + * \param invalidMask Enable mask for invalidating access address (0 to disable). + * \param forRx TRUE for Rx, FALSE for Tx. + * + * \return None. + * + * Force the receiver to receive a miss a packet if the receive channel is in + * \b chanMask while stepping through the invalid pattern in \b invalidMask. + */ +/*************************************************************************************************/ +void BbTesterSetInvalidAccessAddress(uint64_t chanMask, uint32_t invalidMask, bool_t forRx); + +/*************************************************************************************************/ +/*! + * \brief Enable bypassing PDU filtering. + * + * \param enable If TRUE enable bypass PDU filtering, FALSE otherwise. + * + * \return None. + * + * Enable bypassing PDU filtering. + */ +/*************************************************************************************************/ +void BbTesterEnablePduFilterBypass(bool_t enable); + +/* \} */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LL_TESTER_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/sch_api_ble.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/sch_api_ble.h new file mode 100644 index 0000000000..11c07c6f1d --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/ble/sch_api_ble.h @@ -0,0 +1,58 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer scheduler interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef SCH_API_BLE_H +#define SCH_API_BLE_H + +#include "wsf_types.h" +#include "bb_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Resource manager */ +void SchRmInit(void); +uint32_t SchRmPreferredPeriodUsec(void); +bool_t SchRmAdd(uint8_t handle, uint32_t minUsec, uint32_t maxUsec, uint32_t durUsec, uint32_t *pInterUsec); +bool_t SchRmStartUpdate(uint8_t handle, uint32_t minUsec, uint32_t maxUsec, uint32_t durUsec, uint32_t *pInterUsec); +void SchRmCommitUpdate(uint8_t handle); +void SchRmRemove(uint8_t handle); +void SchRmSetReference(uint8_t handle); +uint32_t SchRmGetOffsetUsec(uint32_t rsvnOffs[], uint32_t maxOffsUsec, uint8_t handle); + +/* BLE time utilities */ +uint32_t SchBleCalcDataPktDurationUsec(uint8_t phy, uint16_t len); +uint32_t SchBleCalcAdvPktDurationUsec(uint8_t phy, uint8_t phyOptions, uint16_t len); +uint32_t SchBleCalcAuxPktDurationUsec(uint8_t phy, uint8_t phyOptions, uint16_t len); +void SchBleCalcAdvOpDuration(BbOpDesc_t *pBod); +bool_t SchBleGetNextMstConnDueTime(uint32_t *pDueTime); + +#ifdef __cplusplus +}; +#endif + +#endif /* SCH_API_BLE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/bb_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/bb_api.h new file mode 100644 index 0000000000..838f709988 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/bb_api.h @@ -0,0 +1,456 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \addtogroup BB_API Baseband (BB) API + * \{ + * + * The baseband porting layer is a protocol independent BB + radio abstraction layer. It allows + * the simultaneous operation of protocol specific schedulers to transport packets across each + * medium via a single multi-protocol baseband. This interface describes operations for the + * following protocols: + * + * - Bluetooth low energy: advertising and connections + * - ZigBee/802.15.4 (TBD) + * - BAN/802.15.6 (TBD) + * + * \dot + * digraph + * { + * node [shape=record, width=1.0, height=0.5, fontname=Helvetica, fontsize=8]; + * + * ble [label="BLE\nlink layer", style=filled, fillcolor=lightgray]; + * zigbee [label="802.15.4\nMAC", style=filled, fillcolor=lightgray]; + * ban [label="802.15.6\nMAC", style=filled, fillcolor=lightgray]; + * sch [label="Multi-protocol\nscheduler", style=filled, fillcolor=lightgray]; + * bb_drv [label="{ BB porting layer | BB specific driver }"]; + * bb_hw [label="BB hardware", style=filled, fillcolor=dimgray]; + * + * ble -> sch; + * ble -> bb_drv; + * zigbee -> sch; + * zigbee -> bb_drv; + * ban -> sch; + * ban -> bb_drv; + * sch -> bb_drv; + * bb_drv -> bb_hw [style=dashed]; + * } + * \enddot + * + * \defgroup BB_API_INIT Initialization + * \defgroup BB_API_BOD Baseband Operation Descriptors (BOD) + * \defgroup BB_API_CTRL Control interface + * \defgroup BB_API_BLE Bluetooth LE Protocol + * + * \} + */ +/*************************************************************************************************/ + +#ifndef BB_API_H +#define BB_API_H + +#include "wsf_types.h" +#include "cfg_mac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \addtogroup BB_API_BOD + * \{ */ + +/*! \brief Protocol types */ +enum +{ + BB_PROT_NONE, /*!< Non-protocol specific operation. */ + BB_PROT_BLE, /*!< Bluetooth Low Energy normal mode. */ + BB_PROT_BLE_DTM, /*!< Bluetooth Low Energy direct test mode. */ + BB_PROT_PRBS15, /*!< Enable the continuous PRBS15 transmit sequence. */ + BB_PROT_15P4, /*!< 802.15.4. */ + BB_PROT_NUM /*!< Number of protocols. */ +}; + +/*! \brief Status codes */ +enum +{ + BB_STATUS_SUCCESS, /*!< Operation successful. */ + BB_STATUS_FAILED, /*!< General failure. */ + BB_STATUS_CANCELED, /*!< Receive canceled. */ + BB_STATUS_RX_TIMEOUT, /*!< Receive packet timeout. */ + BB_STATUS_CRC_FAILED, /*!< Receive packet with CRC verification failed. */ + BB_STATUS_FRAME_FAILED, /*!< Receive packet with frame verification failed. */ + BB_STATUS_ACK_FAILED, /*!< ACK packet failure. */ + BB_STATUS_ACK_TIMEOUT, /*!< ACK packet timeout. */ + BB_STATUS_TX_CCA_FAILED, /*!< Transmit CCA failure. */ + BB_STATUS_TX_FAILED /*!< Transmit failure. */ +}; + +/*! \brief PHY types. */ +enum +{ + BB_PHY_BLE_1M = 1, /*!< Bluetooth Low Energy 1Mbps PHY. */ + BB_PHY_BLE_2M = 2, /*!< Bluetooth Low Energy 2Mbps PHY. */ + BB_PHY_BLE_CODED = 3, /*!< Bluetooth Low Energy Coded PHY (data coding unspecified). */ + BB_PHY_15P4 = 4, /*!< 802.15.4 PHY. */ +}; + +/*! \brief PHY options. */ +enum +{ + BB_PHY_OPTIONS_DEFAULT = 0, /*!< BB defined PHY Options behavior. */ + BB_PHY_OPTIONS_BLE_S2 = 1, /*!< Always use S=2 coding when transmitting on LE Coded PHY. */ + BB_PHY_OPTIONS_BLE_S8 = 2 /*!< Always use S=8 coding when transmitting on LE Coded PHY. */ +}; + +/*! \} */ /* BB_API_BOD */ + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Binary divide with 1,000,000 divisor (n[max]=0xFFFFFFFF). */ +#define BB_MATH_DIV_10E6(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(4295)) >> 32)) + +#if (BB_CLK_RATE_HZ == 1000000) +/*! \brief Return microseconds (no conversion required). */ +#define BB_US_TO_BB_TICKS(us) (us) +#elif (BB_CLK_RATE_HZ == 8000000) +/*! \brief Compute BB ticks from given time in microseconds (max time is interval=1,996s). */ +#define BB_US_TO_BB_TICKS(us) ((uint32_t)((us) << 3)) +#elif (BB_CLK_RATE_HZ == 32768) +/*! \brief Compute BB ticks from given time in microseconds (max time is interval=1,996s). */ +#define BB_US_TO_BB_TICKS(us) ((uint32_t)(((uint64_t)(us) * UINT64_C(549755)) >> 24)) /* calculated value may be one tick low */ +#else +/*! \brief Compute BB ticks from given time in microseconds (max time is interval=1,996s). */ +#define BB_US_TO_BB_TICKS(us) BB_MATH_DIV_10E6((uint64_t)(us) * (uint64_t)(BB_CLK_RATE_HZ)) +#endif + +#if (BB_CLK_RATE_HZ == 1000000) +/*! \brief BB ticks to microseconds (no conversion required). */ +#define BB_TICKS_TO_US(n) (n) +#elif (BB_CLK_RATE_HZ == 8000000) +/*! \brief BB ticks to microseconds (8MHz). */ +#define BB_TICKS_TO_US(n) ((n) >> 3) +#elif (BB_CLK_RATE_HZ == 32768) +/*! \brief BB ticks to microseconds (32768 Hz). */ +#define BB_TICKS_TO_US(n) (uint32_t)(((uint64_t)(n) * 15625) >> 9) +#else +/*! \brief BB ticks to microseconds. */ +#define BB_TICKS_TO_US(n) (uint32_t)((uint64_t)(n) * 1000000 / BB_CLK_RATE_HZ) +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \addtogroup BB_API_INIT + * \{ */ + +/*! \brief Typical maximum duration to scan in a scan interval (BbRtCfg_t::maxScanPeriodMs). */ +#define BB_MAX_SCAN_PERIOD_MS 1000 + +/*! \brief Typical RF setup delay (BbRtCfg_t::rfSetupDelayUs). */ +#define BB_RF_SETUP_DELAY_US 150 + +/*! \brief Typical operation setup delay in microseconds (BbRtCfg_t::schSetupDelayUs). */ +#define BB_SCH_SETUP_DELAY_US 500 + + +/*! \brief BB runtime configuration parameters. */ +typedef struct +{ + /* Common */ + uint16_t clkPpm; /*!< Clock accuracy in PPM. */ + uint8_t rfSetupDelayUs; /*!< RF setup delay in microseconds. */ + + /* BLE */ + uint16_t maxScanPeriodMs; /*!< Maximum duration to scan in a scan interval. */ + + /* Scheduler */ + uint16_t schSetupDelayUs; /*!< Operation setup delay in microseconds. */ +} BbRtCfg_t; + +/*! \} */ /* BB_API_INIT */ + +/*! \addtogroup BB_API_BOD + * \{ */ + +/* Forward definition of BOD. */ +struct BbOpDesc_tag; + +/*! \brief BOD completion event callback signature. */ +typedef void (*BbBodCompCback_t)(void); + +/*! \brief BOD event callback signature. */ +typedef void (*BbBodCback_t)(struct BbOpDesc_tag *pBod); + +/*! \brief Protocol event callback signature. */ +typedef void (*BbProtCback_t)(void); + +/*! \brief BOD rescheduling policy (listed in priority order). */ +typedef enum +{ + BB_RESCH_FIXED_PREFERRED, /*!< BOD is fixed (rescheduling has limited recoverable consequences). */ + BB_RESCH_FIXED, /*!< BOD is fixed (rescheduling has recoverable consequences). */ + BB_RESCH_PERIODIC, /*!< BOD is periodic (rescheduling has consequences). */ + BB_RESCH_MOVEABLE_PREFERRED, /*!< BOD is movable (rescheduling has minor consequences). */ + BB_RESCH_MOVEABLE, /*!< BOD is movable (rescheduling has no consequences). */ + BB_RESCH_BACKGROUND /*!< BOD is single background task. */ +} BbReschPol_t; + +/*! \} */ /* BB_API_BOD */ + +/*! \addtogroup BB_API_BOD + * \{ */ + +/* Forward protocol data definitions. */ +struct BbBleData_tag; +struct Bb154Data_tag; + +/*! \brief Baseband operation descriptor (BOD). */ +typedef struct BbOpDesc_tag +{ + struct BbOpDesc_tag *pPrev; /*!< Previous BOD. */ + struct BbOpDesc_tag *pNext; /*!< Next BOD. */ + + uint32_t due; /*!< Absolute clock due time. */ + uint32_t minDurUsec; /*!< Minimum required duration in microseconds. */ + uint32_t maxDurUsec; /*!< Maximum required duration in microseconds. */ + uint16_t dueOffsetUsec; /*!< Due time offset in microseconds. */ + + uint8_t reschPolicy; /*!< Rescheduling policy. */ + + uint8_t protId; /*!< Protocol type. */ + + BbBodCback_t endCback; /*!< End of BOD callback (when BOD ends). */ + BbBodCback_t abortCback; /*!< Abort BOD callback (when BOD is removed before beginning). */ + + void *pCtx; /*!< Client defined context. */ + + union + { + struct BbBleData_tag *pBle; /*!< BLE operation data. */ + struct Bb154Data_tag *p154; /*!< 802.15.4 operation data. */ + } prot; /*!< Protocol specific data. */ +} BbOpDesc_t; + +/*! \} */ /* BB_API_BOD */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*! \addtogroup BB_API_INIT + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Initialize runtime configuration. + * + * \param pCfg Pointer to runtime configuration parameters (data must be static). + * + * \return None. + * + * This function initializes the BB subsystem's runtime configuration. + * + * \note This routine must be called only once before any other initialization routine. + */ +/*************************************************************************************************/ +void BbInitRunTimeCfg(const BbRtCfg_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Initialize the BB. + * + * \return None. + * + * Initialize baseband resources. + */ +/*************************************************************************************************/ +void BbInit(void); + +/*************************************************************************************************/ +/*! + * \brief Register operation completion handler. + * + * \param eventCback Event callback. + * + * \return None. + * + * Register operation completion handler. + */ +/*************************************************************************************************/ +void BbRegister(BbBodCompCback_t eventCback); + +/*************************************************************************************************/ +/*! + * \brief Register protocol handlers. + * + * \param protId Protocol ID. + * \param execOpCback Execute operation callback. + * \param cancelOpCback Cancel operation callback. + * \param startProtCback Start protocol callback. + * \param stopProtCback Stop protocol callback. + * + * \return None. + */ +/*************************************************************************************************/ +void BbRegisterProt(uint8_t protId, BbBodCback_t execOpCback, BbBodCback_t cancelOpCback, + BbProtCback_t startProtCback, BbProtCback_t stopProtCback); + +/*! \} */ /* BB_API_INIT */ + +/*! \addtogroup BB_API_CTRL + * \{ */ + +/*************************************************************************************************/ +/*! + * \brief Start BB processing of given protocol. + * + * \param protId Protocol ID. + * + * \return None. + * + * Enable BB and start processing the list of BODs. This routine may be called several times, if + * a protocol layers has several simultaneously-enabled operations. However, \ref BbStop() must + * be called an equal number of time to disable the baseband. + */ +/*************************************************************************************************/ +void BbStart(uint8_t protId); + +/*************************************************************************************************/ +/*! + * \brief Stop BB processing of given protocol. + * + * \param protId Protocol ID. + * + * Disable BB processing of BODs. + * + * \note For any particular protocol, calls to \ref BbStart() and \ref BbStop() must be + * balanced to ensure that the hardware is disabled if and only if appropriate. + */ +/*************************************************************************************************/ +void BbStop(uint8_t protId); + +/*************************************************************************************************/ +/*! + * \brief Execute BOD. + * + * \param pBod Pointer to the BOD to execute. + * + * \return None. + * + * Execute the protocol specific BOD handler. + */ +/*************************************************************************************************/ +void BbExecuteBod(BbOpDesc_t *pBod); + +/*************************************************************************************************/ +/*! + * \brief Cancel current executing BOD. + * + * \return None. + */ +/*************************************************************************************************/ +void BbCancelBod(void); + +/*************************************************************************************************/ +/*! + * \brief Get the currently-executing BOD. + * + * \return Currently-executing BOD. + */ +/*************************************************************************************************/ +BbOpDesc_t *BbGetCurrentBod(void); + +/*************************************************************************************************/ +/*! + * \brief Cancel current executing BOD. + * + * \return None. + * + * \note This function is expected to be called during the execution context of the + * current executing BOD, typically in the related ISRs. + */ +/*************************************************************************************************/ +void BbSetBodTerminateFlag(void); + +/*************************************************************************************************/ +/*! + * \brief Get termination state of current executing BOD. + * + * \return TRUE if termination flag set, FALSE otherwise. + */ +/*************************************************************************************************/ +bool_t BbGetBodTerminateFlag(void); + +/*************************************************************************************************/ +/*! + * \brief Terminate a BOD immediately. + * + * \return None. + * + * \note This function is expected to be called during the execution context of the + * current executing BOD, typically in the related ISRs. + */ +/*************************************************************************************************/ +void BbTerminateBod(void); + +/*************************************************************************************************/ +/*! + * \brief Get BB clock accuracy. + * + * \return Clock accuracy in part per million. + * + * Returns the current BB clock accuracy. + */ +/*************************************************************************************************/ +uint16_t BbGetClockAccuracy(void); + +/*************************************************************************************************/ +/*! + * \brief Get scheduler setup delay. + * + * \return Scheduler setup delay in microseconds. + * + * Returns the scheduler setup delay. + */ +/*************************************************************************************************/ +uint16_t BbGetSchSetupDelayUs(void); + +/*************************************************************************************************/ +/*! + * \brief Returns the ID of the active protocol. + * + * \return Protocol operation in progress. + */ +/*************************************************************************************************/ +uint8_t BbGetActiveProtocol(void); + +/*! \} */ /* BB_API_CTRL */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac.h new file mode 100644 index 0000000000..cfc63c384b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac.h @@ -0,0 +1,50 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief MAC system configuration. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CFG_MAC_H +#define CFG_MAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*** Baseband ***/ + +#ifndef BB_CLK_RATE_HZ +#define BB_CLK_RATE_HZ 1000000 /*!< BB clock rate in hertz. */ +#endif + +/*** Controller HCI ***/ + +#ifndef CHCI_BUF_TAILROOM +#define CHCI_BUF_TAILROOM 4 /*!< Extra byte allocation required for buffer (e.g., for MIC). */ +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* CFG_MAC_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac_ble.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac_ble.h new file mode 100644 index 0000000000..f493c4511d --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/cfg_mac_ble.h @@ -0,0 +1,108 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief BLE MAC system configuration. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CFG_MAC_BLE_H +#define CFG_MAC_BLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*** LL ***/ + +#ifndef LL_API_PARAM_CHECK +#define LL_API_PARAM_CHECK 1 /*!< Check API parameters. */ +#endif + +#ifndef LL_MAX_CONN +#define LL_MAX_CONN 4 /*!< Absolute maximum number of connections (maximum is 32). */ +#endif + +#ifndef LL_NUM_ADV_FILT +#define LL_NUM_ADV_FILT 8 /*!< Table size for advertising filter. */ +#endif + +#ifndef LL_MAX_ADV_SETS +#define LL_MAX_ADV_SETS 6 /*!< Absolute maximum number of advertising sets. */ +#endif + +#ifndef LL_MAX_PER_SCAN +#define LL_MAX_PER_SCAN 6 /*!< Absolute maximum number of periodic scanners (maximum is 32). */ +#endif + +#ifndef LL_ENABLE_TESTER +#define LL_ENABLE_TESTER 0 /*!< Enable LL tester extensions. */ +#endif + +#ifndef LHCI_ENABLE_VS +#define LHCI_ENABLE_VS 1 /*!< Enable vendor specific command processing. */ +#endif + +/*** Scheduler ***/ + +#ifndef SCH_RM_MAX_RSVN +#define SCH_RM_MAX_RSVN (LL_MAX_CONN + LL_MAX_ADV_SETS) /*!< Maximum number of reservations (maximum is 32). */ +#endif + +/*** Baseband ***/ + +#ifndef BB_DATA_PLD_MAX_LEN +#define BB_DATA_PLD_MAX_LEN 251 /*!< Maximum data channel payload length (valid range 27 to 251, exclude MIC). */ +#endif + +#ifndef BB_ADV_PLD_MAX_LEN +#define BB_ADV_PLD_MAX_LEN 255 /*!< Maximum advertising channel payload length (valid range 95 to 255). */ +#endif + +#ifndef BB_FIXED_DATA_PKT_LEN +#define BB_FIXED_DATA_PKT_LEN 0 /*!< Fixed packet length required for BB data receive buffers (0 to disable). */ +#endif + +#ifndef BB_FIXED_ADVB_PKT_LEN +#define BB_FIXED_ADVB_PKT_LEN 0 /*!< Fixed packet length required for BB advertisement receive buffers (0 to disable). */ +#endif + +#ifndef BB_DATA_PDU_TAILROOM +#define BB_DATA_PDU_TAILROOM 4 /*!< Extra byte allocation required for BB operations (i.e. MIC). */ +#endif + +#ifndef BB_ENABLE_INLINE_ENC_TX +#define BB_ENABLE_INLINE_ENC_TX 0 /*!< Enable inline encryption mode. Not available for all projects. */ +#endif + +#ifndef BB_ENABLE_INLINE_DEC_RX +#define BB_ENABLE_INLINE_DEC_RX 0 /*!< Enable inline decryption mode. Not available for all projects. */ +#endif + +#ifndef BB_SYM_PHY_REQ +#define BB_SYM_PHY_REQ 0 /*!< Symmetric PHY required on connections. */ +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* CFG_MAC_BLE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/sch_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/sch_api.h new file mode 100644 index 0000000000..5b9b1ddb72 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/include/common/sch_api.h @@ -0,0 +1,69 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Multi-protocol scheduler interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef SCH_API_H +#define SCH_API_H + +#include "wsf_types.h" +#include "wsf_os.h" +#include "bb_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Conflict action call signature. */ +typedef BbOpDesc_t*(*BbConflictAct_t)(BbOpDesc_t *pNewBod, BbOpDesc_t *pExistBod); + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void SchInit(void); +void SchHandlerInit(wsfHandlerId_t handlerId); +void SchReset(void); +uint16_t SchStatsGetHandlerWatermarkUsec(void); + +/* Control */ +void SchHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); + +/* List maintenance */ +void SchInsertNextAvailable(BbOpDesc_t *pBod); +bool_t SchInsertAtDueTime(BbOpDesc_t *pBod, BbConflictAct_t conflictCback); +bool_t SchInsertEarlyAsPossible(BbOpDesc_t *pBod, uint32_t min, uint32_t max); +bool_t SchInsertLateAsPossible(BbOpDesc_t *pBod, uint32_t min, uint32_t max); +bool_t SchRemove(BbOpDesc_t *pBod); +void SchReload(BbOpDesc_t *pBod); +void SchRemoveBackground(void); +void SchInsertBackground(BbOpDesc_t *pBod); +void SchTerminateBackground(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* SCH_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/bb/bb_ble_int.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/bb/bb_ble_int.h new file mode 100644 index 0000000000..c2c7b5510f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/bb/bb_ble_int.h @@ -0,0 +1,134 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal BLE baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_INT_H +#define BB_BLE_INT_H + +#include "bb_ble_api.h" +#include "bb_ble_api_op.h" +#include "bb_ble_drv.h" +#include "bb_drv.h" +#include "ll_defs.h" +#include "wsf_assert.h" +#include "wsf_math.h" +#include "cfg_mac_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Maximum length of an advertising packet. */ +#define BB_ADVB_MAX_LEN WSF_MAX(BB_FIXED_ADVB_PKT_LEN, LL_ADVB_MAX_LEN) + +/*! \brief Mark the start of an ISR. */ +#define BB_ISR_START() bbIsrStartTime = BbDrvGetCurrentTime() + +/*! \brief Mark the ISR duration, recording the high watermark. */ +#define BB_ISR_MARK(x) x = WSF_MAX(x, BB_TICKS_TO_US(BbDrvGetCurrentTime() - bbIsrStartTime)) + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Execution operation function. */ +typedef void (*bbBleExecOpFn_t)(BbOpDesc_t *pBod, BbBleData_t *pBle); + +/*! \brief BB control block. */ +typedef struct +{ + struct + { + bbBleExecOpFn_t execOpCback; /*!< Execute operation handler. */ + bbBleExecOpFn_t cancelOpCback; /*!< Cancel operation handler. */ + } opCbacks[BB_BLE_OP_NUM]; /*!< Operation handlers. */ + + uint8_t evtState; /*!< Action state of the currently operating BOD. */ + uint8_t advChIdx; /*!< Current advertising channel index. */ + uint32_t lastScanStart; /*!< Last scan start time. */ + + BbBleDrvDataParam_t bbParam; /*!< Baseband data parameters. */ + + uint16_t rxDataLen; /*!< Receive data buffer length. */ + uint8_t *pRxDataBuf; /*!< Current Rx data buffer. */ +} bbBleCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern bbBleCtrlBlk_t bbBleCb; + +/* ISR start time. */ +extern uint32_t bbIsrStartTime; + +/*************************************************************************************************/ +/*! + * \brief Register operation handlers. + * + * \param opType Operation type. + * \param execOpCback Execute operation callback. + * \param cancelOpCback Cancel operation callback. + * + * \return None. + */ +/*************************************************************************************************/ +void bbBleRegisterOp(uint8_t opType, bbBleExecOpFn_t execOpCback, bbBleExecOpFn_t cancelOpCback); + +#ifdef __cplusplus +}; +#endif + +/*************************************************************************************************/ +/*! + * \brief Clear IFS in operation. + * + * \return None. + * + * The BB may choose not to enable IFS after the next Tx or Rx. + */ +/*************************************************************************************************/ +static inline void bbBleClrIfs(void) +{ + BbBleDrvOpParam_t opParams = { .ifsSetup = FALSE, .ifsUsec = 0 }; + BbBleDrvSetOpParams(&opParams); +} + +/*************************************************************************************************/ +/*! + * \brief Set IFS in operation. + * + * \return None. + * + * The BB must enable IFS after the next Tx or Rx. + */ +/*************************************************************************************************/ +static inline void bbBleSetIfs(void) +{ + BbBleDrvOpParam_t opParams = { .ifsSetup = TRUE, .ifsUsec = LL_BLE_TIFS_US }; + BbBleDrvSetOpParams(&opParams); +} + +#endif /* BB_BLE_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api.h new file mode 100644 index 0000000000..c24b7a1ff1 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api.h @@ -0,0 +1,167 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller common interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_H +#define LCTR_API_H + +#include "ll_api.h" +#include "ll_defs.h" +#include "bb_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Message dispatch handler types. */ +enum +{ + LCTR_DISP_CONN_IND, /*!< Advertising channel connection indication dispatch handler type. */ + LCTR_DISP_CONN, /*!< Connection message dispatch handler type. */ + LCTR_DISP_SCAN, /*!< Scan message dispatch handler type. */ + LCTR_DISP_INIT, /*!< Initiate message dispatch handler type. */ + LCTR_DISP_ADV, /*!< Advertising message dispatch handler type. */ + LCTR_DISP_TEST, /*!< Test message dispatch handler type. */ + LCTR_DISP_PRIV, /*!< Privacy message dispatch handler type. */ + LCTR_DISP_EXT_SCAN, /*!< Extended Scan message dispatch handler type. */ + LCTR_DISP_EXT_ADV, /*!< Extended Advertising message dispatch handler type. */ + LCTR_DISP_EXT_INIT, /*!< Extended Initiate message dispatch handler type. */ + LCTR_DISP_PER_ADV, /*!< Periodic Advertising message dispatch handler type. */ + LCTR_DISP_PER_CREATE_SYNC, /*!< Periodic Create Sync message dispatch handler type. */ + LCTR_DISP_PER_SCAN, /*!< Periodic Scanning message dispatch handler type. */ + LCTR_DISP_TOTAL, /*!< Total number of dispatch handlers. */ + /* Special IDs */ + LCTR_DISP_FIRST_SM = LCTR_DISP_CONN_IND+1, /*!< First state machine. */ + LCTR_DISP_LAST_SM = LCTR_DISP_TOTAL-1, /*!< Last state machine. */ + LCTR_DISP_BCST = 0xFF /*!< Broadcast message type. */ +}; + +/*! \brief Broadcast task messages. */ +enum +{ + LCTR_MSG_RESET /*!< Reset API message. */ +}; + +/*! \brief Task event mask bit positions. */ +enum +{ + LCTR_EVENT_RX_PENDING, /*!< Receive data PDU pending. */ + LCTR_EVENT_TX_PENDING, /*!< Transmit data PDU pending. */ + LCTR_EVENT_TX_COMPLETE, /*!< Transmit data PDU completed. */ + LCTR_EVENT_RX_ADVB, /*!< Receive AdvB PDU completed. */ + LCTR_EVENT_RX_DIRECT_ADVB, /*!< Receive direct AdvB PDU completed. */ + LCTR_EVENT_RX_SCAN_REQ, /*!< Receive scan request PDU completed. */ + LCTR_EVENT_SC_GENERATE_P256_KEY_PAIR, /*!< Generate P-256 public/private key pair. */ + LCTR_EVENT_SC_GENERATE_DHKEY, /*!< Generate Diffie-Hellman key. */ + LCTR_EVENT_TOTAL /*!< Total number of event handlers. */ +}; + +/*! \brief Waiting host reply bitmask. */ +enum +{ + LCTR_HOST_REPLY_CONN_PARAM_REQ = (1 << 0), /*!< Waiting for host to submit a connection parameter request reply. */ + LCTR_HOST_REPLY_LTK_REQ = (1 << 1), /*!< Waiting for host to submit a LTK request reply. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Common message structure passed to event handler. */ +typedef struct +{ + uint16_t handle; /*!< Handle. */ + uint8_t dispId; /*!< Dispatch ID. */ + uint8_t event; /*!< PDU ID. */ +} lctrMsgHdr_t; + +/*! \brief Connect request PDU. */ +typedef struct +{ + uint64_t initAddr; /*!< Scanner's address. */ + uint64_t advAddr; /*!< Advertiser's address. */ + + uint32_t accessAddr; /*!< Connection access address. */ + uint32_t crcInit; /*!< CRC initialization value. */ + uint64_t chanMask; /*!< Channel mask. */ + uint16_t interval; /*!< connInterval value. */ + uint16_t latency; /*!< connSlaveLatency value. */ + uint16_t timeout; /*!< connSupervisionTimeout value. */ + uint8_t txWinSize; /*!< transmitWindowSize value. */ + uint16_t txWinOffset; /*!< transmitWindowOffset value. */ + uint8_t hopInc; /*!< hopIncrement value. */ + uint8_t masterSca; /*!< Master sleep clock accuracy. */ +} lctrConnInd_t; + +/*! \brief Connection establish. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrConnInd_t connInd; /*!< Connection indication. */ + uint32_t connIndEndTs; /*!< Connection indication packet end timestamp. */ + uint8_t peerIdAddrType; /*!< Peer identity address type. */ + uint8_t usedChSel; /*!< Used channel selection. */ + uint8_t phy; /*!< PHY selection. */ + bool_t sendAdvSetTerm; /*!< Send Advertising Set Termination event. */ + uint8_t numExtAdvEvents; /*!< Number of completed extended advertising events. */ + bool_t isAuxConnReq; /*!< True if AUX_CON_REQ is received, False if CONN_IND is received. */ + uint64_t peerIdAddr; /*!< Peer identity address. */ + uint64_t peerRpa; /*!< Peer RPA. */ + uint64_t localRpa; /*!< Local RPA. */ +} lctrConnEstablish_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/* Runtime configuration. */ +extern const LlRtCfg_t *pLctrRtCfg; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +uint16_t LctrInitAdvSetMem(uint8_t *pFreeMem, uint32_t freeMemSize); +uint16_t LctrInitExtScanMem(uint8_t *pFreeMem, uint32_t freeMemSize); +uint16_t LctrInitConnMem(uint8_t *pFreeMem, uint32_t freeMemSize); +void LctrSetSupStates(void); + +/* Task */ +void LctrMsgDispatcher(lctrMsgHdr_t *pMsg); +void LctrEventHandler(uint8_t event); + +/*! \} */ /* LL_LCTR_API */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master.h new file mode 100644 index 0000000000..38fdb40279 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master.h @@ -0,0 +1,109 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_ADV_MASTER_H +#define LCTR_API_ADV_MASTER_H + +#include "lctr_api.h" +#include "lmgr_api_adv_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_ADV_MST + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master scan task messages for \a LCTR_DISP_SCAN dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_SCAN_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Scan events */ + LCTR_SCAN_MSG_DISCOVER_ENABLE, /*!< Scan enable API event. */ + LCTR_SCAN_MSG_DISCOVER_DISABLE, /*!< Scan disable API event. */ + LCTR_SCAN_MSG_TERMINATE, /*!< Scan BOD terminated event. */ + LCTR_SCAN_MSG_PARAM_UPD, /*!< Scan parameter update event. */ + LCTR_SCAN_MSG_TOTAL /*!< Total number of scan events. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Scan parameter message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lmgrScanParam_t param; /*!< Scan parameters. */ +} lctrScanParamMsg_t; + +/*! \brief Scan enable message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + bool_t filtDup; /*!< Filter out duplicate advertisers. */ +} lctrScanEnableMsg_t; + +/*! \brief Initiate message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LlConnSpec_t connSpec; /*!< Connection spec. */ + lmgrScanParam_t scanParam; /*!< Scan parameters. */ + uint64_t peerAddr; /*!< Peer address. */ + uint8_t peerAddrType; /*!< Peer address type. */ +} lctrInitiateMsg_t; + +/*! \brief Advertising report message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LlAdvReportInd_t rpt; /*!< Report data. */ + uint32_t hash; /*!< Event data hash. */ +} lctrAdvReportMsg_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrMstScanInit(void); +void LctrMstScanDefaults(void); + +/* Helpers */ +void lctrAdvReportsInc(void); +void lctrAdvReportsDec(void); + +/*! \} */ /* LL_LCTR_API_ADV_MST */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_ADV_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master_ae.h new file mode 100644 index 0000000000..38384d62e2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_master_ae.h @@ -0,0 +1,171 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller extended scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_ADV_MASTER_AE_H +#define LCTR_API_ADV_MASTER_AE_H + +#include "lctr_api.h" +#include "lmgr_api_adv_master.h" +#include "wsf_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master scan and initiate task messages for \a LCTR_DISP_SCAN dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_EXT_SCAN_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Scan events */ + LCTR_EXT_SCAN_MSG_DISCOVER_ENABLE, /*!< Scan enable API event. */ + LCTR_EXT_SCAN_MSG_DISCOVER_DISABLE, /*!< Scan disable API event. */ + LCTR_EXT_SCAN_MSG_TERMINATE, /*!< Scan BOD terminated event. */ + LCTR_EXT_SCAN_MSG_TOTAL /*!< Total number of scan events. */ +}; + +/*! \brief Scanner create sync task messages for \a LCTR_DISP_PER_CREATE_SYNC dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_CREATE_SYNC_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Advertising events */ + LCTR_CREATE_SYNC_MSG_CREATE, /*!< Create sync create API event. */ + LCTR_CREATE_SYNC_MSG_CANCEL, /*!< Create sync cancel sync API event. */ + LCTR_CREATE_SYNC_MSG_DONE, /*!< Create sync done event. */ + LCTR_CREATE_SYNC_MSG_TERMINATE, /*!< Create sync scanning BOD terminate event. */ + LCTR_CREATE_SYNC_MSG_TOTAL /*!< Total number of Create sync events. */ + +}; + +/*! \brief Scanner periodic synchronous task messages for \a LCTR_DISP_PER_SCAN dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_PER_SCAN_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Advertising events */ + LCTR_PER_SCAN_MSG_SYNC_ESTD, /*!< Periodic scanning synchronous established event. */ + LCTR_PER_SCAN_MSG_TERMINATE, /*!< Periodic scanning terminate API event. */ + LCTR_PER_SCAN_MSG_TERMINATE_DONE, /*!< Periodic scanning terminate done event. */ + LCTR_PER_SCAN_SUP_TIMEOUT, /*!< Periodic synchronous supervision timeout event. */ + LCTR_PER_SCAN_MSG_TOTAL /*!< Total number of periodic scanning events. */ + +}; + +/*! \brief Scan PHYs. */ +enum +{ + LCTR_SCAN_PHY_1M, /*!< LE 1M PHY scanner. */ + LCTR_INIT_PHY_2M, /*!< LE 2M PHY initiator (not valid for scanning). */ + LCTR_SCAN_PHY_CODED, /*!< LE Coded PHY scanner. */ + LCTR_SCAN_PHY_TOTAL, /*!< Total number of scanning PHYs. */ + LCTR_SCAN_PHY_ALL = 0xFF /*!< All PHY scanners. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Extended scan enable message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t filtDup; /*!< Filter out duplicate advertisers. */ + uint32_t durMs; /*!< Duration in milliseconds. */ + uint32_t perMs; /*!< Period in milliseconds. */ +} lctrExtScanEnableMsg_t; + +/*! \brief Extended initiate message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t filterPolicy; /*!< Scan filter policy. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t peerAddrType; /*!< Address type used for peer device. */ + uint64_t peerAddr; /*!< Address of peer device. */ + uint8_t initPhys; /*!< Initiating PHYs. */ +} lctrExtInitiateMsg_t; + +/*! \brief Extended scan message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrExtScanEnableMsg_t enable; /*!< Extended scan enable message data. */ + lctrExtInitiateMsg_t init; /*!< Extended initiate message data. */ +} LctrExtScanMsg_t; + +/*! \brief Periodic create sync message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t filterPolicy; /*!< Filter Policy. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint64_t advAddr; /*!< Advertiser Address. */ + uint16_t skip; /*!< Skip. */ + uint16_t syncTimeOut; /*!< Synchronization Timeout. */ +} lctrPerCreateSyncMsg_t; + +/*! \brief Periodic Advertising message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrPerCreateSyncMsg_t createSync; /*!< Periodic create sync message data. */ +} LctrPerScanMsg_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +/*! \brief Periodic scan message data. */ +extern LctrPerScanMsg_t *pLctrMstPerScanMsg; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrMstExtScanInit(void); +void LctrMstExtScanDefaults(void); +void LctrMstPerCreateSyncInit(void); +void LctrMstPerScanInit(void); + +/* Status */ +bool_t LctrMstExtScanValidateParam(void); + +/* Control */ +void LctrMstExtScanSetScanPhy(uint8_t scanPhy); +void LctrMstExtScanClearScanPhy(uint8_t scanPhy); +void LctrMstExtScanSetParam(uint8_t scanPhy, uint8_t ownAddrType, uint8_t scanFiltPolicy, const LlExtScanParam_t *pParam); +bool_t LctrMstPerIsSyncPending(void); +bool_t LctrMstPerIsSyncDisabled(void); +bool_t LctrMstPerIsSync(uint8_t advSID, uint8_t advAddrType, uint64_t advAddr); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_ADV_MASTER_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave.h new file mode 100644 index 0000000000..59f07524b4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave.h @@ -0,0 +1,88 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller advertising slave interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_ADV_SLAVE_H +#define LCTR_API_ADV_SLAVE_H + +#include "lctr_api.h" +#include "lmgr_api_adv_slave.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_ADV_SLV + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Slave advertising task messages for \a LCTR_DISP_ADV dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_ADV_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Advertising events */ + LCTR_ADV_MSG_START, /*!< Advertising start API event. */ + LCTR_ADV_MSG_STOP, /*!< Advertising stop API event. */ + LCTR_ADV_MSG_INT_START, /*!< Advertising start internal event. */ + LCTR_ADV_MSG_TERMINATE, /*!< Advertising BOD terminated event. */ + LCTR_ADV_MSG_PARAM_UPD, /*!< Advertising parameter update event. */ + LCTR_ADV_MSG_TOTAL /*!< Total number of advertising events. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising parameter message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lmgrAdvParam_t param; /*!< Advertising parameters. */ +} lctrAdvParamMsg_t; + +/*! \brief Link layer controller advertising message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrAdvParamMsg_t advParamUpd; /*!< Advertising parameter update. */ +} LctrAdvMsg_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrSlvAdvInit(void); +void LctrSlvAdvDefaults(void); + +/*! \} */ /* LL_LCTR_API_ADV_SLV */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_ADV_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave_ae.h new file mode 100644 index 0000000000..ee5731bbb8 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_adv_slave_ae.h @@ -0,0 +1,131 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller extended advertising slave interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_ADV_SLAVE_AE_H +#define LCTR_API_ADV_SLAVE_AE_H + +#include "lctr_api.h" +#include "lmgr_api_adv_slave_ae.h" +#include "cfg_mac_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Slave extended advertising task messages for \a LCTR_DISP_EXT_ADV dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_EXT_ADV_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Advertising events */ + LCTR_EXT_ADV_MSG_START, /*!< Extended advertising start API event. */ + LCTR_EXT_ADV_MSG_STOP, /*!< Extended advertising stop API event. */ + LCTR_EXT_ADV_MSG_INT_START, /*!< Extended advertising start internal event. */ // TODO not needed + LCTR_EXT_ADV_MSG_TERMINATE, /*!< Extended advertising BOD terminated event. */ + LCTR_EXT_ADV_MSG_TMR_DUR_EXP, /*!< Extended advertising duration timer expired event. */ + LCTR_EXT_ADV_MSG_TOTAL /*!< Total number of extended advertising events. */ +}; + +/*! \brief Slave periodic advertising task messages for \a LCTR_DISP_PER_ADV dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_PER_ADV_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Advertising events */ + LCTR_PER_ADV_MSG_START, /*!< Periodic advertising start API event. */ + LCTR_PER_ADV_MSG_STOP, /*!< Periodic advertising stop API event. */ + LCTR_PER_ADV_MSG_TERMINATE, /*!< Periodic advertising BOD terminated event. */ + LCTR_PER_ADV_MSG_TOTAL /*!< Total number of periodic advertising events. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Extended Advertising enable message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint32_t durMs; /*!< Duration in milliseconds. */ + uint8_t maxEvents; /*!< Maximum number of extended advertising events. */ +} LctrExtAdvEnableMsg_t; + +/*! \brief Periodic Advertising enable message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ +} LctrPerAdvEnableMsg_t; + +/*! \brief Extended Advertising message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LctrExtAdvEnableMsg_t enable; /*!< Enable message data. */ +} LctrExtAdvMsg_t; + +/*! \brief Periodic Advertising message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LctrPerAdvEnableMsg_t perEnable; /*!< Periodic enable message data. */ +} LctrPerAdvMsg_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrSlvExtAdvInit(void); +void LctrSlvExtAdvDefaults(void); +void LctrSlvPeriodicAdvInit(void); + +/* Status */ +uint8_t LctrIsExtAdvEnableParamValid(uint8_t enable, LlExtAdvEnableParam_t *pEnaParam); +uint8_t LctrIsExtAdvEnableReady(uint8_t handle); +bool_t LctrIsAdvHandleValid(uint8_t handle); +uint8_t LctrGetExtAdvTxPowerLevel(uint16_t handle, int8_t *pLevel); + +/* Control */ +uint8_t LctrGetAdvHandles(uint8_t pHandles[LL_MAX_ADV_SETS]); +uint8_t LctrSetExtAdvSetRandAddr(uint8_t handle, const uint8_t *pAddr); +uint8_t LctrGetExtAdvSetRandAddr(uint8_t handle, uint8_t *pAddr); +uint8_t LctrSetExtAdvParam(uint8_t handle, LlExtAdvParam_t *pExtAdvParam); +uint8_t LctrSetExtAdvData(uint8_t handle, uint8_t op, uint8_t fragPref, uint8_t len, const uint8_t *pData); +uint8_t LctrSetExtScanRespData(uint8_t handle, uint8_t op, uint8_t fragPref, uint8_t len, const uint8_t *pData); +uint8_t LctrRemoveAdvSet(uint8_t handle); +uint8_t LctrClearAdvSets(void); +uint8_t LctrSetAuxOffsetDelay(uint8_t handle, uint32_t delayUsec); +uint8_t LctrSetExtAdvDataFragLen(uint8_t handle, uint8_t fragLen); +uint8_t LctrSetExtAdvTxPhyOptions(uint8_t handle, uint8_t priPhyOpts, uint8_t secPhyOpts); +uint8_t LctrSetPeriodicAdvParam(uint8_t handle, LlPerAdvParam_t *pPerAdvParam); +void LctrSetPeriodicAdvEnable(uint8_t handle, bool_t enable); +uint8_t LctrSetPeriodicAdvData(uint8_t handle, uint8_t op, uint8_t len, const uint8_t *pData); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_ADV_SLAVE_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn.h new file mode 100644 index 0000000000..65ff4f7ce9 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn.h @@ -0,0 +1,286 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_CONN_H +#define LCTR_API_CONN_H + +#include "lctr_api.h" +#include "bb_ble_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_CONN + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Data channel PDU length (header + payload + MIC). */ +#define LCTR_DATA_PDU_LEN(len) ((len) + LL_DATA_HDR_LEN + BB_DATA_PDU_TAILROOM) + +/*! \brief Maximum data channel PDU length (header + payload + MIC). */ +#define LCTR_DATA_PDU_MAX_LEN LCTR_DATA_PDU_LEN(BB_DATA_PLD_MAX_LEN) + +/*! \brief Minimum data channel PDU length (header + payload + MIC). */ +#define LCTR_DATA_PDU_MIN_LEN LCTR_DATA_PDU_LEN(LL_MAX_DATA_LEN_MIN) + +/*! \brief Maximum value for maximum Data PDU length (spec limit is 251) */ +#define LCTR_MAX_DATA_LEN_MAX BB_DATA_PLD_MAX_LEN + +/*! \brief Connected task messages for \a LCTR_DISP_CONN dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_CONN_MSG_RESET = LCTR_MSG_RESET, + /* Receive remote PDU events */ + _LCTR_CONN_MSG_RX_EVENTS = 10, + LCTR_CONN_MSG_RX_CONNECT_IND, /*!< Connect indication received. */ + LCTR_CONN_MSG_RX_LLCP, /*!< LLCP message received. */ + LCTR_CONN_MSG_RX_LLCP_UNKNOWN, /*!< Unknown LLCP message received. */ + LCTR_CONN_MSG_RX_LLCP_INVALID_PARAM, /*!< LLCP message with invalid parameter received. */ + /* Host/API events */ + _LCTR_CONN_MSG_API_EVENTS = 20, + LCTR_CONN_MSG_API_CONN_UPDATE, /*!< Connection update API event. */ + LCTR_CONN_MSG_API_CHAN_MAP_UPDATE, /*!< Channel map update API event. */ + LCTR_CONN_MSG_API_DISCONNECT, /*!< Disconnect API event. */ + LCTR_CONN_MSG_API_START_ENC, /*!< Start encryption API event. */ + LCTR_CONN_MSG_API_LTK_REPLY, /*!< LTK reply. */ + LCTR_CONN_MSG_API_LTK_NEG_REPLY, /*!< LTK negative reply. */ + LCTR_CONN_MSG_API_REMOTE_FEATURE, /*!< Read remote feature API event. */ + LCTR_CONN_MSG_API_REMOTE_VERSION, /*!< Read remote version API event. */ + LCTR_CONN_MSG_API_CONN_PARAM_REPLY, /*!< Remote connection parameter request reply API event. */ + LCTR_CONN_MSG_API_CONN_PARAM_NEG_REPLY,/*!< Remote connection parameter request negative reply API event. */ + LCTR_CONN_MSG_API_DATA_LEN_CHANGE, /*!< Data length change API event. */ + LCTR_CONN_MSG_API_PHY_UPDATE, /*!< PHY update API event. */ + LCTR_CONN_MSG_API_SET_MIN_USED_CHAN, /*!< Set minimum number of used channels API event. */ + /* Internal events */ + _LCTR_CONN_INT_EVENTS = 40, + LCTR_CONN_DATA_PENDING, /*!< New data pending. */ + LCTR_CONN_ARQ_Q_FLUSHED, /*!< ARQ queue transitioned to empty. */ + LCTR_CONN_MST_ESTABLISH, /*!< Establish connection (master only). */ + LCTR_CONN_SLV_INIT_STARTUP_LLCP, /*!< Slave initiates startup LLCP procedures(slave only). */ + _LCTR_CONN_LLCP_EVENTS = 50, + LCTR_CONN_LLCP_CONN_UPDATE, /*!< LL initiated connection update procedure. */ + LCTR_CONN_LLCP_VERSION_EXCH, /*!< LL initiated remote version exchange. */ + LCTR_CONN_LLCP_FEATURE_EXCH, /*!< LL initiated remote feature exchange. */ + LCTR_CONN_LLCP_LENGTH_EXCH, /*!< LL initiated data length exchange. */ + LCTR_CONN_LLCP_TERM, /*!< LL initiated termination. */ + LCTR_CONN_LLCP_PROC_CMPL, /*!< LLCP procedure completed. */ + LCTR_CONN_LLCP_START_PENDING, /*!< Start pending LLCP procedure. */ + LCTR_CONN_LLCP_SKIP_CONN_PARAM, /*!< Skip connection parameter exchange. */ + LCTR_CONN_LLCP_REJECT_CONN_UPD, /*!< Reject a connection update. */ + _LCTR_CONN_TERM_EVENTS = 60, + LCTR_CONN_TERM_SUP_TIMEOUT, /*!< Terminate connection due to supervision timeout. */ + LCTR_CONN_TERM_MIC_FAILED, /*!< Terminate connection due to MIC failure. */ + LCTR_CONN_TERM_INST_PASSED, /*!< Terminate connection due to instant passed. */ + LCTR_CONN_TERMINATED, /*!< Connection event terminated. */ + _LCTR_CONN_TMR_EVENTS = 70, + LCTR_CONN_TMR_LLCP_RSP_EXP, /*!< LLCP response timer expired. */ + LCTR_CONN_TMR_PING_PERIOD_EXP, /*!< LE Ping period timer expired. */ + LCTR_CONN_TMR_AUTH_PAYLOAD_EXP /*!< Authentication payload timer expired. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Connection update message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LlConnSpec_t connSpec; /*!< Updated connection specification. */ +} lctrConnUpdate_t; + +/*! \brief Channel map update message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint64_t chanMap; /*!< Channel map. */ +} lctrChanMapUpdate_t; + +/*! \brief Disconnect message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t reason; /*!< Disconnect reason. */ +} lctrDisconnect_t; + +/*! \brief Start encryption message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t rand[LL_RAND_LEN]; /*!< Random number. */ + uint16_t diversifier; /*!< Diversifier. */ + uint8_t key[LL_KEY_LEN]; /*!< Encryption key. */ +} lctrStartEnc_t; + +/*! \brief Remote connection parameter reply message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t key[LL_KEY_LEN]; /*!< Encryption key. */ +} lctrLtkReply_t; + +/*! \brief Remote connection parameter reply message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + LlConnSpec_t connSpec; /*!< Updated connection specification. */ +} lctrConnParamReply_t; + +/*! \brief Remote connection parameter negative reply message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t reason; /*!< Reason code. */ +} lctrConnParamNegReply_t; + +/*! \brief Data length change message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint16_t maxTxLen; /*!< Maximum transmit length. */ + uint16_t maxTxTime; /*!< Maximum transmit time. */ +} lctrDataLengthChange_t; + +/*! \brief PHY update message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t allPhys; /*!< All PHYs preferences. */ + uint8_t txPhys; /*!< Preferred transmitter PHYs. */ + uint8_t rxPhys; /*!< Preferred receiver PHYs. */ + uint16_t phyOptions; /*!< PHY options. */ +} lctrPhyUpdate_t; + +/*! \brief Set minimum number of used channels message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + uint8_t phys; /*!< Bitmask for the PHYs. */ + uint8_t minUsedChan; /*!< Minimum number of used channels. */ +} lctrSetMinUsedChan_t; + +/*! \brief Link layer controller message data. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrConnEstablish_t connEstablish; /*!< Connection establish message data. */ + lctrConnUpdate_t connUpd; /*!< Connection update message data. */ + lctrChanMapUpdate_t chanMapUpd; /*!< Channel map update message data. */ + lctrDisconnect_t disc; /*!< Disconnect message data. */ + lctrStartEnc_t startEnc; /*!< Start encryption message data. */ + lctrLtkReply_t ltkReply; /*!< LTK reply message data. */ + lctrConnParamReply_t connParamReply; /*!< Remote connection parameter reply message data. */ + lctrConnParamNegReply_t connParamNegReply;/*!< Remote connection parameter negative reply message data. */ + lctrDataLengthChange_t dataLenChange; /*!< Data length change message data. */ + lctrPhyUpdate_t phyUpd; /*!< PHY update message data. */ + lctrSetMinUsedChan_t setMinUsedChan; /*!< Set minimum number of used channels message data. */ +} lctrConnMsg_t; + +/*! \brief Initialize connection context. */ +typedef void (*LctrInitConnHdlr_t)(uint16_t connHandle); + +/*! \brief Set transmit flow control. */ +typedef void (*LctrTxFcHdlr_t)(uint16_t connHandle, uint8_t *pBuf); + +/*! \brief Transmit PDU complete. */ +typedef void (*LctrTxPduCompHdlr_t)(uint16_t connHandle); + +/*! \brief Transmit empty packet acknowledgment, returns TRUE if required. */ +typedef bool_t (*LctrTxAckHdlr_t)(uint16_t connHandle); + +/*! \brief Receive process flow control, returns TRUE if retransmission. */ +typedef bool_t (*LctrRxAckHdlr_t)(uint16_t connHandle); + +/*! \brief VS receive data handler. */ +typedef void (*LctrVsRecvHdlr_t)(uint16_t connHandle, uint8_t *pBuf); + +/*! \brief Connection event complete handler. */ +typedef void (*LctrCeCompHdlr_t)(uint16_t connHandle); + +/*! \brief Vendor specific PDU handlers. */ +typedef struct +{ + LctrInitConnHdlr_t connSetup; /*!< Setup connection context. */ + LctrInitConnHdlr_t connCleanup; /*!< Cleanup connection context. */ + LctrTxFcHdlr_t txPduFc; /*!< Set transmit PDU flow control. */ + LctrTxAckHdlr_t txPduAck; /*!< Tx PDU acknowledge required? */ + LctrRxAckHdlr_t rxPduAck; /*!< Process a receive PDU acknowledgment. */ + LctrVsRecvHdlr_t dataRecv; /*!< Receive data buffer handler. */ + LctrTxPduCompHdlr_t ceSetup; /*!< Setup connection event. */ + LctrCeCompHdlr_t ceCleanup; /*!< Cleanup connection event. */ +} LctrVsHandlers_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrSlvConnInit(void); +void LctrSlvConnEncInit(void); +void LctrMstConnInit(void); +void LctrMstConnEncInit(void); +void LctrVsConnInit(const LctrVsHandlers_t *pHdlrs); + +/* Helpers */ +uint8_t LctrValidateConnSpec(const LlConnSpec_t *pConnSpec); +bool_t LctrIsProcActPended(uint16_t handle, uint8_t event); + +/* Status */ +bool_t LctrIsConnHandleEnabled(uint16_t handle); +uint8_t LctrGetRole(uint16_t handle); +int8_t LctrGetRssi(uint16_t handle); +int8_t LctrGetTxPowerLevel(uint16_t handle); +uint64_t LctrGetChannelMap(uint16_t handle); +uint8_t LctrGetUsedFeatures(uint16_t handle); +uint8_t LctrGetTxPhy(uint16_t handle); +uint8_t LctrGetRxPhy(uint16_t handle); +void LctrGetPeerMinUsedChan(uint16_t handle, uint8_t *pPeerMinUsedChan); +bool_t LctrIsWaitingForReply(uint16_t handle, uint8_t reply); + + +/* Control */ +void LctrSetTxPowerLevel(uint16_t handle, int8_t level); +uint32_t LctrGetAuthPayloadTimeout(uint16_t handle); +bool_t LctrSetAuthPayloadTimeout(uint16_t handle, uint32_t timeoutMs); +void LctrGetEncMode(uint16_t handle, LlEncMode_t *pMode); +bool_t LctrSetEncMode(uint16_t handle, const LlEncMode_t *pMode); +void LctrSetConnOpFlags(uint16_t handle, uint32_t flags, bool_t enable); + +/* Data path */ +void LctrTxAcl(uint8_t *pAclBuf); +uint8_t *LctrRxAcl(void); +void LctrRxAclComplete(uint8_t numBufs); + +/*! \} */ /* LL_LCTR_API_CONN */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_CONN_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn_cs2.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn_cs2.h new file mode 100644 index 0000000000..bb74268318 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_conn_cs2.h @@ -0,0 +1,43 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller channel selection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_CONN_CS_H +#define LCTR_API_CONN_CS_H + +#include "lctr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrChannelSelection2Init(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_CONN_CS_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master.h new file mode 100644 index 0000000000..03090f6cc3 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master.h @@ -0,0 +1,72 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller initiating master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_INIT_MASTER_H +#define LCTR_API_INIT_MASTER_H + +#include "lctr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_INIT_MST + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master initiate task messages for \a LCTR_DISP_INIT dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_INIT_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Initiate events */ + LCTR_INIT_MSG_INITIATE, /*!< Initiate API event. */ + LCTR_INIT_MSG_INITIATE_CANCEL, /*!< Initiate cancel API event. */ + LCTR_INIT_MSG_TERMINATE, /*!< Scan BOD terminated event. */ + LCTR_INIT_MSG_TOTAL /*!< Total number of initiate events. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrMstInitInit(void); +void LctrMstInitDefaults(void); + +/*! \} */ /* LL_LCTR_API_INIT_MST */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_INIT_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master_ae.h new file mode 100644 index 0000000000..ccae5c37e4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_init_master_ae.h @@ -0,0 +1,81 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller extended initiating master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_INIT_MASTER_AE_H +#define LCTR_API_INIT_MASTER_AE_H + +#include "lctr_api.h" +#include "wsf_assert.h" +#include "lctr_api_init_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_INIT_MST_AE + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master extended initiate task messages for \a LCTR_DISP_EXT_INIT dispatcher. */ +enum +{ + /* Broadcast events */ + LCTR_EXT_INIT_MSG_RESET = LCTR_MSG_RESET, /*!< Reset API message. */ + /* Initiate events */ + LCTR_EXT_INIT_MSG_INITIATE, /*!< Initiate API event. */ + LCTR_EXT_INIT_MSG_INITIATE_CANCEL, /*!< Initiate cancel API event. */ + LCTR_EXT_INIT_MSG_TERMINATE, /*!< Initiate scan BOD terminated event. */ + LCTR_EXT_INIT_MSG_TOTAL /*!< Total number of initiate events. */ +}; + +/*! \brief LCTR_EXT_INIT_MSG_INITIATE_CANCEL and LCTR_INIT_MSG_INITIATE_CANCEL shall be aligned. */ +WSF_CT_ASSERT(((int)LCTR_EXT_INIT_MSG_INITIATE_CANCEL == (int)LCTR_INIT_MSG_INITIATE_CANCEL)); + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrMstExtInitInit(void); +void LctrMstExtInitDefaults(void); + +/* Control */ +void LctrMstExtInitParam(uint8_t initPhy, const LlExtInitScanParam_t *pScanParam, const LlConnSpec_t *pConnSpec); +void LctrMstExtInitSetScanPhy(uint8_t scanPhy); +void LctrMstExtInitClearScanPhy(uint8_t scanPhy); + +/*! \} */ /* LL_LCTR_API_INIT_MST_AE */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_INIT_MASTER_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_phy.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_phy.h new file mode 100644 index 0000000000..669eaff587 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_phy.h @@ -0,0 +1,45 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller PHY features interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_PHY_H +#define LCTR_API_PHY_H + +#include "lctr_api.h" +#include "lmgr_api_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrSlvPhyConnInit(void); +void LctrMstPhyConnInit(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_PHY_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_priv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_priv.h new file mode 100644 index 0000000000..ea309e87fe --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_priv.h @@ -0,0 +1,87 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller privacy interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_PRIV_H +#define LCTR_API_PRIV_H + +#include "lctr_api.h" +#include "lmgr_api_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_PRIV + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Slave advertising task messages for \a LCTR_DISP_ADV dispatcher. */ +enum +{ + /* Privacy events */ + LCTR_PRIV_MSG_RES_PRIV_ADDR_TIMEOUT, /*!< Resolvable private address timeout event. */ + LCTR_PRIV_MSG_ADDR_RES_NEEDED /*!< Address resolution needed. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Address resolution pending message. */ +typedef struct +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + bool_t peer; /*!< TRUE if RPA is a peer's RPA. */ + uint8_t peerAddrType; /*!< Peer identity address type. */ + uint64_t peerIdentityAddr; /*!< Peer identity address. */ + uint64_t rpa; /*!< Resolvable private address. */ +} lctrAddrResNeededMsg_t; + +/*! \brief Address resolution pending message. */ +typedef union +{ + lctrMsgHdr_t hdr; /*!< Message header. */ + lctrAddrResNeededMsg_t addrResNeeded; /*!< Address resolution needed. */ +} LctrPrivMsg_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrPrivInit(void); + +/* Control */ +void LctrPrivSetResPrivAddrTimeout(uint32_t timeout); + +/*! \} */ /* LL_LCTR_API_PRIV */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_PRIV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_sc.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_sc.h new file mode 100644 index 0000000000..7cb864c250 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lctr_api_sc.h @@ -0,0 +1,52 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller secure connections interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_API_SC_H +#define LCTR_API_SC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LCTR_API_SC + * \{ + */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LctrScInit(void); + +/* Execution. */ +uint8_t LctrGenerateP256KeyPair(void); +uint8_t LctrGenerateDhKey(const uint8_t *pPubKey, const uint8_t *pPrivKey); + +/*! \} */ /* LL_LCTR_API_SC */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_API_SC_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api.h new file mode 100644 index 0000000000..f4f67bd7e6 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api.h @@ -0,0 +1,158 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager common interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_H +#define LMGR_API_H + +#include "ll_api.h" +#include "ll_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API + * \{ + */ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master scan modes. */ +enum +{ + LMGR_SCAN_MODE_DISCOVER, /*!< Scan enabled state. */ + LMGR_SCAN_MODE_INITIATE /*!< Initiate enabled state. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising broadcast user data. */ +typedef struct +{ + uint8_t buf[LL_ADVBU_MAX_LEN]; /*!< ADVB-U buffer. */ + uint8_t len; /*!< ADVB-U buffer length. */ + bool_t modified; /*!< Content modified by host. */ +} lmgrAdvbUser_t; + +/*! \brief Link layer manager persistent control block (persists with resets). */ +typedef struct +{ + llEvtCback_t evtCback; /*!< Event callback. */ + llAclCback_t sendCompCback; /*!< ACL data send complete callback. */ + llAclCback_t recvPendCback; /*!< ACL data receive pending callback. */ + wsfHandlerId_t handlerId; /*!< System event handler ID. */ + uint16_t connCtxSize; /*!< Size of the connection context. */ + uint16_t advSetCtxSize; /*!< Size of the advertising set context. */ + uint16_t perScanCtxSize; /*!< Size of the periodic scanning context. */ + uint64_t featuresDefault; /*!< Default supported features. */ + + /* Device parameters */ + uint64_t bdAddr; /*!< Public device address. */ + uint64_t supStates; /*!< Supported states. */ +} lmgrPersistCtrlBlk_t; + +/*! \brief Link layer manager control block (cleared with resets). */ +typedef struct +{ + /* Status */ + uint8_t numConnEnabled; /*!< Number of active connection. */ + bool_t advEnabled; /*!< Legacy advertising is enabled. */ + uint8_t numExtAdvEnabled; /*!< Number of extended advertising is enabled. */ + uint8_t numScanEnabled; /*!< Number of scan is enabled. */ + uint8_t numInitEnabled; /*!< Number of initiate is enabled. */ + uint8_t scanMode; /*!< Discover or initiating scan mode. */ + uint8_t numWlFilterEnabled; /*!< Number of enabled whitelist filters. */ + uint8_t numPlFilterEnabled; /*!< Number of enabled periodic filters. */ + bool_t testEnabled; /*!< Test is enabled. */ + uint8_t resetDelayRefCnt; /*!< Reset delay reference counter. */ + uint8_t extAdvEnaDelayCnt; /*!< Extended advertising enable event delay reference count. */ + uint8_t advSetEnaStatus; /*!< Last advertising set enable error status. */ + uint8_t numExtScanPhys; /*!< Number of extended scanning PHYs enabled. */ + uint8_t extScanEnaDelayCnt; /*!< Extended scanning enable event delay reference count. */ + uint8_t extScanEnaStatus; /*!< Last extended scanning enable error status. */ + + /* Device parameters */ + bool_t bdAddrRndModAdv; /*!< Modified random address (advertising). */ + bool_t bdAddrRndModScan; /*!< Modified random address (scan). */ + bool_t bdAddrRndValid; /*!< Random device address valid. */ + uint32_t opModeFlags; /*!< Operational mode flags. */ + uint64_t bdAddrRnd; /*!< Random device address. */ + uint64_t features; /*!< Used local supported features. */ + + /* Operational parameters. */ + int8_t advTxPwr; /*!< Advertising Tx power. */ + bool_t addrResEna; /*!< Address resolution enabled. */ + bool_t useLegacyCmds; /*!< Use only legacy advertising, scan or initiate commands. */ + bool_t useExtCmds; /*!< Use only extended advertising, scan or initiate commands. */ + + /* Power Class 1. */ + int8_t powerThreshold[LL_MAX_PHYS]; /*!< Power threshold for each PHY. */ + uint8_t localMinUsedChan[LL_MAX_PHYS]; /*!< Local minimum number of used channels for each PHY. */ +} lmgrCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrPersistCtrlBlk_t lmgrPersistCb; +extern lmgrCtrlBlk_t lmgrCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Reset */ +void LmgrSetDefaults(void); +void LmgrIncResetRefCount(void); +void LmgrDecResetRefCount(void); + +/* Whitelist */ +void LmgrIncWhitelistRefCount(void); +void LmgrDecWhitelistRefCount(void); + +/* Periodic List */ +void LmgrIncPeriodiclistRefCount(void); +void LmgrDecPeriodiclistRefCount(void); + +/* Status */ +bool_t LmgrIsAddressTypeAvailable(uint8_t ownAddrType); +bool_t LmgrIsLegacyCommandAllowed(void); +bool_t LmgrIsExtCommandAllowed(void); + +/* Event Messages */ +void LmgrSendAdvEnableCnf(uint8_t status); +void LmgrSendScanEnableCnf(uint8_t status); +void LmgrSendAdvSetTermInd(uint8_t handle, uint8_t status, uint16_t connHandle, uint8_t numEvents); +bool_t LmgrSendEvent(LlEvt_t *pEvt); + +/*! \} */ /* LL_LMGR_API */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master.h new file mode 100644 index 0000000000..8f3eeb868c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master.h @@ -0,0 +1,79 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager advertising master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_ADV_MASTER_H +#define LMGR_API_ADV_MASTER_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API_ADV_MST + * \{ + */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Scan parameters. */ +typedef struct +{ + uint16_t scanInterval; /*!< Scan interval in BB ticks. */ + uint16_t scanWindow; /*!< Scan window duration in BB ticks. */ + uint8_t scanType; /*!< Advertising type. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t scanFiltPolicy; /*!< Scanning filter policy. */ +} lmgrScanParam_t; + +/*! \brief Master role device parameter definition. */ +typedef struct +{ + lmgrScanParam_t scanParam; /*!< Scan parameters. */ + uint64_t chanClass; /*!< Channel class. */ + uint8_t scanChanMap; /*!< Scan channel map. */ + uint8_t numAdvReport; /*!< Number of pending advertising reports. */ +} lmgrMstScanCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrMstScanCtrlBlk_t lmgrMstScanCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LmgrMstInit(void); + +/*! \} */ /* LL_LMGR_API_ADV_MST */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_ADV_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master_ae.h new file mode 100644 index 0000000000..05f6b4428f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_master_ae.h @@ -0,0 +1,63 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager advertising extension interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_ADV_MASTER_AE_H +#define LMGR_API_ADV_MASTER_AE_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Periodic advertising sync established event */ +typedef struct +{ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t addrType; /*!< Address type. */ + bdAddr_t addr; /*!< Address. */ + uint8_t advPhy; /*!< Advertising PHY. */ + uint16_t advInterval; /*!< Advertising interval. */ + uint8_t advClkAccuracy; /*!< Advertising clock accuracy. */ +} lmgrPerAdvSyncEstdInd_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Events */ +void LmgrSendExtScanEnableCnf(uint8_t status); +void LmgrSendScanTimeoutInd(void); +void LmgrSendExtAdvRptInd(LlExtAdvReportInd_t *pEvt); +void LmgrSendPerAdvRptInd(LlPerAdvReportInd_t *pEvt); +void LmgrSendSyncEstInd(uint8_t status, uint16_t handle, lmgrPerAdvSyncEstdInd_t *pEvt); +void LmgrSendSyncLostInd(uint16_t handle); + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_ADV_MASTER_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave.h new file mode 100644 index 0000000000..d689eb7cec --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave.h @@ -0,0 +1,86 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager advertising slave interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_ADV_SLAVE_H +#define LMGR_API_ADV_SLAVE_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API_ADV_SLV + * \{ + */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising parameters. */ +typedef struct +{ + uint32_t advInterMin; /*!< Minimum advertising interval. */ + uint32_t advInterMax; /*!< Maximum advertising interval. */ + uint8_t advType; /*!< Advertising type. */ + uint8_t ownAddrType; /*!< Address type used by this device. */ + uint8_t peerAddrType; /*!< Address type of peer device. Only used for directed advertising. */ + uint64_t peerAddr; /*!< Address of peer device. Only used for directed advertising. */ + uint8_t advChanMap; /*!< Advertising channel map. */ + uint8_t advFiltPolicy; /*!< Advertising filter policy. */ +} lmgrAdvParam_t; + +/*! \brief Slave role device parameter definition. */ +typedef struct +{ + uint32_t advTermCntDown; /*!< Advertising termination count down. */ + lmgrAdvParam_t advParam; /*!< Advertising parameters. */ + lmgrAdvbUser_t advData; /*!< Advertising host data buffer. */ + lmgrAdvbUser_t scanRspData; /*!< Scan response host data buffer. */ + uint8_t ownAddrType; /*!< Actual address type used by this device. */ + uint64_t localRpa; /*!< Local RPA used by this device. */ + bool_t scanReportEna; /*!< Scan report events enabled. */ + uint8_t defTxPhyOpts; /*!< Default Tx PHY options */ +} lmgrSlvAdvCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrSlvAdvCtrlBlk_t lmgrSlvAdvCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LmgrSlvInit(void); + +/*! \} */ /* LL_LMGR_API_ADV_SLV */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_ADV_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave_ae.h new file mode 100644 index 0000000000..ad0b3abe13 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_adv_slave_ae.h @@ -0,0 +1,46 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager advertising extension interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_ADV_SLAVE_AE_H +#define LMGR_API_ADV_SLAVE_AE_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Events */ +void LmgrSendExtAdvEnableCnf(uint8_t handle, uint8_t status); +void LmgrSendScanReqReceivedInd(uint8_t handle, uint8_t scanAddrType, uint64_t scanAddr); +void LmgrSendAdvSetTermInd(uint8_t handle, uint8_t status, uint16_t connHandle, uint8_t numEvents); +void LmgrSendPeriodicAdvEnableCnf(uint8_t handle, uint8_t status); + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_ADV_SLAVE_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_conn.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_conn.h new file mode 100644 index 0000000000..8e56d2553a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_conn.h @@ -0,0 +1,79 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_CONN_H +#define LMGR_API_CONN_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API_CONN + * \{ + */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Slave role device parameter definition. */ +typedef struct +{ + uint8_t availTxBuf; /*!< Available number of transmit buffers. */ + uint8_t availRxBuf; /*!< Available number of receive buffers. */ + + uint16_t maxTxLen; /*!< Default maximum number of Data PDU bytes. */ + uint16_t maxTxTime; /*!< Default maximum microseconds for a Data PDU. */ + + wsfQueue_t rxDataQ; /*!< Receive Data PDU (LE-U or LE-C) queue. */ + + uint32_t dataPendMsk; /*!< Bitmask of connection handles with new pending data. */ + + uint8_t allPhys; /*!< Default all PHYs. */ + uint8_t txPhys; /*!< Default transmitter PHYs. */ + uint8_t rxPhys; /*!< Default receiver PHYs. */ + +} lmgrConnCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrConnCtrlBlk_t lmgrConnCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LmgrConnInit(void); + +/*! \} */ /* LL_LMGR_API_CONN */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_CONN_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_priv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_priv.h new file mode 100644 index 0000000000..19f06571b1 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_priv.h @@ -0,0 +1,67 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager privacy interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_PRIV_H +#define LMGR_API_PRIV_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API_PRIV + * \{ + */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Slave role device parameter definition. */ +typedef struct +{ + uint32_t resPrivAddrTimeout; /*!< Resolvable private address timeout. */ + uint8_t numPendingAddrRes; /*!< Number of pending address resolutions. */ +} lmgrPrivCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrPrivCtrlBlk_t lmgrPrivCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LmgrPrivInit(void); + +/*! \} */ /* LL_LMGR_API_PRIV */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_PRIV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_sc.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_sc.h new file mode 100644 index 0000000000..336099a81a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/include/lmgr_api_sc.h @@ -0,0 +1,68 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer manager secure connections interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LMGR_API_SC_H +#define LMGR_API_SC_H + +#include "lmgr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LMGR_API_SC + * \{ + */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Secure connections parameter definition. */ +typedef struct +{ + uint8_t privKey[LL_ECC_KEY_LEN]; /*!< P-256 private key. */ + bool_t eccOpActive; /*!< An ECC generation operation is active. */ + bool_t privKeySet; /*!< P-256 private key set; do not generate new one. */ +} lmgrScCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lmgrScCtrlBlk_t lmgrScCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void LmgrScInit(void); + +/*! \} */ /* LL_LMGR_API_SC */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LMGR_API_SC_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int.h new file mode 100644 index 0000000000..c6f0dec20b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int.h @@ -0,0 +1,190 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_H +#define LCTR_INT_H + +#include "lctr_api.h" +#include "ll_defs.h" +#include "lmgr_api.h" +#include "ll_math.h" + +#if (LL_ENABLE_TESTER) +#include "ll_tester_api.h" +#include "lctr_int_tester.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Minimum delay between connect indication and data channel in CONNECT_IND units. */ +#define LCTR_DATA_CHAN_DLY 1 /* 1.25 ms */ + +/*! \brief Minimum delay between auxiliary connect request and data channel using uncoded PHY in CONNECT_REQ units. */ +#define LCTR_DATA_CHAN_DLY_AUX_UNCODED 2 /* 2.5 ms */ + +/*! \brief Minimum delay between auxiliary connect request and data channel using coded PHY in CONNECT_REQ units. */ +#define LCTR_DATA_CHAN_DLY_AUX_CODED 3 /* 3.75 ms */ + +/*! \brief Convert connect indication ticks to scheduler ticks. */ +#define LCTR_CONN_IND_TICKS(x) ((x) * (1250 / LL_BLE_US_PER_TICK)) + +/*! \brief Convert connect indication ticks to milliseconds (no divide, rounds up). */ +#define LCTR_CONN_IND_MS(x) ((x) + ((x) >> 2) + (((x) & 3) ? 1 : 0)) + +/*! \brief Convert connect indication ticks to microseconds. */ +#define LCTR_CONN_IND_US(x) ((x) * 1250) + +/*! \brief Convert connect indication timeout ticks to milliseconds. */ +#define LCTR_CONN_IND_TO_MS(x) ((x) * 10) + +/*! \brief Convert microseconds to connection indication ticks. */ +#define LCTR_US_TO_CONN_IND(x) LL_MATH_DIV_1250(x) + +/*! \brief Convert BLE protocol ticks to microseconds. */ +#define LCTR_BLE_TO_US(x) ((x) * LL_BLE_US_PER_TICK) + +/*! \brief Convert periodic interval milliseconds to microseconds. */ +#define LCTR_PER_INTER_TO_US(x) ((x) * 1250) + +/*! \brief Convert periodic interval microseconds to milliseconds. */ +#define LCTR_PER_INTER_TO_MS(x) LL_MATH_DIV_1250(x) + +/*! \brief Convert periodic sync timeout unit to milliseconds. */ +#define LCTR_PER_SYNC_TIMEOUT_TO_MS(x) ((x) * 10) + +/*! \brief Fast termination supervision multiplier. */ +#define LCTR_FAST_TERM_CNT 6 + +/*! \brief Duration of a advertising packet in microseconds. */ +#define LCTR_ADV_PKT_1M_US(len) ((LL_PREAMBLE_LEN_1M + LL_AA_LEN + LL_ADV_HDR_LEN + len + LL_CRC_LEN) << 3) + +/*! \brief Duration of a connection indication packet in microseconds. */ +#define LCTR_CONN_IND_PKT_1M_US LCTR_ADV_PKT_1M_US(LL_CONN_IND_PDU_LEN) + +/*! \brief Extra area in ADVB buffer. */ +#define LCTR_ADVB_BUF_EXTRA_SIZE 6 + +/*! \brief Size for ADVB buffer allocation. */ +#define LCTR_ADVB_BUF_SIZE (WSF_MAX(BB_FIXED_ADVB_PKT_LEN, LL_ADVB_MAX_LEN) + LCTR_ADVB_BUF_EXTRA_SIZE) + +/*! \brief RSSI offset of extra data in ADVB buffer. */ +#define LCTR_ADVB_BUF_OFFSET_RSSI ((LCTR_ADVB_BUF_SIZE - LCTR_ADVB_BUF_EXTRA_SIZE) + 0) + +/*! \brief RPA offset of extra data in ADVB buffer. */ +#define LCTR_ADVB_BUF_OFFSET_RX_RPA ((LCTR_ADVB_BUF_SIZE - LCTR_ADVB_BUF_EXTRA_SIZE) + 1) + +/*! \brief CRC offset of extra data in ADVB buffer. */ +#define LCTR_ADVB_BUF_OFFSET_CRC ((LCTR_ADVB_BUF_SIZE - LCTR_ADVB_BUF_EXTRA_SIZE) + 2) + +/*! \brief LCTR Maximum span of scheduler elements. */ +#define LCTR_SCH_MAX_SPAN 0x80000000 + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Channel parameters. */ +typedef struct +{ + /* Channel parameters */ + uint8_t lastChanIdx; /*!< Current channel index. */ + uint8_t numUsedChan; /*!< Number of used channels. */ + uint64_t chanMask; /*!< Channel mask. */ + uint8_t chanRemapTbl[LL_CHAN_DATA_MAX_IDX + 1]; /*!< Channel remapping table. */ + + uint8_t usedChSel; /*!< Used channel selection. */ + uint16_t chIdentifier; /*!< Channel identifier. */ +} lctrChanParam_t; + +/*! \brief Call signature of a reset handler. */ +typedef void (*LctrResetHdlr_t)(void); + +/*! \brief Call signature of a message dispatch handler. */ +typedef void (*LctrMsgDisp_t)(lctrMsgHdr_t *pMsg); + +/*! \brief Call signature of a message dispatch handler. */ +typedef void (*LctrEvtHdlr_t)(void); + +/*! \brief Reservation manager callback signature. */ +typedef void (*LctrRmCback_t)(uint32_t rsvnOffs[], uint32_t refTime); + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern LctrResetHdlr_t lctrResetHdlrTbl[LCTR_DISP_TOTAL]; +extern LctrMsgDisp_t lctrMsgDispTbl[LCTR_DISP_TOTAL]; +extern LctrEvtHdlr_t lctrEventHdlrTbl[LCTR_EVENT_TOTAL]; +extern lctrMsgHdr_t *pLctrMsg; +extern LctrRmCback_t lctrGetConnOffsetsCback; +extern LctrRmCback_t lctrGetPerOffsetsCback; + +/************************************************************************************************** + Functions +**************************************************************************************************/ + +/* Helper routines. */ +uint32_t lctrComputeAccessAddr(void); +uint8_t lctrComputeHopInc(void); +uint8_t lctrPeriodicSelectNextChannel(lctrChanParam_t *pChanParam, uint16_t eventCounter); +void lctrPeriodicBuildRemapTable(lctrChanParam_t *pChanParam); +uint16_t lctrCalcTotalAccuracy(uint8_t mstScaIdx); +uint32_t lctrComputeCrcInit(void); + +/* Host events */ +void lctrNotifyHostHwErrInd(uint8_t code); +void lctrNotifyHostConnectInd(uint16_t handle, uint8_t role, lctrConnInd_t *pConnInd, + uint8_t peerIdAddrType, uint64_t peerIdAddr, uint64_t peerRpa, + uint64_t localRpa, uint8_t status, uint8_t usedChSel); + +/* State machine */ +void lctrMstScanExecuteSm(uint8_t event); +void lctrMstInitExecuteSm(uint8_t event); +void lctrSlvAdvExecuteSm(uint8_t event); + +/*************************************************************************************************/ +/*! + * \brief Get operational mode flag. + * + * \param flag Flag to check. + * + * \return TRUE if flag is set. + * + * Get mode flag governing LL operations. + */ +/*************************************************************************************************/ +static inline bool_t lctrGetOpFlag(uint32_t flag) +{ + return (lmgrCb.opModeFlags & flag) ? TRUE : FALSE; +} + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master.h new file mode 100644 index 0000000000..bfc5df7427 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master.h @@ -0,0 +1,180 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ADV_MASTER_H +#define LCTR_INT_ADV_MASTER_H + +#include "lctr_int.h" +#include "lctr_api_adv_master.h" +#include "lctr_pdu_adv.h" +#include "bb_ble_api.h" +#include "bb_ble_api_op.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Minimum amount of time required for scanning, (minimum scanWindow size is 2.5ms). */ +#define LCTR_MIN_SCAN_USEC 0 + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master scan states. */ +enum +{ + LCTR_SCAN_STATE_DISABLED, /*!< Scan disabled state. */ + LCTR_SCAN_STATE_DISCOVER, /*!< Scan enabled state. */ + LCTR_SCAN_STATE_SHUTDOWN, /*!< Scan shutdown in progress. */ + LCTR_SCAN_STATE_RESET, /*!< Scan reset in progress. */ + LCTR_SCAN_STATE_TOTAL /*!< Total number of scan states. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising report filter. */ +typedef struct +{ + uint64_t filtTbl[LL_NUM_ADV_FILT]; + /*!< Advertising filter table. */ + bool_t enable; /*!< Enable advertising filtering. */ + bool_t addToFiltTbl; /*!< TRUE if duplicate is not found and is to be added to the table. */ + uint8_t headIdx; /*!< Head index of filter table. */ + uint32_t validMask; /*!< Mask for valid entries. */ +} lctrAdvRptFilt_t; + +/*! \brief Master scan state context. */ +typedef struct +{ + /* Scan buffer (placed here to 32-bit align) */ + uint8_t reqBuf[BB_REQ_PDU_MAX_LEN]; + /*!< Scan host data buffer. */ + uint8_t state; /*!< Scan state. */ + wsfQueue_t rxAdvbQ; /*!< Receive ADVB queue. */ + wsfQueue_t rxDirectAdvbQ; /*!< Receive direct ADVB queue. */ + + uint32_t scanWinStart; /*!< Scan window origin. */ + + lmgrScanParam_t scanParam; /*!< Scan parameters. */ + + union + { + /*! Discovery data. */ + struct + { + lctrAdvRptFilt_t advFilt; /*!< Advertising filter data. */ + uint64_t scanReqAdvAddr; /*!< Advertiser address in the scan request. */ + } disc; + + /*! Initiate data. */ + struct + { + lctrConnInd_t connInd; /*!< Connection indication. */ + uint64_t localRpa; /*!< Local RPA. */ + uint16_t connHandle; /*!< Connection handle. */ + uint16_t connInterval; /*!< Connection interval. */ + uint32_t firstCeDue; /*!< First CE due time. */ + bool_t connBodLoaded; /*!< Connection BOD loaded flag. */ + uint8_t usedChSel; /*!< Used channel selection. */ + } init; /*!< Initiation specific data. */ + } data; /*!< Scan specific data. */ + + /* BB/ISR context */ + bool_t selfTerm; /*!< Self-termination flag. */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + int8_t advRssi; /*!< Last received advertising or scan response RSSI. */ + BbOpDesc_t scanBod; /*!< Scan BOD. */ + BbBleData_t bleData; /*!< BLE BB operation data. */ + lctrAdvbPduHdr_t reqPduHdr; /*!< Request PDU header. */ + uint16_t upperLimit; /*!< Scan backoff upper limit. */ + uint8_t backoffCount; /*!< Scan backoff count. */ + uint8_t consRspSuccess; /*!< Number of consecutive scan response received. */ + uint8_t consRspFailure; /*!< Number of consecutive scan response failures. */ +} lctrMstScanCtx_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrMstScanCtx_t lctrMstScan; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Builder */ +void lctrMstDiscoverBuildOp(void); +void lctrMstScanCleanupOp(lctrMstScanCtx_t *pCtx); + +/* Event handlers. */ +void lctrMstRxAdvBPduHandler(void); +void lctrMstRxDirectAdvBPduHandler(void); + +/* ISR */ +void lctrMstDiscoverEndOp(BbOpDesc_t *pOp); +bool_t lctrMstDiscoverAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +void lctrMstDiscoverAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstScanReqTxCompHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstScanRspRxCompHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf); + +/* Action routines. */ +void lctrScanActDiscover(void); +void lctrScanActShutdown(void); +void lctrScanActScanCnf(void); +void lctrScanActDisallowScan(void); +void lctrScanActSelfTerm(void); +void lctrScanActScanTerm(void); +void lctrScanActResetTerm(void); +void lctrScanActUpdateScanParam(void); +void lctrScanActUpdateScanFilt(void); +void lctrInitActInitiate(void); +void lctrInitActConnect(void); +void lctrInitActShutdown(void); + +/* Helper routines. */ +void lctrScanCleanup(lctrMstScanCtx_t *pCtx); +void lctrScanNotifyHostInitiateError(uint8_t reason, uint8_t peerAddrType, uint64_t peerAddr); + +/* Channel. */ +uint8_t lctrScanChanSelectInit(uint8_t chanMap); +uint8_t lctrScanChanSelectNext(uint8_t chanIdx, uint8_t chanMap); + +/* Advertising report filtering. */ +void lctrAdvRptEnable(lctrAdvRptFilt_t *pAdvFilt, bool_t filtEna); +void lctrAdvRptGenerateLegacyHash(uint64_t *pHash, uint8_t addrType, uint64_t addr, uint8_t eventType); +void lctrAdvRptGenerateExtHash(uint64_t *pHash, uint8_t addrType, uint64_t addr, uint8_t eventType, + uint8_t sid, uint16_t did); +bool_t lctrAdvRptCheckDuplicate(lctrAdvRptFilt_t *pAdvFilt, uint64_t hash); +void lctrAdvRptAddEntry(lctrAdvRptFilt_t *pAdvFilt, uint64_t hash); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ADV_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master_ae.h new file mode 100644 index 0000000000..18a9cd387f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_master_ae.h @@ -0,0 +1,433 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller extended scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ADV_MASTER_AE_H +#define LCTR_INT_ADV_MASTER_AE_H + +#include "lctr_int.h" +#include "lctr_api_adv_master_ae.h" +#include "lctr_int_adv_master.h" +#include "lctr_pdu_adv_ae.h" +#include "bb_ble_api.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Resolve the extended scan handle from the context pointer. */ +#define LCTR_GET_EXT_SCAN_HANDLE(pCtx) (pCtx - lctrMstExtScanTbl) + +/*! \brief Resolve the periodic scanning handle from the context pointer. */ +#define LCTR_GET_PER_SCAN_HANDLE(pCtx) (pCtx - lctrMstPerScanTbl) + +/*! \brief Resolve the periodic scanning context from the handle. */ +#define LCTR_GET_PER_SCAN_CTX(h) &(lctrMstPerScanTbl[h]) + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master scan states. */ +enum +{ + LCTR_EXT_SCAN_STATE_DISABLED, /*!< Scan disabled state. */ + LCTR_EXT_SCAN_STATE_DISCOVER, /*!< Scan enabled state. */ + LCTR_EXT_SCAN_STATE_SHUTDOWN, /*!< Scan shutdown in progress. */ + LCTR_EXT_SCAN_STATE_RESET, /*!< Scan reset in progress. */ + LCTR_EXT_SCAN_STATE_TOTAL /*!< Total number of scan states. */ +}; + +/*! \brief Create sync states. */ +enum +{ + LCTR_CREATE_SYNC_STATE_DISABLED, /*!< Create sync disabled state. */ + LCTR_CREATE_SYNC_STATE_DISCOVER, /*!< Create sync enabled state. */ + LCTR_CREATE_SYNC_STATE_SHUTDOWN, /*!< Create sync shutdown in process state. */ + LCTR_CREATE_SYNC_STATE_RESET, /*!< Create sync reset in progress. */ + LCTR_CREATE_SYNC_STATE_TOTAL /*!< Total number of Create sync states. */ +}; + +/*! \brief Periodic scanning states. */ +enum +{ + LCTR_PER_SCAN_STATE_DISABLE, /*!< Periodic scanning disabled state. */ + LCTR_PER_SCAN_STATE_SYNC_ESTD, /*!< Periodic scanning sync established state. */ + LCTR_PER_SCAN_STATE_SYNC_TERMINATE, /*!< Periodic scanning sync terminate in process state. */ + LCTR_PER_SCAN_STATE_RESET, /*!< Periodic scanning sync reset in progress. */ + LCTR_PER_SCAN_STATE_TOTAL /*!< Total number of Periodic scanning states. */ +}; + +/*! \brief Internal common (non-context, non-broadcast) events. */ +enum +{ + LCTR_EXT_SCAN_MSG_NON_SM = LCTR_EXT_SCAN_MSG_TOTAL, + LCTR_EXT_SCAN_MSG_TMR_DUR_EXP, /*!< Duration timer expired event. */ + LCTR_EXT_SCAN_MSG_TMR_PER_EXP /*!< Period timer expired event. */ +}; + +/*! \brief Extended advertising report assembly state. */ +typedef enum +{ + LCTR_RPT_STATE_IDLE, /*!< No report assembly in progress. */ + LCTR_RPT_STATE_IN_PROGRESS, /*!< Report assembly in progress. */ + LCTR_RPT_STATE_COMP, /*!< Report assembly completed. */ +} lctrRptState_t; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Extended scanning context. */ +typedef struct +{ + /* Scan state. */ + uint8_t state; /*!< Scan state. */ + bool_t selfTerm; /*!< Self-termination flag. */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + uint32_t scanWinStart; /*!< Scan window origin. */ + LlScanParam_t scanParam; /*!< Scan parameters. */ + /* N.B. Scan parameters must persist after initiate. */ + union + { + struct + { + /* Report handling. */ + LlExtAdvReportInd_t advRpt; /*!< Advertising report. */ + lctrRptState_t advRptState:8; /*!< Advertising report state. */ + + /* Backoff. */ + uint16_t upperLimit; /*!< Scan backoff upper limit. */ + uint8_t backoffCount; /*!< Scan backoff count. */ + uint8_t consRspSuccess; /*!< Number of consecutive scan response received. */ + uint8_t consRspFailure; /*!< Number of consecutive scan response failures. */ + uint64_t scanReqAdvAddr; /*!< Advertiser address in the scan request. */ + } scan; /*!< Extended scan data. */ + + struct + { + LlExtInitScanParam_t param; /*!< Extended initiating scan parameters. */ + LlConnSpec_t connSpec; /*!< Connection specification. */ + lctrConnInd_t connInd; /*!< Connection indication. */ + uint64_t localRpa; /*!< Local RPA. */ + uint16_t connHandle; /*!< Connection handle. */ + uint16_t connInterval; /*!< Connection interval. */ + uint32_t firstCeDue; /*!< First CE due time. */ + uint32_t scanWinStart; /*!< Scan window origin. */ + bool_t connBodLoaded; /*!< Connection BOD loaded flag. */ + bool_t isLegacy; /*!< TRUE if legacy advertising PDU is received. */ + uint8_t usedChSel; /*!< Used channel selection. */ + uint8_t filtPolicy; /*!< Initiate filter policy. */ + uint8_t ownAddrType; /*!< Own address type. */ + uint8_t phy; /*!< PHY selection. */ + } init; /*!< Extended initiate data. */ + } data; /*!< Extended scan or extended initiate data. */ + + /* Scan buffer (placed here to 32-bit align) */ + uint8_t reqBuf[BB_REQ_PDU_MAX_LEN]; + /*!< Scan host data buffer. */ + uint8_t auxRspBuf[LL_EXT_ADVB_MAX_LEN]; + /*!< Auxiliary response buffer. */ + uint8_t *pExtAdvData; /*!< Advertising data reassembly buffer. */ + + /* Packet state. */ + lctrExtAdvHdr_t extAdvHdr; /*!< Coalesced extended advertising header. */ + lctrAdvbPduHdr_t reqPduHdr; /*!< Request PDU header. */ + lctrAuxPtr_t priChAuxPtr; /*!< Primary channel AuxPtr. */ + lctrSyncInfo_t secSyncInfo; /*!< Secondary channel SyncInfo. */ + + /* BB/ISR. */ + bool_t auxOpPending; /*!< Auxiliary operation pending. */ + uint8_t bodTermCnt; /*!< Number of BOD terminated. */ + BbOpDesc_t scanBod; /*!< Scan BOD. */ + BbBleData_t scanBleData; /*!< BLE BB operation data. */ + BbOpDesc_t auxScanBod; /*!< Auxiliary scan BOD. */ + BbBleData_t auxBleData; /*!< Auxiliary BLE BB operation data. */ +} lctrExtScanCtx_t; + +/*! \brief Extended scanning control block. */ +typedef struct +{ + /* State. */ + uint8_t enaPhys; /*!< Enabled PHYs. */ + bool_t scanTermByHost; /*!< Host initiated scan disable. */ + uint32_t nextScanWinStart; /*!< Next scan window origin. */ + + /* Report */ + uint8_t termReason; /*!< Termination reason. */ + uint8_t filtDup; /*!< Advertising report filter mode. */ + lctrAdvRptFilt_t advFilt; /*!< Advertising filter data. */ + + /* Timers. */ + uint32_t scanDurMs; /*!< Scan duration in milliseconds. */ + uint32_t scanPerMs; /*!< Scan period in milliseconds. */ + wsfTimer_t tmrScanDur; /*!< Scan duration timer. */ + wsfTimer_t tmrScanPer; /*!< Scan period timer. */ +} lctrExtScanCtrlBlk_t; + + +/*! \brief Periodic advertising create sync parameters. */ +typedef struct +{ + uint8_t filterPolicy; /*!< Filter Policy. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint64_t advAddr; /*!< Advertiser Address. */ +} lctrPerParam_t; + +/*! \brief Periodic scanning context. */ +typedef struct +{ + bool_t enabled; /*!< Context enabled. */ + uint8_t state; /*!< Current state. */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + bool_t cancelCreateSync; /*!< Shut down due to create sync cancel. */ + bool_t firstPerAdvRcv; /*!< True if first periodic advertising packet is received. */ + + /* Report handling. */ + LlPerAdvReportInd_t advRpt; /*!< Periodic advertising report. */ + lctrRptState_t advRptState:8; /*!< Periodic advertising report state. */ + uint8_t *pPerAdvData; /*!< Periodic data reassembly buffer. */ + + /* BB data */ + BbOpDesc_t bod; /*!< Periodic scanning BOD. */ + BbBleData_t bleData; /*!< BLE BB operation data. */ + + /* Peer periodic advertising parameters */ + uint16_t eventCounter; /*!< Connection event counter. */ + uint32_t perInter; /*!< Periodic scanning interval in BB ticks. */ + uint8_t sca; /*!< Sleep clock accuracy. */ + uint32_t skipInter; /*!< Skip interval in BB ticks. */ + uint32_t minDurUsec; /*!< Minimum required duration in microseconds. */ + uint32_t rxSyncDelayUsec; /*!< Receive timeout in microseconds. */ + uint32_t lastAnchorPoint; /*!< Last anchor point in BB tick. */ + uint16_t lastActiveEvent; /*!< Last active event counter. */ + + /* Local periodic scanning parameters */ + uint16_t skip; /*!< Skip. */ + uint16_t syncTimeOutMs; /*!< Synchronization Timeout in Milliseconds. */ + + /* Filtering parameters */ + bbBlePerPduFiltParams_t filtParam; /*!< Periodic scan filter parameters. */ + + /* RF parameters */ + int8_t rssi; /*!< RSSI. */ + + lctrChanParam_t chanParam; /*!< Channel parameters. */ + + /* Supervision */ + wsfTimer_t tmrSupTimeout; /*!< Supervision timer. */ + + /* Peer device info */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t advAddrType; /*!< Advertiser Address Type. */ + uint64_t advAddr; /*!< Advertiser Address. */ + + /* Packet state. */ + lctrExtAdvHdr_t extAdvHdr; /*!< Coalesced extended advertising header. */ + + /* PHY */ + uint8_t rxPhys; /*!< Default receiver PHYs. */ + +} lctrPerScanCtx_t; + +/*! \brief Master scan state context. */ +typedef struct +{ + uint8_t state; /*!< Periodic scan state. */ + bool_t createSyncPending; /*!< Create sync is pending. */ + bbBlePerPduFiltParams_t filtParam; /*!< Periodic scan filter parameters. */ + lctrPerScanCtx_t *pPerScanCtx; /*!< Current synchronous context. */ +} lctrPerCreateSyncCtrlBlk_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrExtScanCtx_t lctrMstExtScanTbl[LCTR_SCAN_PHY_TOTAL]; +extern lctrExtScanCtrlBlk_t lctrMstExtScan; +extern lctrPerCreateSyncCtrlBlk_t lctrPerCreateSync; +extern lctrPerScanCtx_t lctrMstPerScanTbl[LL_MAX_PER_SCAN]; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Builder */ +uint8_t lctrMstExtDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx); +uint8_t lctrMstAuxDiscoverBuildOp(lctrExtScanCtx_t *pExtScanCtx); +void lctrMstAuxDiscoverOpCommit(lctrExtScanCtx_t *pExtScanCtx, lctrAuxPtr_t *pAuxPtr, uint32_t startTs, uint32_t endTs); +uint8_t lctrMstPerScanBuildOp(lctrPerScanCtx_t *pPerScanCtx, lctrPerCreateSyncMsg_t *pMsg); +void lctrMstPerScanOpCommit(lctrExtScanCtx_t *pExtScanCtx, lctrAuxPtr_t *pAuxPtr, lctrSyncInfo_t *pSyncInfo, uint32_t startTs, uint32_t endTs); + +/* ISR: Discovery packet handlers */ +bool_t lctrMstDiscoverRxExtAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +void lctrMstDiscoverRxExtAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstDiscoverRxAuxAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstDiscoverRxAuxScanRspHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf); +uint32_t lctrMstDiscoverRxAuxChainHandler(BbOpDesc_t *pOp, const uint8_t *pChainBuf); +bool_t lctrMstDiscoverRxAuxChainPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pChainBuf); +bool_t lctrMstDiscoverRxLegacyAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstDiscoverTxLegacyScanReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +bool_t lctrMstDiscoverRxLegacyScanRspHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf); +/* ISR: Discovery BOD handlers */ +void lctrMstExtDiscoverEndOp(BbOpDesc_t *pOp); +void lctrMstAuxDiscoverEndOp(BbOpDesc_t *pOp); +void lctrMstPerScanEndOp(BbOpDesc_t *pOp); +uint32_t lctrMstPerScanRxPerAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf, uint8_t status); +bool_t lctrMstPerScanRxPerAdvPktPostHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); + +/* Action routines. */ +void lctrExtScanActDiscover(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActShutdown(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActScanCnf(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActDisallowScan(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActScanTerm(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActSelfTerm(lctrExtScanCtx_t *pExtScanCtx); +void lctrExtScanActUpdateDiscover(lctrExtScanCtx_t *pExtScanCtx); +void lctrCreateSyncActCreate(void); +void lctrCreateSyncActCancel(void); +void lctrCreateSyncActTerminate(void); +void lctrCreateSyncActDone(void); +void lctrPerScanActSyncEstd(lctrPerScanCtx_t *pPerScanCtx); +void lctrPerScanActSyncTerminate(lctrPerScanCtx_t *pPerScanCtx); +void lctrPerScanActSyncTerminateDone(lctrPerScanCtx_t *pPerScanCtx); +void lctrPerScanActSyncTimeout(lctrPerScanCtx_t *pPerScanCtx); + +/* State machine */ +void lctrMstExtScanExecuteSm(lctrExtScanCtx_t *pExtScanCtx, uint8_t event); +void lctrMstCreateSyncExecuteSm(uint8_t event); +void lctrMstPerScanExecuteSm(lctrPerScanCtx_t *pPerScanCtx, uint8_t event); + +/* Helpers */ +lctrPerScanCtx_t *lctrAllocPerScanCtx(void); + +/* Messaging */ +void lctrSendExtScanMsg(lctrExtScanCtx_t *pExtScanCtx, uint8_t event); +void lctrSendCreateSyncMsg(uint8_t event); +void lctrSendPerScanMsg(lctrPerScanCtx_t *pCtx, uint8_t event); + +/*************************************************************************************************/ +/*! + * \brief Convert PHY value to PHY value in extended advertising report. + * + * \param auxPtrPhy Auxiliary Pointer PHY field. + * + * \return LL PHY value. + */ +/*************************************************************************************************/ +static inline uint8_t lctrConvertAuxPtrPhyToAdvRptPhy(uint8_t auxPtrPhy) +{ + switch (auxPtrPhy) + { + case 0: /* LE_1M */ + default: + return LL_PHY_LE_1M; + case 1: /* LE_2M */ + return LL_PHY_LE_2M; + case 2: /* LE_Coded */ + return LL_PHY_LE_CODED; + } +} + +/*************************************************************************************************/ +/*! + * \brief Convert AuxPtr PHY value to PHY value in extended advertising report. + * + * \param auxPtrPhy Auxiliary Pointer PHY field. + * + * \return BB PHY value. + */ +/*************************************************************************************************/ +static inline uint8_t lctrConvertAuxPtrPhyToBbPhy(uint8_t auxPtrPhy) +{ + switch (auxPtrPhy) + { + case 0: /* LE_1M */ + default: + return BB_PHY_BLE_1M; + case 1: /* LE_2M */ + return BB_PHY_BLE_2M; + case 2: /* LE_Coded */ + return BB_PHY_BLE_CODED; + } +} + +/*************************************************************************************************/ +/*! + * \brief Compute the connection interval window widening delay in microseconds. + * + * \param unsyncTimeUsec Unsynchronized time in microseconds. + * \param caPpm Total clock accuracy. + * + * \return Window widening delay in microseconds. + */ +/*************************************************************************************************/ +static inline uint32_t lctrCalcAuxAdvWindowWideningUsec(uint32_t unsyncTimeUsec, uint32_t caPpm) +{ + if (lctrGetOpFlag(LL_OP_MODE_FLAG_ENA_WW)) + { + /* Largest unsynchronized time is 1,996 seconds (interval=4s and latency=499) and + * largest total accuracy is 1000 ppm. */ + /* coverity[overflow_before_widen] */ + uint64_t wwDlyUsec = LL_MATH_DIV_10E6(((uint64_t)unsyncTimeUsec * caPpm) + + 999999); /* round up */ + + /* Reduce to 32-bits and always round up to a sleep clock tick. */ + return wwDlyUsec + pLctrRtCfg->ceJitterUsec; + } + else + { + return 0; + } +} + +/*************************************************************************************************/ +/*! + * \brief Compute auxiliary offset. + * + * \param pAuxPtr Auxiliary Pointer. + * \param pOffsetUsec Return auxiliary offset in microseconds. + * \param pSyncDelayUsec Return synchronization delay in microseconds. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrMstComputeAuxOffset(lctrAuxPtr_t *pAuxPtr, uint32_t *pOffsetUsec, uint32_t *pSyncDelayUsec) +{ + uint32_t offsetUsec = pAuxPtr->auxOffset * ((pAuxPtr->offsetUnits == LCTR_OFFS_UNITS_30_USEC) ? 30 : 300); + uint32_t caPpm = BbGetClockAccuracy() + ((pAuxPtr->ca == LCTR_CLK_ACC_0_50_PPM) ? 50 : 500); + uint32_t wwUsec = lctrCalcAuxAdvWindowWideningUsec(offsetUsec, caPpm); + + *pOffsetUsec = offsetUsec - wwUsec; + *pSyncDelayUsec = (wwUsec << 1) + ((pAuxPtr->offsetUnits == LCTR_OFFS_UNITS_30_USEC) ? 30 : 300); /* rounding compensation */ +} + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ADV_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave.h new file mode 100644 index 0000000000..7d2d0f3b30 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave.h @@ -0,0 +1,148 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller advertising slave interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ADV_SLAVE_H +#define LCTR_INT_ADV_SLAVE_H + +#include "lctr_int.h" +#include "lctr_api_adv_slave.h" +#include "lctr_pdu_adv.h" +#include "bb_ble_api.h" +#include "bb_ble_api_op.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Slave advertising states. */ +enum +{ + LCTR_ADV_STATE_DISABLED, /*!< Advertising disabled state. */ + LCTR_ADV_STATE_ENABLED, /*!< Advertising enabled state. */ + LCTR_ADV_STATE_SHUTDOWN, /*!< Advertising shutdown in progress. */ + LCTR_ADV_STATE_RESET, /*!< Advertising reset in progress. */ + LCTR_ADV_STATE_TOTAL /*!< Total number of advertising states. */ +}; + +/*! \brief Common extended advertising PDU types. */ + +enum +{ + LCTR_PDU_ADV_EXT_IND, + LCTR_PDU_AUX_ADV_IND, + LCTR_PDU_AUX_SCAN_RSP, + LCTR_PDU_AUX_SYNC_IND, + LCTR_PDU_AUX_CHAIN_IND, + LCTR_PDU_AUX_CONNECT_RSP +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Slave advertising state context. */ +typedef struct +{ + /* Adv buffer (placed here to 32-bit align) */ + uint8_t advBuf[LL_ADVB_MAX_LEN]; + /*!< Advertising host data buffer. */ + + uint8_t state; /*!< Advertising state. */ + + /* BB/ISR context */ + bool_t connIndRcvd; /*!< Connection indication received flag. */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + uint8_t usedChSel; /*!< Used channel selection. */ + BbOpDesc_t advBod; /*!< Advertising BOD. */ + BbBleData_t bleData; /*!< BLE BB operation data. */ + uint32_t reqEndTs; /*!< Last received request end of packet timestamp. */ + + /* Scan buffer (placed here to 32-bit align) */ + uint8_t scanRspBuf[LL_ADVB_MAX_LEN]; + /*!< Advertising host data buffer. */ + + wsfQueue_t rxScanReqQ; /*!< Received SCAN_REQ queue. */ +} lctrSlvAdvCtx_t; + +/*! \brief Scan request. */ +typedef struct +{ + uint8_t scanAddrType; /*!< Scanner address type. */ + uint64_t scanAddr; /*!< Scanner address. */ + uint8_t scanIdAddrType; /*!< Scanner ID address type. */ + uint64_t scanIdAddr; /*!< Scanner ID address. */ +} lctrSlvScanReport_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrSlvAdvCtx_t lctrSlvAdv; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Builder */ +void lctrSlvAdvBuildOp(void); +void lctrSlvAdvCleanupOp(void); + +/* Event handlers */ +void lctrSlvRxScanReq(void); + +/* Address selection */ +void lctrChooseAdvA(BbBleData_t * const pBle, lctrAdvbPduHdr_t *pPduHdr, + uint8_t ownAddrType, uint8_t peerAddrType, uint64_t peerAddr, + uint64_t *pAdvA); +void lctrChoosePeerAddr(BbBleData_t * const pBle, uint8_t ownAddrType, + uint8_t peerAddrType, uint64_t peerAddr, uint64_t *pPeerRpa); + +/* ISR */ +bool_t lctrSlvAdvHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +bool_t lctrScanReqHandler(BbOpDesc_t *pOp, uint8_t reqLen); +void lctrConnIndHandler(BbOpDesc_t *pOp, uint8_t reqLen, const uint8_t *pReqBuf); +void lctrSlvAdvPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +void lctrSlvAdvEndOp(BbOpDesc_t *pOp); + +/* Channel */ +uint32_t lctrCalcAdvDelay(void); + +/* Action routines */ +void lctrAdvActStart(void); +void lctrAdvActSelfStart(void); +void lctrAdvActShutdown(void); +void lctrAdvActAdvCnf(void); +void lctrAdvActDisallowAdvCnf(void); +void lctrAdvActSelfTerm(void); +void lctrAdvActAdvTerm(void); +void lctrAdvActResetTerm(void); +void lctrAdvActUpdateAdvParam(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ADV_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave_ae.h new file mode 100644 index 0000000000..3f9adce07a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_adv_slave_ae.h @@ -0,0 +1,324 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller slave extended advertising interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ADV_SLAVE_AE_H +#define LCTR_INT_ADV_SLAVE_AE_H + +#include "lctr_int.h" +#include "lctr_api_adv_slave_ae.h" +#include "lmgr_api_adv_slave_ae.h" +#include "bb_ble_api.h" +#include "bb_ble_api_op.h" +#include "lctr_pdu_adv.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Maximum value of the AuxPtr offset field. */ +#define LCTR_AUX_PTR_MAX_OFFSET 0x3FFF + +/*! \brief Number of shifted bytes for Used PHY field from the AUX Offset. */ +#define LCTR_AUX_OFFS_USED_PHY_SHIFT 13 + +/*! \brief Extended Advertising packet length. */ +#define LCTR_EXT_ADVB_LEN(ehLen, dLen) (LL_ADV_HDR_LEN + ehLen + dLen) + +/*! \brief Extended header common field length. */ +#define LCTR_EXT_HDR_CMN_LEN 1 + +/*! \brief Extended header flags field length. */ +#define LCTR_EXT_HDR_FLAG_LEN 1 + +/*! \brief Maximum size of a single complete advertising data buffer. */ +#define LCTR_COMP_EXT_ADV_DATA_MAX_LEN 251 /* TODO: cfg_mac_ble.h configuration */ + +/*! \brief Resolve the extended advertising index from the context pointer. */ +#define LCTR_GET_EXT_ADV_INDEX(pAdvSet) (pAdvSet - &pLctrAdvSetTbl[0]) + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Slave extended advertising states. */ +enum +{ + LCTR_EXT_ADV_STATE_DISABLED, /*!< Extended advertising disabled state. */ + LCTR_EXT_ADV_STATE_ENABLED, /*!< Extended advertising enabled state. */ + LCTR_EXT_ADV_STATE_SHUTDOWN, /*!< Extended advertising shutdown in progress. */ + LCTR_EXT_ADV_STATE_RESET, /*!< Extended advertising reset in progress. */ + LCTR_EXT_ADV_STATE_TOTAL /*!< Total number of extended advertising states. */ +}; + +/*! \brief Slave periodic advertising states. */ +enum +{ + LCTR_PER_ADV_STATE_DISABLED, /*!< Periodic advertising disabled state. */ + LCTR_PER_ADV_STATE_ENABLED, /*!< Periodic advertising enabled state. */ + LCTR_PER_ADV_STATE_SHUTDOWN, /*!< Periodic advertising shutdown in progress. */ + LCTR_PER_ADV_STATE_RESET, /*!< Periodic advertising reset in progress. */ + LCTR_PER_ADV_STATE_TOTAL /*!< Total number of Periodic advertising states. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Extended advertising parameters. */ +typedef struct +{ + uint16_t advEventProp; /*!< Advertising Event Properties. */ + uint32_t priAdvInterMin; /*!< Primary Advertising Interval Minimum. */ + uint32_t priAdvInterMax; /*!< Primary Advertising Interval Maximum. */ + uint32_t priAdvTermCntDown; /*!< Primary Advertising termination count down. */ + uint64_t peerAddr; /*!< Peer Address. */ + uint8_t priAdvChanMap; /*!< Primary Advertising Channel Map. */ + uint8_t ownAddrType; /*!< Own Address Type. */ + uint8_t peerAddrType; /*!< Peer Address Type. */ + uint8_t advFiltPolicy; /*!< Advertising Filter Policy. */ + int8_t advTxPwr; /*!< Advertising Tx Power. */ + uint8_t priAdvPhy; /*!< Primary Advertising PHY. */ + uint8_t secAdvMaxSkip; /*!< Secondary Advertising Maximum Skip. */ + uint8_t secAdvPhy; /*!< Secondary Advertising PHY. */ + uint8_t advSID; /*!< Advertising SID. */ + uint8_t scanReqNotifEna; /*!< Scan Request Notification Enable. */ +} lctrExtAdvParam_t; + +/*! \brief Periodic advertising parameters. */ +typedef struct +{ + uint8_t perState; /*!< Current periodic adv state. */ + bool_t perAdvEnabled; /*!< Periodic advertising enabled or not. */ + uint32_t perAccessAddr; /*!< Periodic advertising access address. */ + uint16_t perEventCounter; /*!< Periodic event counter. */ + bool_t perAuxStart; /*!< True if need to start aux BOD due to periodic adv. */ + + BbOpDesc_t perAdvBod; /*!< Periodic advertising BOD. */ + BbBleData_t perBleData; /*!< Periodic advertising BLE data. */ + uint32_t perOffsUsec; /*!< Offset in microseconds to the next periodic PDU. */ + uint8_t perChHopInc; /*!< Periodic channel hop increment value. */ + uint8_t perChIdx; /*!< Periodic LL Channel. */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + uint32_t perAdvInter; /*!< Periodic advertising interval in BB ticks. */ + + uint32_t advInterMin; /*!< Periodic Advertising Interval Minimum in BB ticks. */ + uint32_t advInterMax; /*!< Periodic Advertising Interval Maximum in BB ticks. */ + uint16_t advEventProp; /*!< Periodic Advertising Event Properties. */ + bool_t advParamReady; /*!< Periodic Advertising Parameter is ready or not. */ + + /* Channel parameters */ + lctrChanParam_t perChanParam; /*!< Periodic Advertising Channel parameter. */ +} lctrPerAdvParam_t; + +/*! \brief Advertising data buffer descriptor. */ +typedef struct +{ + uint16_t did; /*!< Advertising Data ID. */ + uint16_t len; /*!< Advertising data length. */ + uint8_t *pBuf; /*!< Advertising data buffer. */ + bool_t ready; /*!< Advertising data buffer complete. */ + uint16_t txOffs; /*!< Tx buffer offset. */ + uint8_t fragPref; /*!< Host fragmentation preference. */ + + union + { + struct + { + bool_t modified; /*!< Content modified by host. */ + uint8_t len; /*!< Advertising data buffer length. */ + uint16_t did; /*!< Advertising Data ID. */ + uint8_t buf[LCTR_COMP_EXT_ADV_DATA_MAX_LEN]; + /*!< Advertising data buffer. */ + uint8_t fragPref; /*!< Host fragmentation preference. */ + } ext; /*!< Extended advertising data buffer cache (temporary storage during active advertising). */ + + struct + { + bool_t modified; /*!< Content modified by host. */ + uint8_t len; /*!< Advertising data buffer length. */ + uint8_t buf[LL_ADVBU_MAX_LEN]; + /*!< Advertising data buffer. */ + } legacy; /*!< Legacy advertising data buffer. */ + } alt; /*!< Alternate data storage. */ +} lctrAdvDataBuf_t; + +/*! \brief Advertising set. */ +typedef struct +{ + bool_t enabled; /*!< Enable flag. */ + uint8_t handle; /*!< Advertising handle. */ + + uint8_t state; /*!< Current state. */ + + /* Host parameters */ + bool_t bdAddrRndMod; /*!< Modified random address. */ + bool_t bdAddrRndValid; /*!< Random device address valid. */ + uint64_t bdAddrRnd; /*!< Random device address. */ + uint64_t advA; /*!< Advertiser address. */ + uint64_t tgtA; /*!< Target address. */ + lctrExtAdvParam_t param; /*!< Extended advertising parameters. */ + uint32_t auxDelayUsec; /*!< Auxiliary advertising event delay. */ + uint8_t advDataFragLen; /*!< Advertising data fragmentation length. */ + + /* Periodic advertising parameters */ + lctrPerAdvParam_t perParam; /*!< Periodic advertising parameters. */ + + /* Enable parameters */ + wsfTimer_t tmrAdvDur; /*!< Advertising duration timer. */ + uint8_t maxEvents; /*!< Maximum number of AE. */ + + /* Advertising task context */ + uint8_t numEvents; /*!< Number of completed AE. */ + uint8_t termReason; /*!< Termination reason. */ + uint8_t extHdrFlags; /*!< Extended header flags. */ + uint8_t *pExtAdvAuxPtr; /*!< Extended advertising PDU buffer location of AuxPtr field. */ + uint8_t auxChHopInc; /*!< Auxiliary channel hop increment value. */ + uint32_t auxSkipInter; /*!< Total skip time in BB ticks. */ + + /* Buffers */ + uint8_t advHdrBuf[LCTR_EXT_ADVB_LEN(LL_EXT_ADV_HDR_MAX_LEN, 0)]; + /*!< Primary channel legacy advertising and extended advertising header buffer. */ + uint8_t scanRspHdrBuf[LL_ADVB_MAX_LEN]; + /*!< Primary channel legacy scan response buffer. */ + uint8_t auxAdvHdrBuf[LCTR_EXT_ADVB_LEN(LL_EXT_ADV_HDR_MAX_LEN, 0)]; + /*!< Auxiliary extended advertising header buffer. */ + uint8_t auxRspHdrBuf[LCTR_EXT_ADVB_LEN(LL_EXT_ADV_HDR_MAX_LEN, 0)]; + /*!< Auxiliary scan or connect response header buffer. */ + uint8_t perAdvHdrBuf[LCTR_EXT_ADVB_LEN(LL_EXT_ADV_HDR_MAX_LEN, 0)]; + /*!< Periodic advertising header buffer. */ + lctrAdvDataBuf_t advData; /*!< Advertising data buffer. */ + lctrAdvDataBuf_t scanRspData; /*!< Scan response data buffer. */ + lctrAdvDataBuf_t perAdvData; /*!< Periodic advertising data buffer. */ + + /* Connection context. */ + bool_t isAuxConnReq; /*!< True if AUX_CONN_REQ is received, False if CONN_IND is received. */ + uint32_t connIndEndTs; /*!< Connection indication end timestamp. */ + bool_t connIndRcvd; /*!< Connection request received flag. */ + uint8_t usedChSel; /*!< Used channel selection. */ + + /* BB/ISR context */ + bool_t shutdown; /*!< Client initiated shutdown flag. */ + uint8_t bodTermCnt; /*!< Number of BOD terminated. */ + BbOpDesc_t advBod; /*!< Advertising BOD. */ + BbBleData_t bleData; /*!< BLE data. */ + BbOpDesc_t auxAdvBod; /*!< Auxiliary advertising BOD. */ + BbBleData_t auxBleData; /*!< Auxiliary BLE data. */ + uint32_t auxOffsUsec; /*!< Offset in microseconds to the next auxiliary PDU. */ + uint8_t auxChIdx; /*!< AUX LL Channel. */ + bool_t auxBodUsed; /*!< Auxiliary BOD in use flag. */ + lctrAdvbPduHdr_t rspPduHdr; /*!< Response PDU header. */ +} lctrAdvSet_t; + +/*! \brief Slave extended advertising state context. */ +typedef struct +{ + wsfQueue_t rxScanReqQ; /*!< Received SCAN_REQ queue. */ +} lctrSlvExtAdvCtx_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrAdvSet_t *pLctrAdvSetTbl; +extern LctrExtAdvMsg_t *pLctrSlvExtAdvMsg; +extern lctrSlvExtAdvCtx_t lctrSlvExtAdv; +extern LctrPerAdvMsg_t *pLctrSlvPerAdvMsg; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Context */ +void lctrFreeAdvSet(lctrAdvSet_t *pAdvSet); + +/* Address selection */ +void lctrChooseSetAdvA(lctrAdvbPduHdr_t *pPduHdr, BbBleData_t * const pBle, lctrAdvSet_t *pAdvSet); +void lctrChooseSetPeerA(lctrAdvbPduHdr_t *pPduHdr, BbBleData_t * const pBle, lctrAdvSet_t *pAdvSet); + +/* Builder */ +uint8_t lctrSlvExtAdvBuildOp(lctrAdvSet_t *pAdvSet, uint32_t maxStartMs); +void lctrSlvAuxNonConnNonScanBuildOp(lctrAdvSet_t *pAdvSet); +void lctrSlvAuxScanBuildOp(lctrAdvSet_t *pAdvSet); +void lctrSlvAuxConnBuildOp(lctrAdvSet_t *pAdvSet); +void lctrSlvAuxRescheduleOp(lctrAdvSet_t *pAdvSet, BbOpDesc_t * const pOp); +uint8_t lctrSlvPeriodicAdvBuildOp(lctrAdvSet_t *pAdvSet); + +/* Channel */ +void lctrSelectNextAuxChannel(lctrAdvSet_t *pAdvSet); +void lctrSelectNextPerChannel(lctrAdvSet_t *pAdvSet); + +/* ISR: Packet handlers */ +void lctrSlvTxSetupExtAdvHandler(BbOpDesc_t *pOp, uint32_t txTime); +uint32_t lctrSlvTxSetupAuxAdvDataHandler(BbOpDesc_t *pOp, bool_t isChainInd); +uint32_t lctrSlvTxSetupAuxScanRspDataHandler(BbOpDesc_t *pOp, bool_t isChainInd); +bool_t lctrSlvRxAuxScanReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +void lctrSlvRxAuxScanReqPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +void lctrSlvRxLegacyScanReqPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +bool_t lctrSlvRxAuxConnReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +bool_t lctrSlvRxLegacyReqHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +void lctrSlvRxLegacyReqPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pReqBuf); +uint32_t lctrSlvTxSetupPeriodicAdvDataHandler(BbOpDesc_t *pOp, bool_t isChainInd); + +/* ISR: BOD handlers */ +void lctrSlvExtAdvEndOp(BbOpDesc_t *pOp); +void lctrSlvAuxAdvEndOp(BbOpDesc_t *pOp); +void lctrSlvPeriodicAdvEndOp(BbOpDesc_t *pOp); + +/* Action routines */ +void lctrExtAdvActStart(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActRestart(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActShutdown(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActAdvCnf(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActDisallowAdvCnf(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActSelfTerm(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActAdvTerm(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActReset(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActResetTerm(lctrAdvSet_t *pAdvSet); +void lctrExtAdvActDurationExpired(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActStart(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActUpdate(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActDisallowAdvCnf(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActShutdown(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActResetTerm(lctrAdvSet_t *pAdvSet); +void lctrPeriodicAdvActAdvTerm(lctrAdvSet_t *pAdvSet); + +/* Reservation */ +void lctrGetPerAdvOffsets(uint32_t rsvnOffs[], uint32_t refTime); + +/* State machine */ +void lctrSlvExtAdvExecuteSm(lctrAdvSet_t *pAdvSet, uint8_t event); +void lctrSlvPeriodicAdvExecuteSm(lctrAdvSet_t *pAdvSet, uint8_t event); + +/* Messaging */ +void lctrSendAdvSetMsg(lctrAdvSet_t *pAdvSet, uint8_t event); +void lctrSendPeriodicAdvSetMsg(lctrAdvSet_t *pAdvSet, uint8_t event); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ADV_SLAVE_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn.h new file mode 100644 index 0000000000..18ae42ffef --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn.h @@ -0,0 +1,869 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_CONN_H +#define LCTR_INT_CONN_H + +#include "lctr_int.h" +#include "lctr_api_conn.h" +#include "lctr_pdu_conn.h" +#include "lctr_pdu_adv.h" +#include "lmgr_api_conn.h" +#include "ll_defs.h" +#include "sch_api.h" +#include "bb_ble_api.h" +#include "bb_ble_api_op.h" +#include "wsf_cs.h" +#include "wsf_msg.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +#define LCTR_MAX_CONS_CRC 2 /*!< Maximum number of consecutive CRC failures. */ + +#ifndef LCTR_DATA_PDU_START_OFFSET +#define LCTR_DATA_PDU_START_OFFSET 2 /*!< Data PDU start offset in a buffer (match ACL header size). */ +#endif + +#define LCTR_DATA_PDU_FC_OFFSET 0 /*!< Flow control fields data PDU offset. */ +#define LCTR_DATA_PDU_LEN_OFFSET 1 /*!< Length field data PDU offset. */ + +#define LCTR_MAX_INSTANT 32767 /*!< Maximum instant value for connection update. */ + +#define LCTR_CTRL_DATA_HANDLE 0xFF /*!< Connection handle used for LL control PDUs. */ + +#define LCTR_LE_PING_ATTEMPTS 4 /*!< LE Ping attempts. */ + +#define LCTR_CH_SEL_MAX 2 /*!< Total number of channel selection algorithms. */ + +/*! \brief Resolve the connection handle from the context pointer. */ +#define LCTR_GET_CONN_HANDLE(pCtx) (pCtx - pLctrConnTbl) + +/*! \brief Resolve connection context from the handle. */ +#define LCTR_GET_CONN_CTX(h) &(pLctrConnTbl[h]) + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Connected states. */ +enum +{ + LCTR_CONN_STATE_INITIALIZED, /*!< Connection initialized. */ + LCTR_CONN_STATE_ESTABLISHED_STARTUP, /*!< Connection established before ready to start LLCP. */ + LCTR_CONN_STATE_ESTABLISHED_READY, /*!< Connection established and ready to start LLCP. */ + LCTR_CONN_STATE_TERMINATING /*!< Connection terminating. */ +}; + +/*! \brief LLCP states. */ +enum +{ + LCTR_LLCP_STATE_IDLE, /*!< LLCP idle state. */ + LCTR_LLCP_STATE_BUSY, /*!< LLCP busy state. */ + LCTR_LLCP_STATE_TOTAL /*!< Total number of LLCP states. */ +}; + +/*! \brief Common LLCP states. */ +enum +{ + LCTR_CMN_STATE_IDLE, /*!< LLCP idle state. */ + LCTR_CMN_STATE_BUSY, /*!< LLCP busy state. */ + LCTR_CMN_STATE_TOTAL /*!< Total number of LLCP states. */ +}; + +/*! \brief Common LLCP procedure IDs. */ +enum +{ + /* Common SM LLCP procedures. */ + LCTR_PROC_CMN_TERM, /*!< Termination procedure. */ + LCTR_PROC_CMN_CH_MAP_UPD, /*!< Channel map update procedure. */ + LCTR_PROC_CMN_FEAT_EXCH, /*!< Feature exchange procedure. */ + LCTR_PROC_CMN_VER_EXCH, /*!< Version exchange procedure. */ + LCTR_PROC_CMN_DATA_LEN_UPD, /*!< Data length update procedure. */ + LCTR_PROC_CMN_SET_MIN_USED_CHAN, /*!< Set minimum number of used channels procedure. */ + LCTR_PROC_CMN_TOTAL, /*!< Total number of common procedures. */ + + /* Custom SM LLCP procedures. */ + LCTR_PROC_CONN_UPD, /*!< Connection update procedure. */ + LCTR_PROC_CONN_PARAM, /*!< Connection parameter procedure. */ + LCTR_PROC_ENCRYPT, /*!< Encryption Start or Restart procedure. */ + LCTR_PROC_LE_PING, /*!< LE Ping procedure. */ + LCTR_PROC_PHY_UPD, /*!< PHY update procedure. */ + LCTR_PROC_PHY_UPD_PEER, /*!< Peer-initiated PHY update procedure. */ + + LCTR_PROC_INVALID = 0xFF /*!< Invalid ID. */ + + /* Note: additional procedures without instants can be overridden. */ +}; + +/*! \brief Connection context. */ +typedef struct +{ + bool_t enabled; /*!< Context enabled. */ + uint8_t state; /*!< Current state. */ + uint8_t role; /*!< Connection role. */ + uint32_t opModeFlags; /*!< Operational mode flags. */ + + /* Host/API */ + uint8_t termReason; /*!< Termination reason code. */ + uint8_t replyWaitingMsk; /*!< Host reply waiting mask. */ + + /* BB data */ + BbOpDesc_t connBod; /*!< Connection BOD. */ + BbBleData_t bleData; /*!< BLE BB operation data. */ + + union + { + struct + { + uint16_t totalAcc; /*!< Combined sleep clock inaccuracy. */ + uint16_t lastActiveEvent; /*!< Last active event counter. */ + uint32_t txWinSizeUsec; /*!< Tx window size. */ + uint32_t anchorPoint; /*!< Anchor point. */ + uint32_t unsyncedTime; /*!< Unsynced time in BB tick before connection update. */ + bool_t initAckRcvd; /*!< Ack received from master. */ + bool_t abortSlvLatency; /*!< If TRUE abort slave latency. */ + } slv; /*!< Slave connection specific data. */ + + struct + { + bool_t sendConnUpdInd; /*!< Send LL_CONNECTION_UPDATE_IND flag. */ + } mst; /*!< Master connection specific data. */ + } data; /*!< Role specific data. */ + + /* Connection event parameters */ + uint16_t maxLatency; /*!< Maximum latency. */ + uint16_t eventCounter; /*!< Connection event counter. */ + uint16_t connInterval; /*!< Connection interval. */ + + /* RF parameters */ + int8_t rssi; /*!< RSSI. */ + + /* Channel parameters */ + uint8_t lastChanIdx; /*!< Current channel index. */ + uint8_t hopInc; /*!< Hop increment. */ + uint8_t numUsedChan; /*!< Number of used channels. */ + uint64_t chanMask; /*!< Channel mask. */ + uint8_t chanRemapTbl[LL_CHAN_DATA_MAX_IDX + 1]; + /*!< Channel remapping table. */ + uint8_t usedChSel; /*!< Used channel selection. */ + uint16_t chIdentifier; /*!< Channel identifier. */ + + /* Flow control */ + lctrDataPduHdr_t txHdr; /*!< Transmit data PDU header. */ + lctrDataPduHdr_t rxHdr; /*!< Receive data PDU header. */ + wsfQueue_t txLeuQ; /*!< Transmit LE-U queue. */ + wsfQueue_t txArqQ; /*!< Transmit ARQ queue. */ + wsfQueue_t rxDataQ; /*!< Receive data pending queue. */ + uint8_t numTxComp; /*!< Number of completed Tx buffers. */ + uint8_t numRxPend; /*!< Number of Rx pending buffers. */ + bool_t emptyPduPend; /*!< Empty PDU ACK pending. */ + bool_t emptyPduFirstAtt; /*!< Empty PDU first attempt. */ + + /* Supervision */ + uint16_t supTimeoutMs; /*!< Supervision timeout in milliseconds. */ + wsfTimer_t tmrSupTimeout; /*!< Supervision timer. */ + bool_t connEst; /*!< Connection established. */ + + /* Encryption */ + bool_t pauseRxData; /*!< Pause Rx data PDUs. */ + bool_t pauseTxData; /*!< Pause Tx data PDUs. */ + uint8_t ltk[LL_KEY_LEN]; /*!< Long term key. */ + uint8_t skd[LL_SKD_LEN]; /*!< Session key diversifier. */ + uint8_t iv[LL_IV_LEN]; /*!< Initialization vector. */ + uint8_t rand[LL_RAND_LEN]; /*!< Random number. */ + uint16_t ediv; /*!< Encrypted diversifier. */ + + uint64_t txPktCounter; /*!< Transmit packet counter. */ + uint64_t rxPktCounter; /*!< Transmit packet counter. */ + + /* Authentication */ + uint32_t pingPeriodMs; /*!< Ping period in milliseconds. */ + wsfTimer_t tmrPingTimeout; /*!< Ping timer. */ + uint32_t authTimeoutMs; /*!< Authentication payload timeout in milliseconds. */ + wsfTimer_t tmrAuthTimeout; /*!< Authentication payload timer. */ + + LlEncMode_t newEncMode; /*!< Pending encryption mode. */ + bool_t pendEncMode; /*!< New encryption mode pending. */ + + bool_t keyUpdFlag; /*!< Flag for key update. */ + + /* Peer device info */ + uint8_t numSentVerInd; /*!< Number of sent LL_VERSION_IND. */ + bool_t remoteVerValid; /*!< Peer version data valid. */ + lctrVerInd_t remoteVer; /*!< Peer version data. */ + bool_t featExchFlag; /*!< Flag for completed feature exchange. */ + uint64_t usedFeatSet; /*!< Used feature set. */ + + /* Data length */ + lctrDataLen_t localDataPdu; /*!< Local Data PDU parameters. */ + lctrDataLen_t effDataPdu; /*!< Effective Data PDU parameters. */ + uint16_t localConnDurUsec; /*!< Local connection event duration. */ + uint16_t effConnDurUsec; /*!< Effective connection event duration. */ + + /* PHY */ + uint8_t allPhys; /*!< Default all PHYs. */ + uint8_t txPhys; /*!< Default transmitter PHYs. */ + uint8_t rxPhys; /*!< Default receiver PHYs. */ + uint8_t txPhysPending; /*!< Pending transmitter PHYs. */ + + /* Peer minimum number of used channels */ + uint8_t peerMinUsedChan[LL_MAX_PHYS]; + /*!< Peer minimum number of used channels for PHYs. */ + + /* LLCP */ + uint8_t llcpState; /*!< Current LLCP state. */ + uint8_t encState; /*!< Current encryption state. */ + uint8_t pingState; /*!< Current ping state. */ + uint8_t connUpdState; /*!< Connection update state. */ + uint8_t phyUpdState; /*!< PHY update state. */ + uint8_t cmnState; /*!< Common LLCP state. */ + bool_t peerReplyWaiting; /*!< Peer waiting for reply. */ + bool_t llcpInstantComp; /*!< Procedure instant completed. */ + bool_t termAckReqd; /*!< Ack required for Rx'ed LL_TERMINATE_IND. */ + bool_t ackAfterCtrlPdu; /*!< Ack Tx'ed after last Control PDU Rx'ed. */ + bool_t llcpIsOverridden; /*!< Is the current procedure overridden by other procedure. */ + bool_t isSlvReadySent; /*!< True if slave ready to initiate startup LLCP procedure is sent. */ + bool_t isFirstNonCtrlPdu; /*!< True if first non-control PDU from master and slave. */ + bool_t isSlvPhyUpdInstant; /*!< True if slave is in PHY update instant state. */ + uint8_t llcpActiveProc; /*!< Current procedure. */ + uint16_t llcpNotifyMask; /*!< Host notification mask. */ + uint16_t llcpPendMask; /*!< Pending LLCP procedures. */ + uint16_t llcpIncompMask; /*!< Incomplete LLCP procedures. */ + LlConnSpec_t connUpdSpec; /*!< Host connection update specification. */ + lctrConnUpdInd_t connUpd; /*!< Connection update parameters. */ + lctrConnParam_t connParam; /*!< Stored peer connection parameter request or response. */ + lctrChanMapInd_t chanMapUpd; /*!< Channel map parameters. */ + lctrPhy_t phyReq; /*!< Stored peer PHY request. */ + lctrPhyUpdInd_t phyUpd; /*!< PHY update parameters. */ + wsfTimer_t tmrProcRsp; /*!< Procedure response timer. */ +} lctrConnCtx_t; + +/*! \brief Call signature of a cipher block handler. */ +typedef void (*lctrCipherBlkHdlr_t)(BbBleEnc_t *pEnc, uint8_t id, uint8_t dir); + +/*! \brief Call signature of a packet encryption handler. */ +typedef bool_t (*lctrPktEncHdlr_t)(BbBleEnc_t *pEnc, uint8_t *pHdr, uint8_t *pBuf, uint8_t *pMic); + +/*! \brief Call signature of a packet decryption handler. */ +typedef bool_t (*lctrPktDecHdlr_t)(BbBleEnc_t *pEnc, uint8_t *pBuf); + +/*! \brief Call signature of a set packet count handler. */ +typedef void (*lctrPktCntHdlr_t)(BbBleEnc_t *pEnc, uint64_t pktCnt); + +/*! \brief Call signature of a LLCP state machine handler. */ +typedef bool_t (*LctrLlcpHdlr_t)(lctrConnCtx_t *pCtx, uint8_t event); + +/*! \brief Call signature of a control PDU handler. */ +typedef void (*lctrCtrlPduHdlr_t)(lctrConnCtx_t *pCtx, uint8_t *pBuf); + +/*! \brief Call signature of a Channel state machine handler. */ +typedef uint8_t (*LctrChSelHdlr_t)(lctrConnCtx_t *pCtx, uint16_t numSkip); + +/*! \brief LLCP state machine handlers. */ +enum +{ + LCTR_LLCP_SM_ENCRYPT, /*!< Encryption LLCP state machine. */ + LCTR_LLCP_SM_PING, /*!< Ping state machine. */ + LCTR_LLCP_SM_CONN_UPD, /*!< Connection update state machine. */ + LCTR_LLCP_SM_PHY_UPD, /*!< PHY update state machine. */ + LCTR_LLCP_SM_CMN, /*!< Common LLCP state machine. */ + LCTR_LLCP_SM_TOTAL /*!< Total number of LLCP state machine. */ +}; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern lctrCipherBlkHdlr_t lctrInitCipherBlkHdlr; +extern lctrPktEncHdlr_t lctrPktEncryptHdlr; +extern lctrPktDecHdlr_t lctrPktDecryptHdlr; +extern lctrPktCntHdlr_t lctrSetEncryptPktCountHdlr; +extern lctrPktCntHdlr_t lctrSetDecryptPktCountHdlr; +extern lctrConnCtx_t *pLctrConnTbl; +extern lctrDataPdu_t lctrDataPdu; +extern lctrConnMsg_t *pLctrConnMsg; +extern const LctrVsHandlers_t *pLctrVsHdlrs; +extern lctrCtrlPduHdlr_t lctrCtrlPduHdlr; +extern LctrChSelHdlr_t lctrChSelHdlr[LCTR_CH_SEL_MAX]; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +void lctrConnDefaults(void); + +/* Builder */ +lctrConnCtx_t *lctrAllocConnCtx(void); +void lctrFreeConnCtx(lctrConnCtx_t *pCtx); +uint8_t lctrSelectNextDataChannel(lctrConnCtx_t *pCtx, uint16_t numSkip); +uint8_t lctrSelectNextChannel2(lctrConnCtx_t *pCtx, uint16_t numSkip); +void lctrBuildRemapTable(lctrConnCtx_t *pCtx); + +/* Task event handler */ +void lctrConnTxCompletedHandler(void); +void lctrConnRxPendingHandler(void); + +/* Connection update actions */ +void lctrStoreConnUpdateSpec(lctrConnCtx_t *pCtx); +void lctrSendConnUpdateInd(lctrConnCtx_t *pCtx); +void lctrStoreConnUpdate(lctrConnCtx_t *pCtx); +void lctrNotifyHostConnUpdateInd(lctrConnCtx_t *pCtx, uint8_t status); +void lctrActNotifyHostConnUpdSuccess(lctrConnCtx_t *pCtx); +void lctrActHostNegReply(lctrConnCtx_t *pCtx); +void lctrActPeerRejectConnParam(lctrConnCtx_t *pCtx); + +/* Channel map actions */ +void lctrStoreChanMapUpdate(lctrConnCtx_t *pCtx); +void lctrSendChanMapUpdateInd(lctrConnCtx_t *pCtx); +void lctrStoreChanMap(lctrConnCtx_t *pCtx); + +/* Feature exchange actions */ +void lctrSendFeatureReq(lctrConnCtx_t *pCtx); +void lctrSendFeatureRsp(lctrConnCtx_t *pCtx); +void lctrStoreUsedFeatures(lctrConnCtx_t *pCtx); + +/* Version exchange actions */ +void lctrSendVersionInd(lctrConnCtx_t *pCtx); +void lctrStoreRemoteVer(lctrConnCtx_t *pCtx); +void lctrNotifyHostReadRemoteVerCnf(lctrConnCtx_t *pCtx); + +/* Terminate actions */ +void lctrSendTerminateInd(lctrConnCtx_t *pCtx); +void lctrNotifyHostDisconnectInd(lctrConnCtx_t *pCtx); +void lctrStoreTerminateReason(lctrConnCtx_t *pCtx); +void lctrStoreDisconnectReason(lctrConnCtx_t *pCtx); +void lctrStoreConnFailEstablishTerminateReason(lctrConnCtx_t *pCtx); +void lctrStoreLlcpTimeoutTerminateReason(lctrConnCtx_t *pCtx); +void lctrStoreResetTerminateReason(lctrConnCtx_t *pCtx); +void lctrStoreInstantPassedTerminateReason(lctrConnCtx_t *pCtx); +void lctrStoreMicFailedTerminateReason(lctrConnCtx_t *pCtx); + +/* Connection parameter actions */ +void lctrStoreConnParamReq(lctrConnCtx_t *pCtx); +void lctrStoreConnParamRsp(lctrConnCtx_t *pCtx); +void lctrStoreConnParamSpec(lctrConnCtx_t *pCtx); +void lctrSendConnParamReq(lctrConnCtx_t *pCtx); +void lctrSendConnParamRsp(lctrConnCtx_t *pCtx); +void lctrNotifyHostConnParamInd(lctrConnCtx_t *pCtx); + +/* Data length exchange actions */ +void lctrStoreLocalDataLength(lctrConnCtx_t *pCtx); +void lctrSendDataLengthReq(lctrConnCtx_t *pCtx); +void lctrSendDataLengthRsp(lctrConnCtx_t *pCtx); +void lctrStoreRemoteDataLength(lctrConnCtx_t *pCtx); +void lctrNotifyHostDataLengthInd(lctrConnCtx_t *pCtx, uint8_t status); + +/* Set minimum number of used channels actions */ +void lctrSendSetMinUsedChanInd(lctrConnCtx_t *pCtx); +void lctrStoreSetMinUsedChan(lctrConnCtx_t *pCtx); + +/* Unknown/Unsupported */ +void lctrSendUnknownRsp(lctrConnCtx_t *pCtx); +void lctrSendRejectInd(lctrConnCtx_t *pCtx, uint8_t reason, bool_t forceRejectExtInd); + +/* Tx data path */ +uint16_t lctrTxFragLen(lctrConnCtx_t *pTx); +uint16_t lctrTxInitMem(uint8_t *pFreeMem, uint32_t freeMemSize); +uint8_t *lctrTxCtrlPduAlloc(uint8_t pduLen); +void lctrTxDataPduQueue(lctrConnCtx_t *pCtx, uint16_t fragLen, lctrAclHdr_t *pAclHdr, uint8_t *pAclBuf); +void lctrTxCtrlPduQueue(lctrConnCtx_t *pCtx, uint8_t *pBuf); +uint8_t lctrTxQueuePeek(lctrConnCtx_t *pCtx, BbBleDrvTxBufDesc_t *bbDescs, bool_t *pMd); +bool_t lctrTxQueuePop(lctrConnCtx_t *pCtx); +void lctrTxQueuePopCleanup(lctrConnCtx_t *pCtx); +uint8_t lctrTxQueueClear(lctrConnCtx_t *pCtx); + +/* Rx data path */ +uint8_t *lctrRxPduAlloc(uint16_t maxRxLen); +void lctrRxPduFree(uint8_t *pBuf); +void lctrRxEnq(uint8_t *pBuf, uint16_t eventCounter, uint16_t connHandle); +uint8_t *lctrRxDeq(uint16_t *pConnHandle); +void lctrRxConnEnq(lctrConnCtx_t *pCtx, uint8_t *pBuf); +uint8_t *lctrRxConnDeqAcl(lctrConnCtx_t *pCtx); +uint8_t lctrRxConnClear(lctrConnCtx_t *pCtx); + +/* LLCP */ +void lctrStartLlcpTimer(lctrConnCtx_t *pCtx); +void lctrStopLlcpTimer(lctrConnCtx_t *pCtx); +void lctrStartPendingLlcp(lctrConnCtx_t *pCtx); + +/* Data path pause */ +void lctrPauseTxData(lctrConnCtx_t *pCtx); +void lctrUnpauseTxData(lctrConnCtx_t *pCtx); +void lctrCheckPauseComplete(lctrConnCtx_t *pCtx); +void lctrPauseRxData(lctrConnCtx_t *pCtx); +void lctrUnpauseRxData(lctrConnCtx_t *pCtx); + +/* Packet times */ +void lctrSetPacketTimeRestriction(lctrConnCtx_t *pCtx, uint8_t txPhys); +void lctrRemovePacketTimeRestriction(lctrConnCtx_t *pCtx); +uint16_t lctrCalcConnDurationUsec(lctrConnCtx_t *pCtx, const lctrDataLen_t *pDataLen); + +/* Scheduler */ +BbOpDesc_t *lctrConnResolveConflict(BbOpDesc_t *pNewOp, BbOpDesc_t *pExistOp); + +/* ISR */ +uint8_t *lctrProcessRxAck(lctrConnCtx_t *pCtx); +void lctrTxPduAck(lctrConnCtx_t *pCtx); +bool_t lctrProcessTxAck(lctrConnCtx_t *pCtx); +void lctrProcessTxAckCleanup(lctrConnCtx_t *pCtx); +uint16_t lctrSetupForTx(lctrConnCtx_t *pCtx, uint8_t rxStatus, bool_t reqTx); +void lctrRxPostProcessing(lctrConnCtx_t *pCtx, uint8_t *pRxBuf, uint8_t *pNextRxBuf, bool_t loadRxBuf); + +/* Helper */ +void lctrSendConnMsg(lctrConnCtx_t *pCtx, uint8_t event); +bool_t lctrExceededMaxDur(lctrConnCtx_t *pCtx, uint32_t ceStart, uint32_t pendDurUsec); +uint32_t lctrCalcPingPeriodMs(lctrConnCtx_t *pCtx, uint32_t authTimeoutMs); +uint8_t lctrComputeSca(void); + +/* Reservation */ +void lctrGetConnOffsets(uint32_t rsvnOffs[], uint32_t refTime); + +/*************************************************************************************************/ +/*! + * \brief Check for a queue depth of 1 element. + * + * \param pArqQ Queue. + * + * \return TRUE if ARQ only has 1 element, FALSE otherwise. + * + * \note Checks without resource protection. This routine is only intended to be used in task + * context. + */ +/*************************************************************************************************/ +static inline bool_t lctrIsQueueDepthOne(wsfQueue_t *pArqQ) +{ + return pArqQ->pHead == pArqQ->pTail; +} + +/*************************************************************************************************/ +/*! + * \brief Set flags for link termination. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrFlagLinkTerm(lctrConnCtx_t *pCtx) +{ + bool_t removeBod = (pCtx->state == LCTR_CONN_STATE_ESTABLISHED_READY); + + pCtx->state = LCTR_CONN_STATE_TERMINATING; /* signals ISR to terminate link */ + pCtx->llcpState = LCTR_LLCP_STATE_IDLE; /* signals ISR do not wait to send TERMINATE_IND */ + + if (removeBod) + { + SchRemove(&pCtx->connBod); + } +} + +/*************************************************************************************************/ +/*! + * \brief Service the Control PDU ACK state after a successful reception. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrCheckControlPduAck(lctrConnCtx_t *pCtx) +{ + if (pCtx->rxHdr.llid == LL_LLID_CTRL_PDU) + { + /* Control PDU received; reset Tx ACK pending state. */ + pCtx->ackAfterCtrlPdu = FALSE; + } +} + +/*************************************************************************************************/ +/*! + * \brief Service the Control PDU ACK state after a successful transmission. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrSetControlPduAck(lctrConnCtx_t *pCtx) +{ + /* Unconditionally set state upon Tx completion. */ + pCtx->ackAfterCtrlPdu = TRUE; +} + +/*************************************************************************************************/ +/*! + * \brief Set flags for link termination. + * + * \param pCtx Connection context. + * + * \return TRUE if connection is terminated, FALSE otherwise. + */ +/*************************************************************************************************/ +static inline bool_t lctrCheckForLinkTerm(lctrConnCtx_t *pCtx) +{ + if (pCtx->state == LCTR_CONN_STATE_TERMINATING) + { + /* Peer device is LL_TERMINATE_IND initiator. */ + if (pCtx->termAckReqd) /* Tx Ack required after Rx of LL_TERMINATE_IND */ + { + if (pCtx->ackAfterCtrlPdu) /* guarantee Ack Tx'ed */ + { + return TRUE; + } + } + /* Local device is LL_TERMINATE_IND initiator. */ + else if ((pCtx->llcpState == LCTR_LLCP_STATE_IDLE) || /* LL_TERMINATE_IND not pending */ + (pCtx->txArqQ.pHead == NULL)) /* guarantee LL_TERMINATE_IND is Ack'ed */ + /* i.e. "WsfQueueEmpty(&pCtx->txArqQ)" (optimized for ISR) */ + { + return TRUE; + } + } + + return FALSE; +} + +/*************************************************************************************************/ +/*! + * \brief Increment the Tx/encrypt packet counter. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrIncPacketCounterTx(lctrConnCtx_t *pCtx) +{ + if (lctrSetEncryptPktCountHdlr) + { + BbBleEnc_t * const pEnc = &pCtx->bleData.chan.enc; + + if ((pEnc->enaEncrypt) && + (pEnc->nonceMode == BB_NONCE_MODE_PKT_CNTR)) + { + pCtx->txPktCounter++; + } + } +} + +/*************************************************************************************************/ +/*! + * \brief Increment the Rx/decrypt packet counter. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrIncPacketCounterRx(lctrConnCtx_t *pCtx) +{ + if (lctrSetEncryptPktCountHdlr) + { + BbBleEnc_t * const pEnc = &pCtx->bleData.chan.enc; + + if ((pEnc->enaEncrypt) && + (pEnc->nonceMode == BB_NONCE_MODE_PKT_CNTR)) + { + pCtx->rxPktCounter++; + } + } +} + +/*************************************************************************************************/ +/*! + * \brief Set the transmit packet counter value in the BB. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrSetBbPacketCounterTx(lctrConnCtx_t *pCtx) +{ + if (lctrSetEncryptPktCountHdlr) + { + BbBleEnc_t * const pEnc = &pCtx->bleData.chan.enc; + + if (!pEnc->enaEncrypt) + { + return; + } + + switch (pEnc->nonceMode) + { + case BB_NONCE_MODE_PKT_CNTR: + lctrSetEncryptPktCountHdlr(pEnc, pCtx->txPktCounter); + break; + case BB_NONCE_MODE_EVT_CNTR: + lctrSetEncryptPktCountHdlr(pEnc, pCtx->eventCounter); + break; + default: + break; + } + } +} + +/*************************************************************************************************/ +/*! + * \brief Set the receive packet counter value in the BB. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrSetBbPacketCounterRx(lctrConnCtx_t *pCtx) +{ + if (lctrSetDecryptPktCountHdlr) + { + BbBleEnc_t * const pEnc = &pCtx->bleData.chan.enc; + + if (!pEnc->enaDecrypt) + { + return; + } + + switch (pEnc->nonceMode) + { + case BB_NONCE_MODE_PKT_CNTR: + lctrSetDecryptPktCountHdlr(pEnc, pCtx->rxPktCounter); + break; + case BB_NONCE_MODE_EVT_CNTR: + lctrSetDecryptPktCountHdlr(pEnc, pCtx->eventCounter); + break; + default: + break; + } + } +} + +/*************************************************************************************************/ +/*! + * \brief Check if procedure is active, if not pend the procedure. + * + * \param pCtx Connection context. + * \param proc Procedure ID to check/pend. + * + * \return TRUE if active procedure, FALSE if pended. + */ +/*************************************************************************************************/ +static inline bool_t lctrCheckActiveOrPend(lctrConnCtx_t *pCtx, uint8_t proc) +{ + if (pCtx->llcpActiveProc == proc) + { + return TRUE; + } + else + { + pCtx->llcpPendMask |= 1 << proc; + return FALSE; + } +} + +/*************************************************************************************************/ +/*! + * \brief Store connection timeout termination reason. + * + * \param pCtx Connection context. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrStoreConnTimeoutTerminateReason(lctrConnCtx_t *pCtx) +{ + if (pCtx->termReason == LL_ERROR_CODE_CONN_FAILED_TO_ESTABLISH) + { + pCtx->termReason = LL_ERROR_CODE_CONN_TIMEOUT; + } +} + +/*************************************************************************************************/ +/*! + * \brief Increment available Tx data buffers. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrDataTxIncAvailBuf(void) +{ + WSF_CS_INIT(); + + WSF_CS_ENTER(); + lmgrConnCb.availTxBuf++; + WSF_CS_EXIT(); +} + +/*************************************************************************************************/ +/*! + * \brief Decrement available Tx data buffers. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrDataTxDecAvailBuf(void) +{ + WSF_CS_INIT(); + + WSF_CS_ENTER(); + lmgrConnCb.availTxBuf--; + WSF_CS_EXIT(); +} + +/*************************************************************************************************/ +/*! + * \brief Increment available Rx data buffers. +* + * \param numBufs Number of completed packets. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrDataRxIncAvailBuf(uint8_t numBufs) +{ + WSF_CS_INIT(); + + WSF_CS_ENTER(); + lmgrConnCb.availRxBuf += numBufs; + WSF_CS_EXIT(); +} + +/*************************************************************************************************/ +/*! + * \brief Get connection operational mode flags. + * + * \param pCtx Connection context to get the flag. + * \param flag Flags. + * + * \return Status error code. + * + * Set mode flags governing LL operations of a given connection. + */ +/*************************************************************************************************/ +static inline bool_t lctrGetConnOpFlag(lctrConnCtx_t *pCtx, uint32_t flag) +{ + return (pCtx->opModeFlags & flag) ? TRUE : FALSE; +} + +/*************************************************************************************************/ +/*! + * \brief Convert PHYS bit to PHY. + * + * \param physBit PHYS bit. + * + * \return PHY. + */ +/*************************************************************************************************/ +static inline uint8_t lctrPhysBitToPhy(uint8_t physBit) +{ + switch (physBit) + { + default: + case LL_PHYS_LE_1M_BIT: + return BB_PHY_BLE_1M; + case LL_PHYS_LE_2M_BIT: + return BB_PHY_BLE_2M; + case LL_PHYS_LE_CODED_BIT: + return BB_PHY_BLE_CODED; + } +} + +/*************************************************************************************************/ +/*! + * \brief Convert PHY to PHYS bit. + * + * \param phy PHY. + * + * \return PHYS bit. + */ +/*************************************************************************************************/ +static inline uint8_t lctrPhyToPhysBit(uint8_t phy) +{ + switch (phy) + { + default: + case BB_PHY_BLE_1M: + return LL_PHYS_LE_1M_BIT; + case BB_PHY_BLE_2M: + return LL_PHYS_LE_2M_BIT; + case BB_PHY_BLE_CODED: + return LL_PHYS_LE_CODED_BIT; + } +} + +/*************************************************************************************************/ +/*! + * \brief Get LLCP procedure ID. + * + * \param event Event. + * + * \return LLCP procedure event ID. + */ +/*************************************************************************************************/ +static inline uint8_t lctrGetProcId(uint8_t event) +{ + switch (event) + { + case LCTR_CONN_MSG_API_CHAN_MAP_UPDATE: + return LCTR_PROC_CMN_CH_MAP_UPD; + + case LCTR_CONN_MSG_API_REMOTE_FEATURE: + return LCTR_PROC_CMN_FEAT_EXCH; + + case LCTR_CONN_MSG_API_SET_MIN_USED_CHAN: + return LCTR_PROC_CMN_SET_MIN_USED_CHAN; + + case LCTR_CONN_MSG_API_REMOTE_VERSION: + return LCTR_PROC_CMN_VER_EXCH; + + case LCTR_CONN_MSG_API_DISCONNECT: + return LCTR_PROC_CMN_TERM; + + case LCTR_CONN_MSG_API_DATA_LEN_CHANGE: + return LCTR_PROC_CMN_DATA_LEN_UPD; + + case LCTR_CONN_MSG_API_CONN_UPDATE: + return LCTR_PROC_CONN_UPD; + + case LCTR_CONN_MSG_API_PHY_UPDATE: + return LCTR_PROC_PHY_UPD; + + case LCTR_CONN_MSG_API_START_ENC: + return LCTR_PROC_ENCRYPT; + + default: + return LCTR_PROC_INVALID; + } +} + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_CONN_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_master.h new file mode 100644 index 0000000000..d3ea7ce6fc --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_master.h @@ -0,0 +1,83 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller master connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_CONN_MASTER_H +#define LCTR_INT_CONN_MASTER_H + +#include "lctr_int.h" +#include "lctr_int_conn.h" +#include "lctr_api_conn.h" +#include "lctr_pdu_conn.h" +#include "ll_defs.h" +#include "bb_ble_api.h" +#include "wsf_msg.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Buffer offset of txWinOffset in a CONN_IND PDU. */ +#define LCTR_CONN_IND_TX_WIN_OFFSET (LL_DATA_HDR_LEN + 6 + 6 + 8) + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern LctrLlcpHdlr_t lctrMstLlcpSmTbl[LCTR_LLCP_SM_TOTAL]; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +void lctrMstConnExecuteSm(lctrConnCtx_t *pConnCtx, uint8_t event); +void lctrMstLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t event); +bool_t lctrMstLlcpExecuteConnUpdSm(lctrConnCtx_t *pCtx, uint8_t event); + +/* Builder */ +void lctrMstConnBuildOp(lctrConnCtx_t *pCtx, lctrConnInd_t *pConnInd); + +/* ISR */ +void lctrMstConnBeginOp(BbOpDesc_t *pOp); +void lctrMstConnCleanupOp(BbOpDesc_t *pOp); +void lctrMstConnEndOp(BbOpDesc_t *pOp); +void lctrMstConnAbortOp(BbOpDesc_t *pOp); +void lctrMstConnTxCompletion(BbOpDesc_t *pOp, uint8_t status); +void lctrMstConnRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status); + +/* Action routines. */ +void lctrMstSetEstablishConn(lctrConnCtx_t *pCtx); +void lctrMstReloadDataPdu(lctrConnCtx_t *pCtx); + +/* Helper */ +uint32_t lctrMstConnAdjustOpStart(lctrConnCtx_t *pCtx, uint32_t scanRefTime, lctrConnInd_t *pConnInd); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_CONN_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_slave.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_slave.h new file mode 100644 index 0000000000..28b84a0199 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_conn_slave.h @@ -0,0 +1,75 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller slave connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_CONN_SLAVE_H +#define LCTR_INT_CONN_SLAVE_H + +#include "lctr_int_conn.h" +#include "bb_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern LctrLlcpHdlr_t lctrSlvLlcpSmTbl[LCTR_LLCP_SM_TOTAL]; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +void lctrSlvConnExecuteSm(lctrConnCtx_t *pConnCtx, uint8_t event); +void lctrSlvLlcpExecuteSm(lctrConnCtx_t *pCtx, uint8_t event); +bool_t lctrSlvLlcpExecuteConnUpdSm(lctrConnCtx_t *pCtx, uint8_t event); +void lctrConnStatelessEventHandler(lctrConnCtx_t *pCtx, uint8_t event); +bool_t lctrLlcpExecuteCommonSm(lctrConnCtx_t *pCtx, uint8_t event); +void lctrLlcpStatelessEventHandler(lctrConnCtx_t *pCtx, uint8_t event); + +/* Status */ +bool_t lctrSlvCheckEncOverrideConnParam(lctrConnCtx_t *pCtx); +bool_t lctrSlvCheckEncOverrideCommonParam(lctrConnCtx_t *pCtx); +bool_t lctrSlvCheckConnUpdInstant(lctrConnCtx_t *pCtx); + +/* Builder */ +uint32_t lctrCalcIntervalWindowWideningUsec(lctrConnCtx_t *pCtx, uint32_t unsyncTimeUsec); +void lctrSlvConnBuildOp(lctrConnCtx_t *pCtx); + +/* ISR */ +void lctrSlvConnBeginOp(BbOpDesc_t *pOp); +void lctrSlvConnCleanupOp(BbOpDesc_t *pOp); +void lctrSlvConnEndOp(BbOpDesc_t *pOp); +void lctrSlvConnTxCompletion(BbOpDesc_t *pOp, uint8_t status); +void lctrSlvConnRxCompletion(BbOpDesc_t *pOp, uint8_t *pRxBuf, uint8_t status); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_CONN_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_master.h new file mode 100644 index 0000000000..b4f0e2a71c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_master.h @@ -0,0 +1,48 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller master connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ENC_MASTER_H +#define LCTR_INT_ENC_MASTER_H + +#include "lctr_int_conn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +bool_t lctrMstExecuteEncryptSm(lctrConnCtx_t *pCtx, uint8_t event); + +/* Action routines. */ +void lctrGenerateMstVectors(lctrConnCtx_t *pCtx); +void lctrStoreSlvVectors(lctrConnCtx_t *pCtx); +void lctrSendEncReq(lctrConnCtx_t *pCtx); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ENC_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_slave.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_slave.h new file mode 100644 index 0000000000..554983ecd4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_enc_slave.h @@ -0,0 +1,90 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller slave connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_ENC_SLAVE_H +#define LCTR_INT_ENC_SLAVE_H + +#include "lctr_int.h" +#include "lctr_int_conn.h" +#include "lctr_api_conn.h" +#include "lctr_pdu_conn.h" +#include "ll_defs.h" +#include "bb_ble_api.h" +#include "wsf_msg.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Master SKD offset. */ +#define LCTR_SKD_M_OFFS 0 + +/*! \brief Master IV offset. */ +#define LCTR_IV_M_OFFS 0 + +/*! \brief Slave SKD offset. */ +#define LCTR_SKD_S_OFFS (LL_SKD_LEN / 2) + +/*! \brief Slave IV offset. */ +#define LCTR_IV_S_OFFS (LL_IV_LEN / 2) + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +bool_t lctrSlvExecuteEncryptSm(lctrConnCtx_t *pCtx, uint8_t event); +bool_t lctrExecutePingSm(lctrConnCtx_t *pCtx, uint8_t event); + +/* Action routines. */ +void lctrEnableTxDataEnc(lctrConnCtx_t *pCtx); +void lctrDisableTxDataEnc(lctrConnCtx_t *pCtx); +void lctrEnableRxDataEnc(lctrConnCtx_t *pCtx); +void lctrDisableRxDataEnc(lctrConnCtx_t *pCtx); +void lctrGenerateSlvVectors(lctrConnCtx_t *pCtx); +void lctrStoreLtkReply(lctrConnCtx_t *pCtx); +void lctrStoreLtkNegRepTerminateReason(lctrConnCtx_t *pCtx); +void lctrCalcSessionKey(lctrConnCtx_t *pCtx); +void lctrInvalidEncPduSeq(lctrConnCtx_t *pCtx); +void lctrSendEncRsp(lctrConnCtx_t *pCtx); +void lctrSendStartEncReq(lctrConnCtx_t *pCtx); +void lctrSendStartEncRsp(lctrConnCtx_t *pCtx); +void lctrSendPauseEncReq(lctrConnCtx_t *pCtx); +void lctrSendPauseEncRsp(lctrConnCtx_t *pCtx); +void lctrSendPingReq(lctrConnCtx_t *pCtx); +void lctrSendPingRsp(lctrConnCtx_t *pCtx); +void lctrEncNotifyHostLtkReqInd(lctrConnCtx_t *pCtx); +void lctrNotifyEncChangeInd(lctrConnCtx_t *pCtx, uint8_t status); +void lctrNotifyEncKeyRefreshInd(lctrConnCtx_t *pCtx); +void lctrNotifyAuthPayloadTimeout(lctrConnCtx_t *pCtx); +void lctrRestartAuthPayloadTimer(lctrConnCtx_t *pCtx); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_ENC_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master.h new file mode 100644 index 0000000000..57015cc5cf --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master.h @@ -0,0 +1,94 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_INIT_MASTER_H +#define LCTR_INT_INIT_MASTER_H + +#include "lctr_api_init_master.h" +#include "lctr_int.h" +#include "lctr_int_adv_master.h" +#include "lctr_int_conn.h" +#include "lctr_int_conn_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master initiate states. */ +enum +{ + LCTR_INIT_STATE_DISABLED, /*!< Initiate disabled state. */ + LCTR_INIT_STATE_ENABLED, /*!< Initiate enabled state. */ + LCTR_INIT_STATE_SHUTDOWN, /*!< Scan shutdown in progress. */ + LCTR_INIT_STATE_RESET, /*!< Scan reset in progress. */ + LCTR_INIT_STATE_TOTAL /*!< Total number of scan states. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrMstScanCtx_t lctrMstInit; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Builder */ +void lctrMstInitiateBuildOp(LlConnSpec_t *pConnSpec, uint8_t peerAddrType, uint64_t peerAddr); +void lctrMstInitiateOpCommit(void); + +/* ISR */ +void lctrMstInitiateEndOp(BbOpDesc_t *pOp); +bool_t lctrMstInitiateAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstConnIndTxCompHandler(BbOpDesc_t *pOp, const uint8_t *pIndBuf); + +/* Action routines. */ +void lctrInitActInitiate(void); +void lctrInitActConnect(void); +void lctrInitActShutdown(void); +void lctrInitActScanTerm(void); +void lctrInitActResetTerm(void); +void lctrInitActDisallowInitiate(void); +void lctrInitActDisallowCancel(void); + +/* Helper routines. */ +void lctrScanCleanup(lctrMstScanCtx_t *pCtx); +void lctrScanNotifyHostInitiateError(uint8_t reason, uint8_t peerAddrType, uint64_t peerAddr); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_INIT_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master_ae.h new file mode 100644 index 0000000000..addc33ce42 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_init_master_ae.h @@ -0,0 +1,125 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller scanning master interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_INIT_MASTER_AE_H +#define LCTR_INT_INIT_MASTER_AE_H + +#include "lctr_api_init_master_ae.h" +#include "lctr_int.h" +#include "lctr_int_adv_master_ae.h" +#include "lctr_int_conn.h" +#include "lctr_int_conn_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ +/*! \brief Resolve the extended initiate handle from the context pointer. */ +#define LCTR_GET_EXT_INIT_HANDLE(pCtx) (pCtx - lctrMstExtInitTbl) + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Master initiate states. */ +enum +{ + LCTR_EXT_INIT_STATE_DISABLED, /*!< Initiate disabled state. */ + LCTR_EXT_INIT_STATE_ENABLED, /*!< Initiate enabled state. */ + LCTR_EXT_INIT_STATE_SHUTDOWN, /*!< Initiate shutdown in progress. */ + LCTR_EXT_INIT_STATE_RESET, /*!< Initiate reset in progress. */ + LCTR_EXT_INIT_STATE_TOTAL /*!< Total number of initiate states. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ +/*! \brief Extended initiating control block. */ +typedef struct +{ + /* Initiate */ + uint64_t peerAddr; /*!< Initiating peer address. */ + uint8_t peerAddrType; /*!< Initiating peer address type. */ + uint8_t estConnPhys; /*!< PHYs which established connections. */ + + /* State. */ + uint8_t enaPhys; /*!< Enabled PHYs. */ + bool_t initTermByHost; /*!< Host initiated initiate disable. */ + +} lctrExtInitCtrlBlk_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrExtScanCtx_t lctrMstExtInitTbl[LCTR_SCAN_PHY_TOTAL]; +extern lctrExtInitCtrlBlk_t lctrMstExtInit; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +void lctrMstExtInitExecuteSm(lctrExtScanCtx_t *pExtInitCtx, uint8_t event); + +/* Builder */ +uint8_t lctrMstExtInitiateBuildOp(lctrExtScanCtx_t *pExtInitCtx, LlConnSpec_t *pConnSpec, uint64_t peerAddr, uint8_t peerAddrType); +uint8_t lctrMstAuxInitiateBuildOp(lctrExtScanCtx_t *pExtInitCtx, LlConnSpec_t *pConnSpec, uint64_t peerAddr, uint8_t peerAddrType); +void lctrMstExtInitiateOpCommit(lctrExtScanCtx_t *pExtInitCtx); + +/* ISR: Initiate packet handlers */ +void lctrMstExtPreInitiateExecHandler(BbOpDesc_t *pOp); +bool_t lctrMstInitiateRxExtAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +void lctrMstInitiateRxExtAdvPktPostProcessHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstInitiateRxAuxAdvPktHandler(BbOpDesc_t *pOp, const uint8_t *pAdvBuf); +bool_t lctrMstInitiateRxAuxConnRspHandler(BbOpDesc_t *pOp, const uint8_t *pRspBuf); +bool_t lctrMstExtConnIndTxCompHandler(BbOpDesc_t *pOp, const uint8_t *pIndBuf); + +/* ISR: Initiate BOD callback */ +void lctrMstExtInitiateEndOp(BbOpDesc_t *pOp); +void lctrMstAuxInitiateEndOp(BbOpDesc_t *pOp); +void lctrMstExtInitiateScanEndOp(BbOpDesc_t *pOp); +void lctrMstAuxInitiateScanEndOp(BbOpDesc_t *pOp); + +/* Action routines. */ +void lctrExtInitActConnect(lctrExtScanCtx_t *pExtInitCtx); +void lctrExtInitActShutdown(lctrExtScanCtx_t *pExtInitCtx); +void lctrExtInitActScanTerm(lctrExtScanCtx_t *pExtInitCtx); +void lctrExtInitActDisallowInitiate(lctrExtScanCtx_t *pExtInitCtx); +void lctrExtInitActDisallowCancel(lctrExtScanCtx_t *pExtInitCtx); + +/* Helper routines. */ +void lctrMstExtInitCleanupOp(lctrExtScanCtx_t *pExtInitCtx); +void lctrScanNotifyHostInitiateError(uint8_t reason, uint8_t peerAddrType, uint64_t peerAddr); +uint8_t lctrExtInitSetupInitiate(lctrExtScanCtx_t *pExtInitCtx, uint8_t peerAddrType, uint64_t peerAddr, uint8_t filtPolicy, uint8_t ownAddrType); + +/* Messaging */ +void lctrSendExtInitMsg(lctrExtScanCtx_t *pExtScanCtx, uint8_t event); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_INIT_MASTER_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_master_phy.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_master_phy.h new file mode 100644 index 0000000000..2cb669a074 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_master_phy.h @@ -0,0 +1,44 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller PHY features (master) interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_PHY_MASTER_H +#define LCTR_INT_PHY_MASTER_H + +#include "lctr_int.h" +#include "lctr_int_conn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +bool_t lctrMstLlcpExecutePhyUpdateSm(lctrConnCtx_t *pCtx, uint8_t event); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_PHY_MASTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_priv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_priv.h new file mode 100644 index 0000000000..53f8e69224 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_priv.h @@ -0,0 +1,54 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller privacy interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_PRIV_H +#define LCTR_INT_PRIV_H + +#include "lctr_int.h" +#include "wsf_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Slave advertising state context. */ +typedef struct +{ + wsfTimer_t tmrResPrivAddrTimeout; /*!< Resolvable private address timeout timer. */ +} lctrPrivCtx_t; + +/************************************************************************************************** + Globals +**************************************************************************************************/ + +extern lctrPrivCtx_t lctrPriv; + + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_PRIV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_slave_phy.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_slave_phy.h new file mode 100644 index 0000000000..45cb17d80c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_slave_phy.h @@ -0,0 +1,55 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller PHY features (slave) interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_PHY_SLAVE_H +#define LCTR_INT_PHY_SLAVE_H + +#include "lctr_int.h" +#include "lctr_int_conn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* State machine */ +bool_t lctrSlvLlcpExecutePhyUpdateSm(lctrConnCtx_t *pCtx, uint8_t event); + +/* Action routines */ +void lctrStoreHostPhyUpdate(lctrConnCtx_t *pCtx); +void lctrStorePeerPhyReq(lctrConnCtx_t *pCtx); +void lctrStorePeerPhyUpdateInd(lctrConnCtx_t *pCtx); + +void lctrSendPhyReqPdu(lctrConnCtx_t *pCtx, uint8_t txPhys, uint8_t rxPhys); +void lctrSendPhyRspPdu(lctrConnCtx_t *pCtx, uint8_t txPhys, uint8_t rxPhys); +void lctrSendPhyUpdateIndPdu(lctrConnCtx_t *pCtx, uint8_t txPhys, uint8_t rxPhys); + +void lctrNotifyHostPhyUpdateInd(lctrConnCtx_t *pCtx, uint8_t status); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_PHY_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_tester.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_tester.h new file mode 100644 index 0000000000..9bb1cea278 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_int_tester.h @@ -0,0 +1,71 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal link layer controller connection interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_INT_TESTER_H +#define LCTR_INT_TESTER_H + +#include "ll_tester_api.h" +#include "wsf_msg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +void LctrForceTxAcl(uint8_t *pAclBuf); + +/*************************************************************************************************/ +/*! + * \brief Force transmission of a data PDU. + * + * \param connHandle Connection handle. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lctrForceTxData(uint16_t connHandle) +{ + uint8_t *pAclBuf; + + if ((pAclBuf = WsfMsgAlloc(4 + 4 + 1)) != NULL) + { + pAclBuf[0] = connHandle & 0xFF; + pAclBuf[1] = connHandle >> 8; + pAclBuf[2] = 0x05; + pAclBuf[3] = 0x00; + pAclBuf[4] = 0x01; + pAclBuf[5] = 0x00; + pAclBuf[6] = 0x40; + pAclBuf[7] = 0x00; + pAclBuf[8] = 0xFF; + LctrForceTxAcl(pAclBuf); + } +} + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_INT_TESTER_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv.h new file mode 100644 index 0000000000..b037a8cce8 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv.h @@ -0,0 +1,89 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller advertising channel packet interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_PDU_ADV_H +#define LCTR_PDU_ADV_H + +#include "lmgr_api_adv_slave.h" +#include "lctr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +#define LCTR_ADV_HDR_PDU_TYPE_SHIFT 0 /*!< ADV header PDU type field shift. */ +#define LCTR_ADV_HDR_CH_SEL_SHIFT 5 /*!< ADV header channel selection field shift. */ +#define LCTR_ADV_HDR_TX_ADD_SHIFT 6 /*!< ADV header Tx Address type field shift. */ +#define LCTR_ADV_HDR_RX_ADD_SHIFT 7 /*!< ADV header Rx Address type field shift. */ +#define LCTR_ADV_HDR_LEN_SHIFT 8 /*!< ADV header length field shift. */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Advertising channel PDU header. */ +typedef struct +{ + uint8_t pduType; /*!< PDU type. */ + uint8_t chSel; /*!< Channel selection. */ + bool_t txAddrRnd; /*!< Tx address type is random. */ + bool_t rxAddrRnd; /*!< Rx address type is random. */ + uint8_t len; /*!< Payload length. */ +} lctrAdvbPduHdr_t; + +/*! \brief Scan request PDU. */ +typedef struct +{ + uint64_t scanAddr; /*!< Scanner's address. */ + uint64_t advAddr; /*!< Advertiser's address. */ +} lctrScanReq_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Pack */ +uint8_t lctrPackAdvbPduHdr(uint8_t *pBuf, const lctrAdvbPduHdr_t *pHdr); +uint8_t lctrPackAdvPdu(uint8_t *pBuf, uint64_t advA, const lmgrAdvbUser_t *pAdvData); +uint8_t lctrPackConnDirectIndAdvPdu(uint8_t *pBuf, uint64_t advA, uint64_t initA); +uint8_t lctrPackScanReqPdu(uint8_t *pBuf, const lctrScanReq_t *pPdu); +uint8_t lctrPackScanRspPdu(uint8_t *pBuf, uint64_t advA, const lmgrAdvbUser_t *pRspData); +uint8_t lctrPackConnIndPduAddr(uint8_t *pBuf, const lctrConnInd_t *pPdu); +uint8_t lctrPackConnIndPdu(uint8_t *pBuf, const lctrConnInd_t *pPdu); + +/* Unpack */ +uint8_t lctrUnpackAdvbPduHdr(lctrAdvbPduHdr_t *pHdr, const uint8_t *pBuf); +uint8_t lctrUnpackScanReqPdu(lctrScanReq_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackConnIndPdu(lctrConnInd_t *pPdu, const uint8_t *pBuf); + +/* Validate */ +bool_t lctrValidateConnIndPdu(lctrConnInd_t *pPdu); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_PDU_ADV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv_ae.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv_ae.h new file mode 100644 index 0000000000..753210149a --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_adv_ae.h @@ -0,0 +1,130 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller extended advertising channel packet interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_PDU_ADV_AE_H +#define LCTR_PDU_ADV_AE_H + +#include "lctr_pdu_adv.h" +#include "lctr_int_adv_slave_ae.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Advertising mode. */ +enum +{ + LCTR_ADV_MODE_CONN_BIT = (1 << 0), /*!< Connectable bit. */ + LCTR_ADV_MODE_SCAN_BIT = (1 << 1) /*!< Scannable bit. */ +}; + +/*! \brief Clock accuracy. */ +enum +{ + LCTR_CLK_ACC_51_500_PPM = 0, /*!< Clock accuracy is between 51 and 500 PPM. */ + LCTR_CLK_ACC_0_50_PPM = 1 /*!< Clock accuracy is between 0 and 51 PPM. */ +}; + +/*! \brief Channel offset units. */ +enum +{ + LCTR_OFFS_UNITS_30_USEC = 0, /*!< Unit is 30 microseconds. */ + LCTR_OFFS_UNITS_300_USEC = 1 /*!< Unit is 300 microseconds. */ +}; + +#define LCTR_AUX_PTR_LEN 3 /*!< Size of AuxPtr field. */ +#define LCTR_TX_POWER_LEN 1 /*!< Size of TxPower field. */ +#define LCTR_SYNC_INFO_LEN 18 /*!< Size of SyncInfo field. */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Extended advertising channel PDU header. */ +typedef struct +{ + uint8_t extHdrLen; /*!< Extended header length. */ + uint8_t advMode; /*!< Advertising mode. */ + uint8_t extHdrFlags; /*!< Extended header flags. */ + uint64_t advAddr; /*!< Advertiser's address. */ + uint64_t tgtAddr; /*!< Target address. */ + uint16_t did; /*!< Advertising data ID in ADI. */ + uint8_t sid; /*!< Advertising set ID in ADI. */ + int8_t txPwr; /*!< Tx Power. */ + uint8_t acadLen; /*!< ACAD length. */ + const uint8_t *pAcad; /*!< Buffer pointer to ACAD. */ + const uint8_t *pAuxPtr; /*!< Buffer pointer to AuxPtr field. */ + const uint8_t *pSyncInfo; /*!< Buffer pointer to SyncInfo field. */ +} lctrExtAdvHdr_t; + +/*! \brief Auxiliary Pointer. */ +typedef struct +{ + uint8_t auxChIdx; /*!< Auxiliary channel index. */ + uint8_t ca; /*!< Advertiser's clock accuracy. */ + uint8_t offsetUnits; /*!< Offset units. */ + uint16_t auxOffset; /*!< Auxiliary offset. */ + uint8_t auxPhy; /*!< Auxiliary PHY. */ +} lctrAuxPtr_t; + +/*! \brief Sync info. */ +typedef struct +{ + uint16_t syncOffset; /*!< Sync packet offset. */ + uint8_t offsetUnits; /*!< Offset units. */ + uint16_t syncInter; /*!< Sync interval. */ + uint64_t chanMap; /*!< Secondary channel map. */ + uint8_t sca; /*!< Sleep clock accuracy. */ + uint32_t accAddr; /*!< Access address. */ + uint32_t crcInit; /*!< CRC initialization value. */ + uint16_t eventCounter; /*!< Event counter. */ +} lctrSyncInfo_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Pack */ +uint8_t lctrPackAdvExtIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, bool_t isPeriodic); +uint8_t lctrPackAuxAdvIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, lctrAdvDataBuf_t *pAdvData, bool_t isPeriodic); +uint8_t lctrPackAuxScanRspPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, bool_t isPeriodic); +uint8_t lctrPackAuxChainIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, lctrAdvDataBuf_t *pAdvData, bool_t isPeriodic); +uint8_t lctrPackAuxConnRspPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, bool_t isPeriodic); +void lctrPackAuxPtr(lctrAdvSet_t const *pAdvSet, uint32_t offsUsec, uint8_t chIdx, uint8_t *pAuxPtr); +uint8_t lctrPackLegacyAdvPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf); +uint8_t lctrPackLegacyScanRspPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf); +uint8_t lctrPackSyncIndPdu(lctrAdvSet_t *pAdvSet, uint8_t *pPduBuf, lctrAdvDataBuf_t *pAdvData, bool_t isPeriodic); + +/* Unpack */ +uint8_t lctrUnpackExtAdvHeader(lctrExtAdvHdr_t *pPdu, uint8_t *pNewFlags, const uint8_t *pBuf); +void lctrUnpackAuxPtr(lctrAuxPtr_t *pAuxPtr, const uint8_t *pBuf); +void lctrUnpackSyncInfo(lctrSyncInfo_t *pSyncInfo, const uint8_t *pBuf); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_PDU_ADV_AE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_conn.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_conn.h new file mode 100644 index 0000000000..7907a669ca --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lctr/lctr_pdu_conn.h @@ -0,0 +1,244 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer controller data channel packet interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LCTR_PDU_CONN_SLAVE_H +#define LCTR_PDU_CONN_SLAVE_H + +#include "wsf_types.h" +#include "bb_ble_api.h" +#include "ll_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +#define LCTR_OFFSET_COUNT 6 /*!< Number of offsets in a connection parameter request. */ + +/*! \brief Packet boundary flags. */ +enum +{ + LCTR_PB_START_NON_AUTO_FLUSH = 0, /*!< Start of a non-automatically flushable L2CAP PDU. */ + LCTR_PB_CONT_FRAG = 1, /*!< Continuing fragment of Higher Layer Message. */ + LCTR_PB_START_AUTO_FLUSH = 2, /*!< Start of an automatically flushable L2CAP PDU. */ + /* N.B. next two enumerations intentionally use identical values. */ + LCTR_PB_COMPLETE_AUTO_FLUSH = 3, /*!< A complete L2CAP PDU automatically flushable (not allowed for LE-U). */ + LCTR_PB_VS_DATA = 3 /*!< Vendor specific data. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief ACL header. */ +typedef struct +{ + uint16_t connHandle; /*!< Connection handle. */ + uint8_t pktBound; /*!< Packet boundary flag. */ + uint16_t len; /*!< Data length. */ +} lctrAclHdr_t; + +/*! \brief Data channel PDU header. */ +typedef struct +{ + uint8_t llid; /*!< PDU type. */ + uint8_t nesn; /*!< Next Expected Sequence Number. */ + uint8_t sn; /*!< Sequence Number. */ + uint8_t md; /*!< More Data. */ + uint8_t len; /*!< Payload length. */ +} lctrDataPduHdr_t; + +/*! \brief Connection update indication PDU. */ +typedef struct +{ + uint8_t txWinSize; /*!< transmitWindowSize value. */ + uint16_t txWinOffset; /*!< transmitWindowOffset value. */ + uint16_t interval; /*!< connInterval value. */ + uint16_t latency; /*!< connSlaveLatency value. */ + uint16_t timeout; /*!< connSupervisionTimeout value. */ + uint16_t instant; /*!< connInstant value. */ +} lctrConnUpdInd_t; + +/*! \brief Connection update indication PDU. */ +typedef struct +{ + uint64_t chanMask; /*!< Channel mask. */ + uint16_t instant; /*!< connInstant value. */ +} lctrChanMapInd_t; + +/*! \brief Terminate indication control PDU. */ +typedef struct +{ + uint8_t errorCode; /*!< Error code. */ +} lctrTermInd_t; + +/*! \brief Encryption request control PDU. */ +typedef struct +{ + uint8_t rand[LL_RAND_LEN]; /*!< Random number. */ + uint16_t ediv; /*!< Encrypted diversifier. */ + uint8_t skd_m[LL_SKD_LEN/2];/*!< Master's session key diversifier. */ + uint8_t iv_m[LL_IV_LEN/2]; /*!< Master's initialization vector. */ +} lctrEncReq_t; + +/*! \brief Encryption response control PDU. */ +typedef struct +{ + uint8_t skd_s[LL_SKD_LEN/2];/*!< Slave's session key diversifier. */ + uint8_t iv_s[LL_IV_LEN/2]; /*!< Slave's initialization vector. */ +} lctrEncRsp_t; + +/*! \brief Unknown response control PDU. */ +typedef struct +{ + uint8_t unknownType; /*!< Unknown type. */ +} lctrUnknownRsp_t; + +/*! \brief Feature request or response control PDU. */ +typedef struct +{ + uint64_t featSet; /*!< Feature set. */ +} lctrFeat_t; + +/*! \brief Connection parameter request/response values. */ +typedef struct +{ + uint16_t connIntervalMin; /*!< Minimum connection interval. */ + uint16_t connIntervalMax; /*!< Maximum connection interval. */ + uint16_t connLatency; /*!< Connection latency. */ + uint16_t supTimeout; /*!< Supervision timeout. */ + uint8_t prefPeriod; /*!< Preferred periodicity. */ + uint16_t refConnEvtCnt; /*!< Reference connection event count. */ + uint16_t offset[LCTR_OFFSET_COUNT]; /*!< Anchor point offset from \a refConnEvtCnt, first preference. */ +} lctrConnParam_t; + +/*! \brief Version indication control PDU. */ +typedef struct +{ + uint8_t versNr; /*!< Bluetooth controller specification version. */ + uint16_t compId; /*!< Company identifier. */ + uint16_t subVersNr; /*!< Sub-Version number. */ +} lctrVerInd_t; + +/*! \brief Reject indication control PDU. */ +typedef struct +{ + uint8_t opcode; /*!< Reject opcode. */ + uint8_t reason; /*!< Reject reason code. */ +} lctrRejInd_t; + +/*! \brief Data length request or response PDU. */ +typedef struct +{ + uint16_t maxRxLen; /*!< Maximum receive length. */ + uint16_t maxRxTime; /*!< Maximum receive time. */ + uint16_t maxTxLen; /*!< Maximum transmit length. */ + uint16_t maxTxTime; /*!< Maximum transmit time. */ +} lctrDataLen_t; + +/*! \brief PHY request or response PDU. */ +typedef struct +{ + uint8_t txPhys; /*!< Transmitter PHYs. */ + uint8_t rxPhys; /*!< Receiver PHYs. */ +} lctrPhy_t; + +/*! \brief PHY update indication PDU. */ +typedef struct +{ + uint8_t masterToSlavePhy; /*!< Master-to-slave PHY. */ + uint8_t slaveToMasterPhy; /*!< Slave-to-master PHY. */ + uint16_t instant; /*!< Instant. */ +} lctrPhyUpdInd_t; + +/*! \brief Minimum number of used channels indication PDU. */ +typedef struct +{ + uint8_t phys; /*!< Bitmask for the affected PHYs. */ + uint8_t minUsedChan; /*!< Minimum number of used channels. */ +} lctrMinUsedChanInd_t; + +/*! \brief Data channel control PDU. */ +typedef struct +{ + lctrDataPduHdr_t hdr; /*!< Unpacked PDU header. */ + uint8_t opcode; /*!< Control PDU opcode. */ + + union + { + lctrConnUpdInd_t connUpdInd; /*!< Connection update indication. */ + lctrChanMapInd_t chanMapInd; /*!< Channel map request. */ + lctrTermInd_t termInd; /*!< Terminate indication. */ + lctrEncReq_t encReq; /*!< Encryption request. */ + lctrEncRsp_t encRsp; /*!< Encryption response. */ + lctrUnknownRsp_t unknownRsp; /*!< Unknown response. */ + lctrFeat_t featReqRsp; /*!< Feature request or response or slave feature request. */ + lctrVerInd_t verInd; /*!< Version indication. */ + lctrConnParam_t connParamReqRsp; /*!< Connection parameter request or response. */ + lctrRejInd_t rejInd; /*!< Reject indication. */ + lctrDataLen_t lenReq; /*!< Data length request. */ + lctrDataLen_t lenRsp; /*!< Data length response. */ + lctrPhy_t phyReq; /*!< PHY request. */ + lctrPhy_t phyRsp; /*!< PHY response. */ + lctrPhyUpdInd_t phyUpdInd; /*!< PHY update indication. */ + lctrMinUsedChanInd_t minUsedChanInd;/*!< Minimum number of used channels indication. */ + } pld; /*!< Unpacked PDU payload. */ +} lctrDataPdu_t; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Pack */ +uint8_t lctrPackAclHdr(uint8_t *pBuf, const lctrAclHdr_t *pHdr); +uint8_t lctrPackDataPduHdr(uint8_t *pBuf, const lctrDataPduHdr_t *pHdr); +uint8_t lctrPackConnUpdInd(uint8_t *pBuf, const lctrConnUpdInd_t *pPdu); + +/* Unpack */ +uint8_t lctrUnpackAclHdr(lctrAclHdr_t *pHdr, const uint8_t *pBuf); +uint8_t lctrUnpackDataPduHdr(lctrDataPduHdr_t *pHdr, const uint8_t *pBuf); +uint8_t lctrUnpackConnUpdateIndPdu(lctrConnUpdInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackChanMapIndPdu(lctrChanMapInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackTerminateIndPdu(lctrTermInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackUnknownRspPdu(lctrUnknownRsp_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackFeaturePdu(lctrFeat_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackRejectIndPdu(uint8_t *pReason, const uint8_t *pBuf); +uint8_t lctrUnpackVersionIndPdu(lctrVerInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackConnParamPdu(lctrConnParam_t *pConnParam, const uint8_t *pBuf); +uint8_t lctrUnpackRejectExtIndPdu(lctrRejInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackDataLengthPdu(lctrDataLen_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackPhyPdu(lctrPhy_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackPhyUpdateIndPdu(lctrPhyUpdInd_t *pPdu, const uint8_t *pBuf); +uint8_t lctrUnpackMinUsedChanIndPdu(lctrMinUsedChanInd_t *pPdu, const uint8_t *pBuf); + +/* Decode */ +uint8_t lctrDecodeCtrlPdu(lctrDataPdu_t *pPdu, const uint8_t *pBuf, uint8_t role); +uint8_t lctrDecodeEncPdu(lctrDataPdu_t *pPdu, const uint8_t *pBuf, uint8_t role); + +#ifdef __cplusplus +}; +#endif + +#endif /* LCTR_PDU_CONN_SLAVE_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lhci/lhci_int.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lhci/lhci_int.h new file mode 100644 index 0000000000..e92db3cc93 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/lhci/lhci_int.h @@ -0,0 +1,502 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief LL HCI main module interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LHCI_INT_H +#define LHCI_INT_H + +#include "lhci_api.h" +#include "hci_defs.h" +#include "ll_api.h" +#include "wsf_os.h" +#include "wsf_queue.h" +#include "util/bstream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup LL_LHCI_INT + * \{ + */ + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/* Command complete parameter lengths */ + +/* --- Controller Group --- */ +#define LHCI_LEN_SET_EVENT_MASK_EVT 1 /*!< Set event mask command complete event length. */ +#define LHCI_LEN_RESET_EVT 1 /*!< Reset command complete event length. */ +#define LHCI_LEN_READ_PWR_LVL_EVT 4 /*!< Read power level command complete event length. */ +#define LHCI_LEN_READ_AUTH_PAYLOAD_TO_EVT 5 /*!< Read authenticated payload timeout command complete event length. */ +#define LHCI_LEN_WRITE_AUTH_PAYLOAD_TO_EVT 3 /*!< Write authenticated payload timeout command complete event length. */ + +/* --- Informational commands --- */ +#define LHCI_LEN_READ_LOCAL_VER_EVT 9 /*!< Read local version command complete event length. */ +#define LHCI_LEN_READ_LOCAL_SUP_CMDS_EVT 65 /*!< Read local supported commands command complete event length. */ +#define LHCI_LEN_READ_LOCAL_SUP_FEAT_EVT 9 /*!< Read local supported feature command complete event length. */ +#define LHCI_LEN_READ_BUF_SIZE_EVT 8 /*!< Read buffer size command complete event length. */ +#define LHCI_LEN_READ_BD_ADDR_EVT 7 /*!< Read BD address command complete event length. */ + +/* --- LE controller commands --- */ +#define LHCI_LEN_LE_SET_EVENT_MASK_EVT 1 /*!< LE set event mask command complete event length. */ +#define LHCI_LEN_LE_READ_BUF_SIZE_EVT 4 /*!< LE read buffer size command complete event length. */ +#define LHCI_LEN_LE_READ_LOCAL_SUP_FEAT_EVT 9 /*!< LE read local supported feature command complete event length. */ +#define LHCI_LEN_LE_SET_RAND_ADDR_EVT 1 /*!< LE set random address command complete event length. */ +#define LHCI_LEN_LE_SET_ADV_PARAM_EVT 1 /*!< LE set advertising parameter command complete event length. */ +#define LHCI_LEN_LE_READ_ADV_TX_POWER_EVT 2 /*!< LE read advertising Tx power command complete event length. */ +#define LHCI_LEN_LE_SET_ADV_DATA_EVT 1 /*!< LE set advertising data command complete event length. */ +#define LHCI_LEN_LE_SET_SCAN_RESP_DATA_EVT 1 /*!< LE set scan response data command complete event length. */ +#define LHCI_LEN_LE_SET_ADV_ENABLE_EVT 1 /*!< LE set advertising enable command complete event length. */ +#define LHCI_LEN_LE_SET_SCAN_PARAM_EVT 1 /*!< LE set scan parameter command complete event length. */ +#define LHCI_LEN_LE_SET_SCAN_ENABLE_EVT 1 /*!< LE set scan enable command complete event length. */ +#define LHCI_LEN_LE_CREATE_CONN_CANCEL_EVT 1 /*!< LE create connection cancel command complete event length. */ +#define LHCI_LEN_LE_READ_WL_SIZE_EVT 2 /*!< LE read white list size command complete event length. */ +#define LHCI_LEN_LE_CLEAR_WHITE_LIST_EVT 1 /*!< LE clear white list command complete event length. */ +#define LHCI_LEN_LE_ADD_DEV_WHITE_LIST_EVT 1 /*!< LE add device to white list command complete event length. */ +#define LHCI_LEN_LE_REMOVE_DEV_WHITE_LIST_EVT 1 /*!< LE remove device from white list command complete event length. */ +#define LHCI_LEN_LE_SET_HOST_CHAN_CLASS 1 /*!< LE set host channel class command complete event length. */ +#define LHCI_LEN_LE_READ_CHAN_MAP_EVT 8 /*!< LE read channel map command complete event length. */ +#define LHCI_LEN_LE_ENCRYPT_EVT 17 /*!< LE encrypt command complete event length. */ +#define LHCI_LEN_LE_LTK_REQ_REPL_EVT 3 /*!< LE LTK request reply command complete event length. */ +#define LHCI_LEN_LE_LTK_REQ_NEG_REPL_EVT 3 /*!< LE LTK request negative reply command complete event length. */ +#define LHCI_LEN_LE_RAND_EVT 9 /*!< LE random command complete event length. */ +#define LHCI_LEN_LE_READ_SUP_STATES_EVT 9 /*!< LE read supported states command complete event length. */ +#define LHCI_LEN_LE_RECEIVER_TEST_EVT 1 /*!< LE receiver test command complete event length. */ +#define LHCI_LEN_LE_TRANSMITTER_TEST_EVT 1 /*!< LE transmitter test command complete event length. */ +#define LHCI_LEN_LE_TEST_END_EVT 3 /*!< LE test end command complete event length. */ +/* New in version 4.1 */ +#define LHCI_LEN_LE_REM_CONN_PARAM_REP 3 /*!< LE remote connection parameter reply command complete event length. */ +#define LHCI_LEN_LE_REM_CONN_PARAM_NEG_REP 3 /*!< LE remote connection parameter negative reply command complete event length. */ +/* New in version 4.2 */ +#define LHCI_LEN_LE_SET_DATA_LEN 3 /*!< LE set data length command complete event length. */ +#define LHCI_LEN_LE_READ_DEF_DATA_LEN 5 /*!< LE read default data length command complete event length. */ +#define LHCI_LEN_LE_WRITE_DEF_DATA_LEN 1 /*!< LE write default data length command complete event length. */ +#define LHCI_LEN_LE_ADD_DEV_RES_LIST_EVT 1 /*!< LE add device to resolving list command complete event length. */ +#define LHCI_LEN_LE_REMOVE_DEV_RES_LIST_EVT 1 /*!< LE remove device from resolving list command complete event length. */ +#define LHCI_LEN_LE_CLEAR_RES_LIST_EVT 1 /*!< LE clear resolving list command complete event length. */ +#define LHCI_LEN_LE_READ_RES_LIST_SIZE_EVT 2 /*!< LE read resolving list size command complete event length. */ +#define LHCI_LEN_LE_READ_PEER_RES_ADDR_EVT 7 /*!< LE read peer resolving address command complete event length. */ +#define LHCI_LEN_LE_READ_LOCAL_RES_ADDR_EVT 7 /*!< LE read local resolving address command complete event length. */ +#define LHCI_LEN_LE_SET_ADDR_RES_ENABLE_EVT 1 /*!< LE set address resolution enable command complete event length. */ +#define LHCI_LEN_LE_SET_RES_PRIV_ADDR_TO_EVT 1 /*!< LE set resolving private address timeout command complete event length. */ +#define LHCI_LEN_LE_READ_MAX_DATA_LEN 9 /*!< LE read maximum data length command complete event length. */ +/* New in version 5.0 */ +#define LHCI_LEN_LE_SET_PRIVACY_MODE 1 /*!< LE set privacy mode command complete event length. */ +#define LHCI_LEN_LE_SET_ADV_SET_RAND_ADDR 1 /*!< LE set advertising set random address command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_ADV_PARAM 2 /*!< LE set extended advertising parameters command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_ADV_DATA 1 /*!< LE set extended advertising data command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_SCAN_RESP_DATA 1 /*!< LE set extended scan response data command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_ADV_ENABLE 1 /*!< LE set extended advertising enable command complete event length. */ +#define LHCI_LEN_LE_READ_MAX_ADV_DATA_LEN 3 /*!< LE read maximum advertising data length command complete event length. */ +#define LHCI_LEN_LE_READ_NUM_OF_SUP_ADV_SETS 2 /*!< LE read number of supported advertising sets command complete event length. */ +#define LHCI_LEN_LE_REMOVE_ADV_SET 1 /*!< LE remove advertising set command complete event length. */ +#define LHCI_LEN_LE_CLEAR_ADV_SETS 1 /*!< LE clear advertising sets command complete event length. */ +#define LHCI_LEN_LE_SET_PER_ADV_PARAM 1 /*!< LE set periodic advertising parameters command complete event length. */ +#define LHCI_LEN_LE_SET_PER_ADV_DATA 1 /*!< LE set periodic advertising data command complete event length. */ +#define LHCI_LEN_LE_SET_PER_ADV_ENABLE 1 /*!< LE set periodic advertising enable command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_SCAN_PARAM 1 /*!< LE set extended scan parameter command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_SCAN_ENABLE 1 /*!< LE set extended scan enable command complete event length. */ +#define LHCI_LEN_LE_PER_ADV_CREATE_SYNC_CANCEL 1 /*!< LE periodic advertising create sync cancel command complete event length. */ +#define LHCI_LEN_LE_PER_ADV_TERMINATE_SYNC 1 /*!< LE periodic advertising terminate sync command complete event length. */ +#define LHCI_LEN_LE_ADD_DEV_PER_ADV_LIST 1 /*!< LE add device from periodic advertising list command complete event length. */ +#define LHCI_LEN_LE_REM_DEV_PER_ADV_LIST 1 /*!< LE remove device from periodic advertising list command complete event length. */ +#define LHCI_LEN_LE_CLEAR_PER_ADV_LIST 1 /*!< LE clear periodic advertising list command complete event length. */ +#define LHCI_LEN_LE_READ_PER_ADV_LIST_SIZE 2 /*!< LE read periodic advertising list size command complete event length. */ +#define LHCI_LEN_LE_READ_SUP_TX_POWER 3 /*!< LE read supported Tx power command complete event length. */ +#define LHCI_LEN_LE_WRITE_RF_PATH_COMP 1 /*!< LE write RF path compensation command complete event length. */ +#define LHCI_LEN_LE_READ_RF_PATH_COMP 5 /*!< LE read RF path compensation command complete event length. */ +#define LHCI_LEN_LE_SET_EXT_SCAN_ENABLE_EVT 1 /*!< LE set extended scan enable command complete event length. */ +#define LHCI_LEN_LE_READ_PHY_EVT 5 /*!< LE read PHY command complete event length. */ +#define LHCI_LEN_LE_SET_DEF_PHY_EVT 1 /*!< LE set default PHY command complete event length. */ +#define LHCI_LEN_LE_ENHANCED_RECEIVER_TEST_EVT 1 /*!< LE enhanced receiver test command complete event length. */ +#define LHCI_LEN_LE_ENHANCED_TRANSMITTER_TEST_EVT 1 /*!< LE enhanced transmitter test command complete event length. */ + +/*! \brief Mandatory event mask. */ +#define LHCI_DEF_EVT_MASK UINT64_C(0x00001FFFFFFFFFFF); + +/*! \brief Default page 2 event mask. */ +#define LHCI_DEF_EVT_PG2_MASK UINT64_C(0x0000000000000000); + +/*! \brief Default LE specific event mask. */ +#define LHCI_DEF_LE_EVT_MASK UINT64_C(0x000000000000001F); + +/*! \brief Local supported features value. */ +#define LHCI_LOCAL_SUP_FEAT_VAL UINT64_C(0x0000006000000000) + /* bit 37: BR/EDR Not Supported */ + /* bit 38: LE Supported (Controller) */ + +/*! \brief Convert bytes to bits. */ +#define LHCI_BYTE_TO_BITS(x) (8 * x) + +/*! \brief Vendor specific event length. */ +#define LHCI_LEN_VS_EVT 2 + +/*! \brief Indicate command status event shall be returned. */ +#define LHCI_LEN_CMD_STATUS_EVT 0xFF + +/* Cordio vendor specific OCF range is 0x3E0-0x3FF. */ +#define LHCI_OPCODE_VS_SET_SCAN_CH_MAP HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E0) /*!< Set Scan Channel Map opcode. */ +#define LHCI_OPCODE_VS_SET_EVENT_MASK HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E1) /*!< Set Vendor Specific Event Mask opcode. */ +#define LHCI_OPCODE_VS_SET_RSRC_MGR_MODE HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E2) /*!< DEPRECATED. */ +#define LHCI_OPCODE_VS_ENA_ACL_SINK HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E3) /*!< Enable ACL Packet Sink opcode. */ +#define LHCI_OPCODE_VS_GENERATE_ACL HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E4) /*!< Generate ACL Packets opcode. */ +#define LHCI_OPCODE_VS_ENA_AUTO_GEN_ACL HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E5) /*!< Enable Auto Generate ACL Packets opcode. */ +#define LHCI_OPCODE_VS_SET_TX_TEST_ERR_PATT HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E6) /*!< Set Tx Test Error Pattern opcode. */ +#define LHCI_OPCODE_VS_SET_CONN_OP_FLAGS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E7) /*!< Set Connection Operational Flags opcode. */ +#define LHCI_OPCODE_VS_SET_P256_PRIV_KEY HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E8) /*!< Set P-256 Private Key opcode. */ +#define LHCI_OPCODE_VS_GET_ACL_TEST_REPORT HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3E9) /*!< Get ACL Test Report opcode. */ +#define LHCI_OPCODE_VS_SET_LOCAL_MIN_USED_CHAN HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3EA) /*!< Set local minimum number of used channels. */ +#define LHCI_OPCODE_VS_GET_PEER_MIN_USED_CHAN HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3EB) /*!< Get peer minimum number of used channels. */ +#define LHCI_OPCODE_VS_SET_BD_ADDR HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F0) /*!< Set BD address opcode. */ +#define LHCI_OPCODE_VS_GET_RAND_ADDR HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F1) /*!< Get Random Address opcode. */ +#define LHCI_OPCODE_VS_SET_LOCAL_FEAT HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F2) /*!< Set Local Feature opcode. */ +#define LHCI_OPCODE_VS_SET_OP_FLAGS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F3) /*!< Set Operational Flags opcode. */ +#define LHCI_OPCODE_VS_SET_ADV_TX_PWR HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F5) /*!< Set Advertising Tx Power opcode. */ +#define LHCI_OPCODE_VS_SET_CONN_TX_PWR HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F6) /*!< Set Connection Tx Power opcode. */ +#define LHCI_OPCODE_VS_SET_ENC_MODE HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F7) /*!< Set Encryption Mode opcode. */ +#define LHCI_OPCODE_VS_SET_CHAN_MAP HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F8) /*!< Set Channel Map opcode. */ + +#define LHCI_OPCODE_VS_SET_DIAG_MODE HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F9) /*!< Set Diagnostic Mode opcode. */ + +#define LHCI_OPCODE_VS_GET_PDU_FILT_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3F4) /*!< Get PDU Filter Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_SYS_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FA) /*!< Get Memory Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_ADV_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FB) /*!< Get Advertising Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_SCAN_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FC) /*!< Get Scan Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_CONN_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FD) /*!< Get Connection Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_TEST_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FE) /*!< Get Test Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_POOL_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3FF) /*!< Get Pool Statistics opcode. */ + +#define LHCI_OPCODE_VS_SET_AUX_DELAY HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3D0) /*!< Set Additional AuxPtr offset. */ +#define LHCI_OPCODE_VS_SET_EXT_ADV_FRAG_LEN HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3D1) /*!< Set extended advertising data fragmentation length. */ +#define LHCI_OPCODE_VS_SET_EXT_ADV_PHY_OPTS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3D2) /*!< Set extended advertising PHY options. */ +#define LHCI_OPCODE_VS_SET_EXT_ADV_DEF_PHY_OPTS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3D3) /*!< Set extended advertising default PHY options. */ + +#define LHCI_OPCODE_VS_GET_AUX_ADV_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3DA) /*!< Get Auxiliary Advertising Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_AUX_SCAN_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3DB) /*!< Get Auxiliary Scanning Statistics opcode. */ +#define LHCI_OPCODE_VS_GET_PER_SCAN_STATS HCI_OPCODE(HCI_OGF_VENDOR_SPEC, 0x3DC) /*!< Get Periodic Scanning Statistics opcode. */ + +/* Vendor specific event masks. */ +#define LHCI_VS_EVT_MASK_SCAN_REPORT_EVT 0x01 /*!< (Byte 0) VS event bit, scan report. */ +#define LHCI_VS_EVT_MASK_DIAG_TRACE_EVT 0x02 /*!< (Byte 0) VS event bit, diagnostic tracing. */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Message handler types. */ +enum +{ + LHCI_MSG_PRIV, /*!< Privacy command handler type. Must be before CONN. */ + LHCI_MSG_CONN, /*!< Connection command handler type. */ + LHCI_MSG_CONN_CS2, /*!< Connection Channel Selection 2 command handler type. */ + LHCI_MSG_ENC, /*!< Encryption command handler type. */ + LHCI_MSG_SCAN, /*!< Scan command handler type. */ + LHCI_MSG_EXT_SCAN, /*!< Extended scan command handler type. */ + LHCI_MSG_PER_SCAN, /*!< Periodic scan command handler type. */ + LHCI_MSG_ADV, /*!< Advertising command handler type. */ + LHCI_MSG_EXT_ADV, /*!< Extended advertising command handler type. */ + LHCI_MSG_PER_ADV, /*!< Periodic advertising command handler type. */ + LHCI_MSG_SC, /*!< Secure connections command handler type. */ + LHCI_MSG_PHY, /*!< PHY features command handler type. */ + LHCI_MSG_VS_EXT, /*!< Extended vendor specific command handler type. */ + LHCI_MSG_TESTER, /*!< Tester vendor specific command handler type. */ + LHCI_MSG_TOTAL /*!< Total number of command handlers. */ +}; + +/*! \brief Task event types. */ +enum +{ + LHCI_EVT_ACL_RCVD = (1 << 0), /*!< HCI ACL packet received. */ + LHCI_EVT_CMD_RCVD = (1 << 1), /*!< HCI command packet received. */ + LHCI_EVT_SEND_CMPL = (1 << 2), /*!< HCI event packet send completion. */ + LHCI_EVT_HW_ERR = (1 << 3), /*!< HCI hardware error. */ +}; + +/*! \brief Event handler call signature. */ +typedef bool_t (*lhciEvtHandler_t)(LlEvt_t *pEvt); + +/*! \brief Service ACL call signature. */ +typedef uint8_t *(*lhciServiceAcl_t)(void); + +/*! \brief Control block of the LL HCI subsystem (persists with resets). */ +typedef struct +{ + wsfHandlerId_t handlerId; /*!< Task handler ID. */ + + wsfQueue_t aclQ; /*!< ACL queue. */ + wsfQueue_t cmdQ; /*!< Command queue. */ + wsfQueue_t evtQ; /*!< Event queue. */ + bool_t evtTrPending; /*!< Event transport in progress. */ +} lhciPersistCb_t; + +/*! \brief Control block of the LL HCI subsystem (cleared with resets). */ +typedef struct +{ + uint64_t evtMsk; /*!< General event mask. */ + uint64_t evtMskPg2; /*!< General event mask page 2. */ + uint64_t leEvtMsk; /*!< LE specific event mask. */ + + uint8_t numScanReqRcvd; /*!< Number of scan request received. */ + uint8_t hwErrorCode; /*!< Hardware error code. */ + + bool_t recvAclSink; /*!< Receive ACL sink. */ + uint32_t recvAclPktCnt; /*!< Receive ACL packet count. */ + uint32_t recvAclOctetCnt; /*!< Receive ACL octet count. */ + bool_t genEnaFlag; /*!< Generate enable flag. */ + uint8_t genPldCnt; /*!< Generate ACL packet fill value. */ + uint16_t genPktLen; /*!< Generate ACL packet length (0 to disable). */ + uint32_t genPktCnt; /*!< Generate ACL packet count. */ + uint32_t genOctetCnt; /*!< Generate ACL octet count. */ + + uint8_t numAdvReport; /*!< Number of pending advertising reports. */ +} lhciCb_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/*! \brief Command handler table. */ +extern lhciCmdHandler_t lhciCmdTbl[LHCI_MSG_TOTAL]; + +/*! \brief Event handler table. */ +extern lhciEvtHandler_t lhciEvtTbl[LHCI_MSG_TOTAL]; + +/*! \brief Receive pending handler. */ +extern lhciServiceAcl_t lhciServiceAcl; + +/* Persistent control block */ +extern lhciPersistCb_t lhciPersistCb; + +/* Control block */ +extern lhciCb_t lhciCb; + +/* Handler duration watermark in microseconds. */ +extern uint16_t lhciHandlerWatermarkUsec; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Reset */ +void lhciReset(void); + +/* Data exchange */ +void lhciRecv(uint8_t type, uint8_t *pBuf); +void lhciSendComplete(uint8_t type, uint8_t *pBuf); +bool_t lhciService(uint8_t *pType, uint16_t *pLen, uint8_t **pBuf); +void lhciSendHwError(uint8_t code); + +/* Handlers */ +bool_t lhciLlEvtHandler(LlEvt_t *pEvt); +void lhciAclSendComplete(uint16_t handle, uint8_t numBufs); +uint8_t *lhciRecvAcl(void); +void lhciAclRecvPending(uint16_t handle, uint8_t numBufs); +void lhciGenerateAcl(uint16_t handle, uint16_t pktLen, uint8_t numPkts); + +/* Command parser */ +bool_t lhciCommonDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciConnDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstConnDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstExtConnDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstEncDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvEncDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstScanDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvAdvDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstExtScanDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvExtAdvDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciPrivAdvDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciPrivConnDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciScDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciPhyDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciCommonVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciConnVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstConnVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstScanVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvAdvVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvEncVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciScVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciMstExtScanVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciSlvExtAdvVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); +bool_t lhciVsExtDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf); + +/* Event builders */ +void lhciSendCmdStatusEvt(LhciHdr_t *pCmdHdr, uint8_t status); +bool_t lhciConnEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciConnCsEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciMstConnEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciMstScanEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciSlvAdvEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciMstExtScanEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciSlvExtAdvEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciMstEncEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciSlvEncEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciPrivConnEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciScEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciPhyEncodeEvtPkt(LlEvt_t *pEvt); +bool_t lhciSlvVsStdEncodeEvtPkt(LlEvt_t *pEvt); + +/* Events */ +uint8_t *lhciAllocEvt(uint8_t evtCode, uint8_t paramLen); +uint8_t *lhciAllocCmdCmplEvt(uint8_t paramLen, uint16_t opCode); + +/* Command packet. */ +uint8_t lhciUnpackConnSpec(LlConnSpec_t *pConnSpec, const uint8_t *pBuf); + +/*************************************************************************************************/ +/*! + * \brief Pack an event packet header. + * + * \param pBuf Packed packet buffer. + * \param evtCode Event code. + * \param paramLen Parameter length. + * + * \return Packet length. + */ +/*************************************************************************************************/ +static inline uint8_t lhciPackEvtHdr(uint8_t *pBuf, uint8_t evtCode, uint8_t paramLen) +{ + const uint8_t len = HCI_EVT_HDR_LEN; + + UINT8_TO_BSTREAM(pBuf, evtCode); + UINT8_TO_BSTREAM(pBuf, paramLen); + + return len; +} + +/*************************************************************************************************/ +/*! + * \brief Pack a command status event packet. + * + * \param pBuf Packed packet buffer. + * \param status Completion status. + * \param opCode OpCode. + * + * \return Packet length. + */ +/*************************************************************************************************/ +static inline uint8_t lhciPackCmdStatusEvt(uint8_t *pBuf, uint8_t status, uint16_t opCode) +{ + const uint8_t len = HCI_LEN_CMD_STATUS; + + UINT8_TO_BSTREAM (pBuf, status); + UINT8_TO_BSTREAM (pBuf, 1); /* Num_HCI_Command_Packets is always 1 */ + UINT16_TO_BSTREAM(pBuf, opCode); + + return len; +} + +/*************************************************************************************************/ +/*! + * \brief Pack a command complete event packet. + * + * \param pBuf Packed packet buffer. + * \param opCode OpCode. + * + * \return Packet length. + */ +/*************************************************************************************************/ +static inline uint8_t lhciPackCmdCompleteEvt(uint8_t *pBuf, uint16_t opCode) +{ + const uint8_t len = HCI_LEN_CMD_CMPL; + + UINT8_TO_BSTREAM (pBuf, 1); /* Num_HCI_Command_Packets is always 1 */ + UINT16_TO_BSTREAM(pBuf, opCode); + + return len; +} + +/*************************************************************************************************/ +/*! + * \brief Pack a command complete status parameter. + * + * \param pBuf Packed packet buffer. + * \param status Completion status. + * + * \return Packet length. + */ +/*************************************************************************************************/ +static inline uint8_t lhciPackCmdCompleteEvtStatus(uint8_t *pBuf, uint8_t status) +{ + const uint8_t len = sizeof(uint8_t); + + UINT8_TO_BSTREAM (pBuf, status); + + return len; +} + +/*************************************************************************************************/ +/*! + * \brief Pack a vendor specific event packet. + * + * \param pBuf Packed packet buffer. + * \param vsEvtCode Event code. + * + * \return Packet length. + */ +/*************************************************************************************************/ +static inline uint8_t lhciPackVsEvt(uint8_t *pBuf, uint16_t vsEvtCode) +{ + const uint8_t len = LHCI_LEN_VS_EVT; + + UINT16_TO_BSTREAM(pBuf, vsEvtCode); + + return len; +} + +/*************************************************************************************************/ +/*! + * \brief Send an event. + * + * \param pEvtBuf Buffer containing event. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lhciSendEvt(uint8_t *pEvtBuf) +{ + LhciSendEvent(pEvtBuf - HCI_EVT_HDR_LEN); +} + +/*************************************************************************************************/ +/*! + * \brief Send a command complete event. + * + * \param pEvtBuf Buffer containing command complete event. + * + * \return None. + */ +/*************************************************************************************************/ +static inline void lhciSendCmdCmplEvt(uint8_t *pEvtBuf) +{ + LhciSendEvent(pEvtBuf - (HCI_EVT_HDR_LEN + HCI_LEN_CMD_CMPL)); +} + +/*! \} */ /* LL_INT_LHCI */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LHCI_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/sch/sch_int_rm.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/sch/sch_int_rm.h new file mode 100644 index 0000000000..8f262211a1 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/ble/sch/sch_int_rm.h @@ -0,0 +1,86 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal scheduler resource manager interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef SCH_INT_RM_H +#define SCH_INT_RM_H + +#include "sch_api.h" +#include "ll_math.h" +#include "cfg_mac_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Maximum number of reservations per unit of preferred periodicity. */ +#define SCH_RM_MAX_RSVN_PREF_PER 2 /* TODO allow run-time configuration */ + +/*! \brief Preferred periodicity. */ +#define SCH_RM_PREF_PER_USEC 40000 /* TODO allow run-time configuration (e.g. multiples of 10-ms) */ + /* Use 10000 for 1M and 2M only PHY support. */ + /* Use 40000 for Coded S8 PHY support. */ + +/*! \brief Binary divide by preferred periodicity (10,000us) (n[max]=75,776). */ +#define SCH_RM_DIV_PREF_PER(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(1717987)) >> 34)) + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Reservation descriptor. */ +typedef struct +{ + uint8_t handle; /*!< Reservation handle. */ + uint32_t offsUsec; /*!< Offset in microseconds. */ + uint32_t interUsec; /*!< Interval in microseconds. */ +} schRmRsvn_t; + +/*! \brief Scheduler resource manager control block. */ +typedef struct +{ + uint8_t numRsvn; /*!< Number of reservations. */ + uint32_t rsvnInterUsec[SCH_RM_MAX_RSVN]; /*!< Reserved intervals indexed by handle. */ +} SchRmCb_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern SchRmCb_t schRmCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +uint8_t schRmBuildReservationTable(schRmRsvn_t rsvn[], uint32_t rsvnOffs[], uint8_t exclude); +void schRmSortListDescending(uint32_t item[], uint8_t numItems); +void schRmSortRsvnList(schRmRsvn_t rsvn[], uint8_t numRsvn); + +#ifdef __cplusplus +}; +#endif + +#endif /* SCH_INT_RM_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/bb/bb_int.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/bb/bb_int.h new file mode 100644 index 0000000000..01a00a6bed --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/bb/bb_int.h @@ -0,0 +1,68 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_INT_H +#define BB_INT_H + +#include "bb_api.h" +#include "wsf_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief BB control block. */ +typedef struct +{ + BbOpDesc_t *pOpInProgress; /*!< Current BB operation in progress. */ + BbBodCompCback_t bodCompCback; /*!< BOD completion handler. */ + + struct + { + BbBodCback_t execOpCback; /*!< Execute operation handler. */ + BbBodCback_t cancelOpCback; /*!< Cancel operation handler. */ + BbProtCback_t startProtCback; /*!< Start protocol handler. */ + BbProtCback_t stopProtCback; /*!< Stop protocol handler. */ + uint32_t startCnt; /*!< Start counter. */ + } prot[BB_PROT_NUM]; /*!< Protocol callbacks. */ + + uint8_t protIdStarted; /*!< Started protocol ID. */ + bool_t protStarted; /*!< Protocol started. */ + bool_t termBod; /*!< Terminate current BOD. */ +} BbCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern BbCtrlBlk_t bbCb; +extern const BbRtCfg_t *pBbRtCfg; + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/sch/sch_int.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/sch/sch_int.h new file mode 100644 index 0000000000..938abc82d4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/controller/sources/common/sch/sch_int.h @@ -0,0 +1,120 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Internal multi-protocol scheduler interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef SCH_INT_H +#define SCH_INT_H + +#include "sch_api.h" +#include "bb_drv.h" +#include "wsf_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Maximum span of scheduler elements. */ +#define SCH_MAX_SPAN 0x80000000 + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*! \brief Scheduler states. */ +enum +{ + SCH_STATE_IDLE, /*!< Scheduler idle. */ + SCH_STATE_LOAD, /*!< Scheduler loading next BOD. */ + SCH_STATE_EXEC /*!< Scheduler executing BOD. */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +typedef struct +{ + bool_t active; /*!< Whether background task is active. */ + BbOpDesc_t *pBod; /*!< Head element of scheduled list of BOD. */ +} SchBackground_t; + +/*! \brief Scheduler control block. */ +typedef struct +{ + bool_t state; /*!< Current scheduler state. */ + bool_t eventSetFlag; /*!< Scheduler event set (BB terminated BOD). */ + wsfHandlerId_t handlerId; /*!< System event handler ID. */ + + BbOpDesc_t *pHead; /*!< Head element of scheduled list of BOD. */ + BbOpDesc_t *pTail; /*!< Tail element of scheduled list of BOD. */ + SchBackground_t background; /*!< Background BOD. */ +} SchCtrlBlk_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern SchCtrlBlk_t schCb; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Load */ +void schLoadNext(void); +bool_t schTryLoadHead(void); + +/* List management */ +void schRemoveHead(void); + +/*************************************************************************************************/ +/*! + * \brief Is BOD due time in the future. + * + * \param pBod Target BOD. + * + * \return TRUE if BOD time is in the future, FALSE otherwise. + */ +/*************************************************************************************************/ +static inline bool_t schDueTimeInFuture(BbOpDesc_t *pBod) +{ + bool_t result = FALSE; + + const uint32_t curTime = BbDrvGetCurrentTime(); + const uint32_t delta = pBod->due - curTime; + + if (delta < SCH_MAX_SPAN) /* due time has not passed */ + { + result = TRUE; + } + + return result; +} + +#ifdef __cplusplus +}; +#endif + +#endif /* SCH_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/libcordio_stack.a b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/libcordio_stack.a new file mode 100644 index 0000000000000000000000000000000000000000..8d02e1fb51ae861580a642ce34aaeb6992996685 GIT binary patch literal 1117152 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

c8z)FNbf;?gpFbHadprE$J=U)X|RNCUTwSaQ3 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%0A!O=w3K4Xu16}N%nbx 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


+m{77Q{PVLW4lpb6r0vp6w=oh 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 A_5c6? literal 0 HcmV?d00001 diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_154_drv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_154_drv.h new file mode 100644 index 0000000000..0f7ad71047 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_154_drv.h @@ -0,0 +1,328 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband driver interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_154_DRV_H +#define BB_154_DRV_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/* Define structures as packed if necessary. */ +#if defined (__GNUC__) +# define BB_154_PACKED __attribute__ ((packed)) +#elif defined (__CC_ARM) +# define BB_154_PACKED __attribute__ ((packed)) +#else +# error "Not supported compiler type." +#endif + +/*! \brief Minimum number of receive buffers. */ +#define BB_154_DRV_MIN_RX_BUF_CNT 2 /*!< BB_154_DRV_MIN_RX_BUF_CNT. */ +#define BB_154_RX_BUF_CNT 2 /*!< BB_154_RX_BUF_CNT. */ + +/*! \brief Driver status flags. */ +enum +{ + BB_154_DRV_FLAG_RX_ACK_CMPL = (1 << 0), /*!< Rx ack. completed. */ + BB_154_DRV_FLAG_TX_ACK_CMPL = (1 << 1), /*!< Tx ack. completed. */ + BB_154_DRV_FLAG_RX_ACK_START = (1 << 2), /*!< Rx ack. started. */ + BB_154_DRV_FLAG_TX_ACK_START = (1 << 3), /*!< Tx ack. started. */ +}; + +/*! \brief Operation flags. */ +enum +{ + BB_154_DRV_FLAG_TX_AUTO_RX_ACK = (1 << 0), /*!< Automatically wait for ACK after transmit completes. */ + BB_154_DRV_FLAG_RX_AUTO_TX_ACK = (1 << 1), /*!< Automatically send ACK after receive completes. */ + BB_154_DRV_FLAG_RX_WHILE_ED = (1 << 2), /*!< Receive any packet detected while performing ED. */ + BB_154_DRV_FLAG_DIS_CCA = (1 << 3) /*!< Disable CCA before transmit. */ +}; + +/*! \brief Receive flags. */ +enum +{ + BB_154_DRV_RX_FLAG_GO_IDLE = (1 << 0), /*!< Can go idle. */ + BB_154_DRV_RX_FLAG_SET_ACK_FP = (1 << 1) /*!< Set frame pending in ack. */ +}; + +/*! \brief BB_154_DRV_FLAG_TX_RX_AUTO_ACK. */ +#define BB_154_DRV_FLAG_TX_RX_AUTO_ACK (BB_154_DRV_FLAG_TX_AUTO_RX_ACK | BB_154_DRV_FLAG_RX_AUTO_TX_ACK) + +/* Symbols to microseconds for 802.15.4-2006 2.4GHz PHY */ +#define BB_154_SYMB_TO_US(x) ((x) * 16) /*!< BB_154_SYMB_TO_US. */ +#define BB_154_SYMB_TO_MS(x) (((x) * 16) / 1000) /*!< BB_154_SYMB_TO_MS. */ +#define BB_154_US_TO_SYMB(x) ((x) / 16) /*!< BB_154_US_TO_SYMB. */ +/* Transaction persistence time factor */ +#define BB_154_TPT_TO_MS(x) (((x) * 15723) >> 10) /*!< 15723/1024 approximates to 15.36 */ + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief 802.15.4 channelization parameters. */ +typedef struct +{ + uint8_t channel; /*!< Channel. */ + int8_t txPower; /*!< Transmit power, units dBm. */ +} Bb154DrvChan_t; + +/*! \brief Transmit complete ISR callback signature. */ +typedef void (*Bb154DrvTxIsr_t)(uint8_t flags); + +/*! \brief Frame pending check callback. */ +typedef bool_t (*Bb154DrvFPIsr_t)(uint8_t srcAddrMode, uint64_t srcAddr); + +/*! \brief Receive complete ISR callback signature. */ +typedef uint8_t (*Bb154DrvRxIsr_t)(uint8_t *pBuf, uint16_t len, uint8_t linkQuality, uint32_t timestamp, uint8_t flags); + +/*! \brief CCA or energy detect complete ISR callback signature. */ +typedef void (*Bb154DrvEdIsr_t)(uint8_t energyLevel); + +/*! \brief Driver error callback signature. */ +typedef void (*Bb154DrvErr_t)(uint8_t status); + +/*! \brief Operation parameters. */ +typedef struct +{ + uint8_t flags; /*!< Baseband driver operation flags. */ + uint8_t psduMaxLength; /*!< Maximum length of PSDU. */ + Bb154DrvTxIsr_t txCback; /*!< Transmit complete ISR callback. */ + Bb154DrvFPIsr_t fpCback; /*!< Frame pending check callback. */ + Bb154DrvRxIsr_t rxCback; /*!< Receive complete ISR callback. */ + Bb154DrvEdIsr_t edCback; /*!< ED complete ISR callback. */ + Bb154DrvErr_t errCback; /*!< Error callback. */ +} Bb154DrvOpParam_t; + +/*! \brief Transmit buffer descriptor. */ /* Note - must be packed so buffer immediately follows length */ +typedef struct BB_154_PACKED Bb154DrvTxBufDesc +{ + uint8_t pad[2]; /*!< Padding to make structure uint32 aligned */ + uint8_t handle; /*!< Handle used for data frames only */ + uint8_t len; /*!< Length of frame, which is concatenated to this header */ +} Bb154DrvTxBufDesc_t; + +/*! \brief BB_154_DRV_TX_FRAME_PTR */ +#define BB_154_DRV_TX_FRAME_PTR(x) ((uint8_t *)(((Bb154DrvTxBufDesc_t *)(x))+1)) + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Initialize the 802.15.4 baseband driver. + * + * \return None. + * + * One-time initialization of baseband resources. This routine can be used to setup software + * driver resources, load RF trim parameters and execute RF calibrations. + * + * This routine should block until the BB hardware is completely initialized. + */ +/*************************************************************************************************/ +void Bb154DrvInit(void); + +/*************************************************************************************************/ +/*! + * \brief Enable the BB hardware. + * + * \return None. + * + * This routine brings the BB hardware out of low power (enable power and clocks). This routine is + * called just before a 802.15.4 BOD is executed. + */ +/*************************************************************************************************/ +void Bb154DrvEnable(void); + +/*************************************************************************************************/ +/*! + * \brief Disable the BB hardware. + * + * \return None. + * + * This routine signals the BB hardware to go into low power (disable power and clocks). This + * routine is called after all 802.15.4 operations are disabled. + */ +/*************************************************************************************************/ +void Bb154DrvDisable(void); + +/*************************************************************************************************/ +/*! + * \brief Set channelization parameters. + * + * \param pParam Channelization parameters. + * + * \return None. + * + * Calling this routine will set parameters for all future transmit, receive, and energy detect + * operations until this routine is called again providing new parameters. + * + * \note \a pParam is not guaranteed to be static and is only valid in the context of the + * call to this routine. Therefore parameters requiring persistence should be copied. + */ +/*************************************************************************************************/ +void Bb154DrvSetChannelParam(const Bb154DrvChan_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Reset channelization parameters. + * + * \return None. + * + * Calling this routine will reset (clear) the channelization parameters. + */ +/*************************************************************************************************/ +void Bb154DrvResetChannelParam(void); + +/*************************************************************************************************/ +/*! + * \brief Set the operation parameters. + * + * \param pOpParam Operations parameters. + * + * \return None. + * + * Calling this routine will set parameters for all future transmit, receive, ED, and CCA + * operations until this routine is called again providing new parameters. + * + * \note \a pOpParam is not guaranteed to be static and is only valid in the context of the + * call to this routine. Therefore parameters requiring persistence should be copied. + */ +/*************************************************************************************************/ +void Bb154DrvSetOpParams(const Bb154DrvOpParam_t *pOpParam); + +/*************************************************************************************************/ +/*! + * \brief Flushes PIB attributes to hardware. + * + * \return None. + * + * Calling this routine will flush all PIB attributes that have a hardware counterpart to the + * respective registers in hardware. + */ +/*************************************************************************************************/ +void Bb154DrvFlushPIB(void); + +/*************************************************************************************************/ +/*! + * \brief Clear all received buffers (active and queued). + * + * \return None. + * + * Calling this routine will clear and free the active receive buffer (if any) and all queued + * receive buffers. This should only be called when the operation is terminating. + */ +/*************************************************************************************************/ +void Bb154DrvClearRxBufs(void); + +/*************************************************************************************************/ +/*! + * \brief Reclaim the buffer associated with the received frame. + * + * \param pRxFrame Pointer to the received frame. + * + * \return Total number of receive buffers queued. + * + * Calling this routine will put the buffer associated with the received frame back onto the + * receive queue. Note the actual buffer pointer may not be the same as the frame pointer + * dependent on driver implementation. If the queue is empty when the driver expects to + * transition to the receive state, the driver will instead move into the off state. + */ +/*************************************************************************************************/ +uint8_t Bb154DrvReclaimRxFrame(uint8_t *pRxFrame); + +/*************************************************************************************************/ +/*! + * \brief Build receive buffer queue + * + * \param len Length of each receive buffer. + * \param num Number of buffers to load into the queue. + * + * \return None. + */ +/*************************************************************************************************/ +void Bb154DrvBuildRxBufQueue(uint16_t len, uint8_t num); + +/*************************************************************************************************/ +/*! + * \brief Transmit a packet. + * + * \param pDesc Chain of transmit buffer descriptors. + * \param cnt Number of descriptors. + * \param due Due time for transmit (if \a now is FALSE). + * \param now TRUE if packet should be transmitted with minimal delay. + * + * \return None. + */ +/*************************************************************************************************/ +void Bb154DrvTx(Bb154DrvTxBufDesc_t *pDesc, uint8_t cnt, uint32_t due, bool_t now); + +/*************************************************************************************************/ +/*! + * \brief Receive a packet. + * + * \param due Due time for receive (if \a now is FALSE). + * \param now TRUE if packet should be received with minimal delay. + * \param timeout Timeout. + * + * \return None. + */ +/*************************************************************************************************/ +void Bb154DrvRx(uint32_t due, bool_t now, uint32_t timeout); + +/*************************************************************************************************/ +/*! + * \brief Perform energy detect. + * + * \param due Due time for energy detect (if \a now is FALSE). + * \param now TRUE if energy detect should occur minimal delay. + * + * \return None. + * + * Perform energy detect and return energy level to assess channel status. + */ +/*************************************************************************************************/ +void Bb154DrvEd(uint32_t due, bool_t now); + +/*************************************************************************************************/ +/*! + * \brief Cancel any pending operation. + * + * \return TRUE if pending operation could be cancelled. + * + * Cancel any pending operation. + */ +/*************************************************************************************************/ +bool_t Bb154DrvOff(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_154_DRV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_ble_drv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_ble_drv.h new file mode 100644 index 0000000000..45834cc859 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_ble_drv.h @@ -0,0 +1,443 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband driver interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_DRV_H +#define BB_BLE_DRV_H + +#include "wsf_types.h" +#include "ll_defs.h" +#include "cfg_mac_ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \addtogroup BB_BLE_DRV_ENC + * \{ + */ + +/*! \brief Nonce modes. */ +enum +{ + BB_NONCE_MODE_PKT_CNTR, /*!< Packet counter mode (default). */ + BB_NONCE_MODE_EVT_CNTR /*!< Event counter mode, BbBleEnc_t::pEventCounter must be non-NULL. */ +}; + +/*! \brief Bluetooth Low Energy encryption data. */ +typedef struct +{ + /* SK placed here for 32-bit alignment. */ + uint8_t sk[LL_KEY_LEN]; /*!< Session/Encryption key. */ + uint8_t iv[LL_IV_LEN]; /*!< Initialization vector. */ + bool_t enaEncrypt; /*!< Tx/Encryption enabled flag. */ + bool_t enaDecrypt; /*!< Rx/Decryption enabled flag. */ + bool_t enaAuth; /*!< Enable authentication. */ + uint8_t nonceMode; /*!< Nonce mode. */ + uint16_t *pEventCounter; /*!< Connection event counter. */ + uint8_t dir; /*!< Direction value. */ + void *pEncryptCtx; /*!< Tx/Encryption context. */ + void *pDecryptCtx; /*!< Rx/Decryption context. */ +} BbBleEnc_t; + +/*! \} */ /* BB_BLE_DRV_ENC */ + +/*! \addtogroup BB_BLE_DRV_CHAN + * \{ */ + +/*! \brief BLE channelization parameters. */ +typedef struct +{ + uint8_t opType; /*!< Operation type. */ + uint8_t chanIdx; /*!< Channel index. */ + int8_t txPower; /*!< Transmit power, units dBm. */ + uint32_t accAddr; /*!< Access address. */ + uint32_t crcInit; /*!< CRC initialization value. */ + uint8_t txPhy; /*!< Transmitter PHY. */ + uint8_t rxPhy; /*!< Receiver PHY. */ + uint8_t initTxPhyOptions; /*!< Initial Tx PHY options. */ + uint8_t tifsTxPhyOptions; /*!< TIFS Tx PHY options. */ + bool_t peerTxStableModIdx; /*!< Peer uses stable modulation index on transmitter. */ + bool_t peerRxStableModIdx; /*!< Peer uses stable modulation index on receiver. */ + BbBleEnc_t enc; /*!< Encryption parameters (NULL if disabled). */ + +#if (LL_ENABLE_TESTER) + uint32_t accAddrRx; /*!< Access address override for receptions. */ + uint32_t accAddrTx; /*!< Access address override for transmissions. */ + uint32_t crcInitRx; /*!< CRC initialization override for receptions. */ + uint32_t crcInitTx; /*!< CRC initialization override for transmissions. */ +#endif +} BbBleDrvChan_t; + +/*! \} */ /* BB_BLE_DRV_CHAN */ + +/*! \addtogroup BB_BLE_DRV_DATA + * \{ + * This section contains driver routines used for packet transmission. + */ + +/*! \brief Transmit complete ISR callback signature. */ +typedef void (*BbBleDrvTxIsr_t)(uint8_t status); + +/*! \brief Receive complete ISR callback signature. */ +typedef void (*BbBleDrvRxIsr_t)(uint8_t status, int8_t rssi, uint32_t crc, uint32_t timestamp, uint8_t rxPhyOptions); + +/*! \brief BLE data transfer parameters. */ +typedef struct +{ + BbBleDrvTxIsr_t txCback; /*!< Transmit completion callback. */ + BbBleDrvRxIsr_t rxCback; /*!< Receive completion callback. */ + + uint32_t due; /*!< Due time of the first packet. */ + uint32_t rxTimeoutUsec; /*!< Receive timeout in microseconds. */ + uint16_t dueOffsetUsec; /*!< Due time offset in microseconds. */ +} BbBleDrvDataParam_t; + +/*! \brief Operation parameters. */ +typedef struct +{ + bool_t ifsSetup; /*!< TRUE if IFS timer should be set up for next operation. */ + uint16_t ifsUsec; /*!< IFS time in microseconds. */ +} BbBleDrvOpParam_t; + +/*! \brief Transmit buffer descriptor. */ +typedef struct +{ + uint16_t len; /*!< Length of buffer. */ + uint8_t *pBuf; /*!< Pointer to buffer. */ +} BbBleDrvTxBufDesc_t; + +/*! \} */ /* BB_BLE_DRV_DATA */ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*! \addtogroup BB_BLE_DRV_INIT + * \{ + * This section contains driver routines which initialize as well as enable the BLE mode of the + * BB hardware. + */ + +/*************************************************************************************************/ +/*! + * \brief Initialize the BLE baseband driver. + * + * \return None. + * + * One-time initialization of BLE baseband driver. + */ +/*************************************************************************************************/ +void BbBleDrvInit(void); + +/*************************************************************************************************/ +/*! + * \brief Enable the BB hardware. + * + * \return None. + * + * Wake the BB hardware out of sleep and enable for operation. All BB functionality is + * available when this routine completes. BB clock is set to zero and started. + */ +/*************************************************************************************************/ +void BbBleDrvEnable(void); + +/*************************************************************************************************/ +/*! + * \brief Disable the BB hardware. + * + * \return None. + * + * Disable the baseband and put radio hardware to sleep. Must be called from an idle state. + * A radio operation cannot be in progress. + */ +/*************************************************************************************************/ +void BbBleDrvDisable(void); + +/*! \} */ /* BB_BLE_DRV_INIT */ + +/*! \addtogroup BB_BLE_DRV_CHAN + * \{ + * This section contains the driver routine used to set the chanelization parameters. + */ + +/*************************************************************************************************/ +/*! + * \brief Set channelization parameters. + * + * \param pChan Channelization parameters. + * + * \return None. + * + * Calling this routine will set parameters for all future transmit and receive operations + * until this routine is called again providing new parameters. + * + * The setting of channelization parameters influence the operations of the following listed + * routines. Therefore, this routine is called to set the channel characteristics before + * the use of data routines described in \a BB_BLE_DRV_DATA. + * + * \note The \a pParam contents are not guaranteed to be static and is only valid in the + * context of the call to this routine. Therefore parameters requiring persistence + * should be copied. + */ +/*************************************************************************************************/ +void BbBleDrvSetChannelParam(BbBleDrvChan_t *pChan); + +/*! \} */ /* BB_BLE_DRV_CHAN */ + +/*! \addtogroup BB_BLE_DRV_DATA + * \{ + * This section contains driver routines used for packet transmission. + */ + +/*************************************************************************************************/ +/*! + * \brief Set the data packet exchange parameters. + * + * \param pParam Data exchange parameters. + * + * \return None. + * + * Calling this routine will set parameters for all future transmit and receive operations + * until this routine is called again providing new parameters. + */ +/*************************************************************************************************/ +void BbBleDrvSetDataParams(const BbBleDrvDataParam_t *pParam); + +/*************************************************************************************************/ +/*! + * \brief Set the operation parameters. + * + * \param pOpParam Operations parameters. + * + * \return None. + * + * Calling this routine will set parameters for the next transmit or receive operations. + */ +/*************************************************************************************************/ +void BbBleDrvSetOpParams(const BbBleDrvOpParam_t *pOpParam); + +/*************************************************************************************************/ +/*! + * \brief Transmit a packet. + * + * \param descs Array of transmit buffer descriptors. + * \param cnt Number of descriptors. + * + * \return None. + * + * Set the first data buffer for the first packet of an alternating Tx-Rx data exchange cycle. + */ +/*************************************************************************************************/ +void BbBleDrvTxData(BbBleDrvTxBufDesc_t descs[], uint8_t cnt); + +/*************************************************************************************************/ +/*! + * \brief Transmit packet at TIFS after the last packet received. + * + * \param descs Array of transmit buffer descriptor. + * \param cnt Number of descriptors. + * + * \return None. + * + * If possible, the transmit will occur at the TIFS timing. If not possible, the callback status + * will indicate this. + */ +/*************************************************************************************************/ +void BbBleDrvTxTifsData(BbBleDrvTxBufDesc_t descs[], uint8_t cnt); + +/*************************************************************************************************/ +/*! + * \brief Receive packet. + * + * \param pBuf Receive data buffer. + * \param len Length of data buffer. + * + * \return None. + * + * Set the first data buffer for the first packet of an alternating Rx-Tx data exchange cycle. + */ +/*************************************************************************************************/ +void BbBleDrvRxData(uint8_t *pBuf, uint16_t len); + +/*************************************************************************************************/ +/*! + * \brief Receive packet at TIFS after the last packet transmitted. + * + * \param pBuf Receive data buffer. + * \param len Length of data buffer. + * + * \return None. + * + * If possible, the receive will occur on the TIFS timing. If not possible, the callback status + * will indicate this. + */ +/*************************************************************************************************/ +void BbBleDrvRxTifsData(uint8_t *pBuf, uint16_t len); + +/*************************************************************************************************/ +/*! + * \brief Cancel TIFS timer. + * + * \return None. + * + * This stops any active TIFS timer operation. This routine is always called in the callback + * (i.e. ISR) context. + */ +/*************************************************************************************************/ +void BbBleDrvCancelTifs(void); + +/*************************************************************************************************/ +/*! + * \brief Cancel a pending transmit or receive. + * + * \return None. + * + * This stops any active radio operation. This routine is never called in the callback + * (i.e. ISR) context. + */ +/*************************************************************************************************/ +void BbBleDrvCancelData(void); + +/*! \} */ /* BB_BLE_DRV_DATA */ + +/*! \addtogroup BB_BLE_DRV_ENC + * \{ + * This section contains driver routines used for encryption. + */ + +/*************************************************************************************************/ +/*! + * \brief Generate cryptographic grade random number. + * + * \param pBuf Buffer to store random number. + * \param len Number of bytes. + * + * \return None. + */ +/*************************************************************************************************/ +void BbBleDrvRand(uint8_t *pBuf, uint8_t len); + +/*************************************************************************************************/ +/*! + * \brief Execute AES CBC transformation on payload and add 4 byte MIC. + * + * \param pEnc Encryption parameters. + * \param id Context ID. + * \param localDir Direction bit of local device (0=slave, 1=master). + * + * \return None. + * + * This routine completes the transformation in a blocking manner. + * + * \note Leave this implementation empty if inline hardware encryption is available. + */ +/*************************************************************************************************/ +void BbBleDrvAesInitCipherBlock(BbBleEnc_t *pEnc, uint8_t id, uint8_t localDir); + +/*************************************************************************************************/ +/*! + * \brief Execute AES CBC transformation on payload and add 4 byte MIC. + * + * \param pEnc Encryption parameters. + * \param pHdr Packet header. + * \param pBuf Packet data. + * \param pMic Storage for MIC. + * + * \return TRUE if the MIC was set. + * + * This routine completes the transformation in a blocking manner. This routine modifies the + * length field of the PDU to account for the MIC. + * + * \note Leave this implementation empty if inline hardware encryption is available. + */ +/*************************************************************************************************/ +bool_t BbBleDrvAesCcmEncrypt(BbBleEnc_t *pEnc, uint8_t *pHdr, uint8_t *pBuf, uint8_t *pMic); + +/*************************************************************************************************/ +/*! + * \brief Execute AES CBC transformation on payload and return MIC evaluation status. + * + * \param pEnc Encryption parameters. + * \param pBuf Packet data. + * + * \return TRUE if authentication successful, FALSE otherwise. + * + * This routine completes the transformation in a blocking manner. This routine modifies the + * length field of the PDU to account for the MIC. + * + * \note Leave this implementation empty if inline hardware encryption is available. + */ +/*************************************************************************************************/ +bool_t BbBleDrvAesCcmDecrypt(BbBleEnc_t *pEnc, uint8_t *pBuf); + +#if (BB_ENABLE_INLINE_ENC_TX) +void BbBleDrvSetEncryptPacketCount(BbBleEnc_t *pEnc, uint64_t pktCnt); +void BbBleDrvSetDecryptPacketCount(BbBleEnc_t *pEnc, uint64_t pktCnt); +#endif + +/*! \} */ /* BB_BLE_DRV_ENC */ + +/*! \addtogroup BB_BLE_DRV_TEST + * \{ + * This section contains driver routines used for test modes. + */ + +/*************************************************************************************************/ +/*! + * \brief Enable or disable data whitening. + * + * \param enable Flag to indicate data whitening. + * + * \return None. + * + * Sets an internal variable that indicates if data whitening is enabled or not. + */ +/*************************************************************************************************/ +void BbBleDrvEnableDataWhitening(bool_t enable); + +/*************************************************************************************************/ +/*! + * \brief Enable or disable PRBS15. + * + * \param enable Flag to indicate PRBS15. + * + * \return None. + * + * Immediately enable or disable continuous PRBS15 bitstream. Setting the channelization + * parameters with \a BbBleDrvSetChannelParam() must precede enabling PRBS15. + * + * Use of \a BB_BLE_DRV_DATA routines is not allowed while PRBS15 is enabled. + */ +/*************************************************************************************************/ +void BbBleDrvEnablePrbs15(bool_t enable); + +/*! \} */ /* BB_BLE_DRV_TEST */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_DRV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_drv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_drv.h new file mode 100644 index 0000000000..4eaca6aabd --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/bb_drv.h @@ -0,0 +1,136 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband driver interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_DRV_H +#define BB_DRV_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*! \addtogroup BB_DRV_INIT + * \{ + * This section contains driver routines which initialize as well as enable the sleep mode + * of the BB hardware. + */ + +/*************************************************************************************************/ +/*! + * \brief Initialize the baseband driver. + * + * \return None. + * + * One-time initialization of baseband resources. This routine can be used to setup baseband + * resources, load RF trim parameters and execute RF calibrations and seed the random number + * generator. + * + * This routine should block until the BB hardware is completely initialized. + */ +/*************************************************************************************************/ +void BbDrvInit(void); + +/*************************************************************************************************/ +/*! + * \brief Enable the BB hardware. + * + * \return None. + * + * This routine brings the BB hardware out of low power (enable power and clocks) just before a + * first BB operation is executed. + */ +/*************************************************************************************************/ +void BbDrvEnable(void); + +/*************************************************************************************************/ +/*! + * \brief Disable the BB hardware. + * + * \return None. + * + * This routine signals the BB hardware to go into low power (disable power and clocks) after all + * BB operations have been disabled. + */ +/*************************************************************************************************/ +void BbDrvDisable(void); + +/*************************************************************************************************/ +/*! + * \brief Get version codes. + * + * \param pBbVer If non-NULL, return BB hardware version. + * \param pPhyVer If non-NULL, return PHY hardware version. + * + * \return None. + * + * Interrogate the HW for version codes. + */ +/*************************************************************************************************/ +void BbDrvGetVersions(uint32_t *pBbVer, uint32_t *pPhyVer); + +/*! \} */ /* BB_DRV_INIT */ + +/*! \addtogroup BB_DRV_CLOCK + * \{ + * This section contains driver routines related to the BB clock. + */ + +/*************************************************************************************************/ +/*! + * \brief Get the current BB clock value. + * + * \return Current BB clock value. + * + * This routine reads the current value from the BB clock and returns its value. The clock should + * increment at the rate BB_CLK_RATE_HZ (wrapping as appropriate) whenever the BB is enabled. + */ +/*************************************************************************************************/ +uint32_t BbDrvGetCurrentTime(void); + +/*************************************************************************************************/ +/*! + * \brief Get the current FRC time. + * + * \param pTime Pointer to return the current time. + * + * \return TRUE if time is valid, FALSE otherwise. + * + * Get the current FRC time. + * + * \note FRC is limited to the same bit-width as the BB clock. Return value is available + * only when the BB is active. + */ +/*************************************************************************************************/ +bool_t BbDrvGetTimestamp(uint32_t *pTime); + +/*! \} */ /* BB_DRV_CLOCK */ + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_DRV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_api.h new file mode 100644 index 0000000000..ebf0dcd474 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_api.h @@ -0,0 +1,148 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Controller HCI transport API. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CHCI_API_H +#define CHCI_API_H + +#include "wsf_types.h" +#include "wsf_os.h" +#include "cfg_mac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \brief Protocols that source and sink messages. */ +enum +{ + CHCI_TR_PROT_BLE = 0, /*!< BLE protocol. */ + CHCI_TR_PROT_BOOT = 1, /*!< Boot protocol. */ + CHCI_TR_PROT_15P4 = 2, /*!< 802.15.4 protocol */ + CHCI_TR_PROT_NUM /*!< Number of protocols. */ +}; + +/*! \brief Type of message. */ +enum +{ + CHCI_TR_TYPE_CMD = 0, /*!< Command message (receive only). */ + CHCI_TR_TYPE_DATA, /*!< Data message (send or receive). */ + CHCI_TR_TYPE_EVT, /*!< Event message (send only). */ + CHCI_TR_TYPE_NUM /*!< Number of types. */ +}; + +/*! \brief Error codes. */ +enum +{ + CHCI_TR_CODE_INVALID_DATA = 0xA0, /*!< Invalid data received. */ + CHCI_TR_CODE_OUT_OF_MEMORY = 0xA1 /*!< Out of memory. */ +}; + +/*! \brief 802.15.4 protocol command type. */ +#define CHCI_15P4_CMD_TYPE 0x80 + +/*! \brief 802.15.4 protocol data type. */ +#define CHCI_15P4_DATA_TYPE 0x81 + +/*! \brief 802.15.4 protocol header length. */ +#define CHCI_15P4_HDR_LEN 3 + +/*! \brief Message received callback. */ +typedef void (*ChciTrRecvCback_t)(uint8_t type, uint8_t *pBuf); + +/*! \brief Message send complete callback. */ +typedef void (*ChciTrSendCompleteCback_t)(uint8_t type, uint8_t *pBuf); + +/*! \brief Service callback. */ +typedef bool_t (*ChciTrServiceCback_t)(uint8_t *pType, uint16_t *pLen, uint8_t **pBuf); + +/*! \brief Send hardware error callback. */ +typedef void (*ChciTrSendHwErrorCback_t)(uint8_t code); + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Initialize the transport handler. + * + * \param handlerId Handler ID. + * + * \return None. + */ +/*************************************************************************************************/ +void ChciTrHandlerInit(wsfHandlerId_t handlerId); + +/*************************************************************************************************/ +/*! + * \brief Controller HCI transport message dispatch handler. + * + * \param event WSF event. + * \param pMsg WSF message. + * + * \return None. + */ +/*************************************************************************************************/ +void ChciTrHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); + +/*************************************************************************************************/ +/*! + * \brief Set callbacks for a protocol. + * + * \param prot Protocol. + * \param recvCback Message received callback. + * \param sendCompleteCback Message send complete callback. + * \param serviceCback Service callback. + * + * \return None. + */ +/*************************************************************************************************/ +void ChciTrSetCbacks(uint8_t prot, ChciTrRecvCback_t recvCback, ChciTrSendCompleteCback_t sendCompleteCback, + ChciTrServiceCback_t serviceCback); + +/*************************************************************************************************/ +/*! + * \brief Set send hardware error callback. + * + * \param sendHwErrorCback Send hardware error callback. + * + * \return None. + */ +/*************************************************************************************************/ +void ChciTrSetSendHwErrorCback(ChciTrSendHwErrorCback_t sendHwErrorCback); + +/*************************************************************************************************/ +/*! + * \brief Flag protocol for needing service. + * + * \param prot Protocol. + * + * \return None. + */ +/*************************************************************************************************/ +void ChciTrNeedsService(uint8_t prot); + +#ifdef __cplusplus +}; +#endif + +#endif /* CHCI_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_drv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_drv.h new file mode 100644 index 0000000000..20de99ae9e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_drv.h @@ -0,0 +1,75 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Controller HCI driver interface. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CHCI_DRV_H +#define CHCI_DRV_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Initialize the driver. + * + * \return None. + */ +/*************************************************************************************************/ +void chciDrvInit(void); + +/*************************************************************************************************/ +/*! + * \brief Write data the driver. + * + * \param prot Protocol. + * \param type Packet type. + * \param len Number of bytes to write. + * \param pData Byte array to write. + * + * \return Return actual number of data bytes written. + * + * \note The type parameter allows the driver layer to prepend the data with a header on the + * same write transaction. + */ +/*************************************************************************************************/ +uint16_t chciDrvWrite(uint8_t prot, uint8_t type, uint16_t len, uint8_t *pData); + +/*************************************************************************************************/ +/*! + * \brief Service the transport device. + * + * \return TRUE if work pending, FALSE if no work is pending. + */ +/*************************************************************************************************/ +bool_t chciDrvService(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* CHCI_DRV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr.h new file mode 100644 index 0000000000..7c12ef408f --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr.h @@ -0,0 +1,77 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Controller HCI transport interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CHCI_TR_H +#define CHCI_TR_H + +#include "wsf_types.h" +#include "wsf_os.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Signal the completion of a message write. + * + * \return None. + * + * This routine is used for asynchronous write operations. When the driver has completed the + * use of the write buffer, this routine is called to free the buffer and release flow control. + */ +/*************************************************************************************************/ +void chciTrSendComplete(void); + +/*************************************************************************************************/ +/*! + * \brief Signal the completion of a message receive. + * + * \param prot Protocol. + * \param type Message type. + * \param pBuf Message. + * + * \return None. + */ +/*************************************************************************************************/ +void chciTrRecv(uint8_t prot, uint8_t type, uint8_t *pBuf); + +/*************************************************************************************************/ +/*! + * \brief Signal a hardware error. + * + * \param code Error code. + * + * \return None. + */ +/*************************************************************************************************/ +void chciTrHwError(uint8_t code); + +#ifdef __cplusplus +}; +#endif + +#endif /* CHCI_TR_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr_serial.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr_serial.h new file mode 100644 index 0000000000..b55dd2e17b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/chci_tr_serial.h @@ -0,0 +1,48 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Controller HCI serial transport interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CHCI_TR_SERIAL_H +#define CHCI_TR_SERIAL_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************************************/ +/*! + * \brief Receive function. Gets called by external code when bytes are received. + * + * \param pBuf Pointer to buffer of incoming bytes. + * \param len Number of bytes in incoming buffer. + * + * \return None. + */ +/*************************************************************************************************/ +void chciTrSerialRxIncoming(uint8_t *pBuf, uint8_t len); + +#ifdef __cplusplus +}; +#endif + +#endif /* CHCI_TR_SERIAL_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/hci_defs.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/hci_defs.h new file mode 100644 index 0000000000..0566258a86 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/hci_defs.h @@ -0,0 +1,1094 @@ +/*************************************************************************************************/ +/*! + * \file hci_defs.h + * + * \brief HCI constants and definitions from the Bluetooth specification. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ +#ifndef HCI_DEFS_H +#define HCI_DEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \addtogroup STACK_HCI_API + * \{ */ + +/** \name Packet definitions + * + */ +/**@{*/ +#define HCI_CMD_HDR_LEN 3 /*!< \brief Command packet header length */ +#define HCI_ACL_HDR_LEN 4 /*!< \brief ACL packet header length */ +#define HCI_EVT_HDR_LEN 2 /*!< \brief Event packet header length */ +#define HCI_EVT_PARAM_MAX_LEN 255 /*!< \brief Maximum length of event packet parameters */ +#define HCI_ACL_DEFAULT_LEN 27 /*!< \brief Default maximum ACL packet length */ +#define HCI_PB_FLAG_MASK 0x3000 /*!< \brief ACL packet boundary flag mask */ +#define HCI_PB_START_H2C 0x0000 /*!< \brief Packet boundary flag, start, host-to-controller */ +#define HCI_PB_CONTINUE 0x1000 /*!< \brief Packet boundary flag, continue */ +#define HCI_PB_START_C2H 0x2000 /*!< \brief Packet boundary flag, start, controller-to-host */ +#define HCI_HANDLE_MASK 0x0FFF /*!< \brief Mask for handle bits in ACL packet */ +#define HCI_HANDLE_NONE 0xFFFF /*!< \brief Value for invalid handle */ +/**@}*/ + +/** \name Packet types + * + */ +#define HCI_CMD_TYPE 1 /*!< \brief HCI command packet */ +#define HCI_ACL_TYPE 2 /*!< \brief HCI ACL data packet */ +#define HCI_EVT_TYPE 4 /*!< \brief HCI event packet */ +/**@}*/ + +/** \name Error codes + * + */ +/**@{*/ +#define HCI_SUCCESS 0x00 /*!< \brief Success */ +#define HCI_ERR_UNKNOWN_CMD 0x01 /*!< \brief Unknown HCI command */ +#define HCI_ERR_UNKNOWN_HANDLE 0x02 /*!< \brief Unknown connection identifier */ +#define HCI_ERR_HARDWARE_FAILURE 0x03 /*!< \brief Hardware failure */ +#define HCI_ERR_PAGE_TIMEOUT 0x04 /*!< \brief Page timeout */ +#define HCI_ERR_AUTH_FAILURE 0x05 /*!< \brief Authentication failure */ +#define HCI_ERR_KEY_MISSING 0x06 /*!< \brief PIN or key missing */ +#define HCI_ERR_MEMORY_EXCEEDED 0x07 /*!< \brief Memory capacity exceeded */ +#define HCI_ERR_CONN_TIMEOUT 0x08 /*!< \brief Connection timeout */ +#define HCI_ERR_CONN_LIMIT 0x09 /*!< \brief Connection limit exceeded */ +#define HCI_ERR_SYNCH_CONN_LIMIT 0x0A /*!< \brief Synchronous connection limit exceeded */ +#define HCI_ERR_ACL_CONN_EXISTS 0x0B /*!< \brief ACL connection already exists */ +#define HCI_ERR_CMD_DISALLOWED 0x0C /*!< \brief Command disallowed */ +#define HCI_ERR_REJ_RESOURCES 0x0D /*!< \brief Connection rejected limited resources */ +#define HCI_ERR_REJ_SECURITY 0x0E /*!< \brief Connection rejected security reasons */ +#define HCI_ERR_REJ_BD_ADDR 0x0F /*!< \brief Connection rejected unacceptable BD_ADDR */ +#define HCI_ERR_ACCEPT_TIMEOUT 0x10 /*!< \brief Connection accept timeout exceeded */ +#define HCI_ERR_UNSUP_FEAT 0x11 /*!< \brief Unsupported feature or parameter value */ +#define HCI_ERR_INVALID_PARAM 0x12 /*!< \brief Invalid HCI command parameters */ +#define HCI_ERR_REMOTE_TERMINATED 0x13 /*!< \brief Remote user terminated connection */ +#define HCI_ERR_REMOTE_RESOURCES 0x14 /*!< \brief Remote device low resources */ +#define HCI_ERR_REMOTE_POWER_OFF 0x15 /*!< \brief Remote device power off */ +#define HCI_ERR_LOCAL_TERMINATED 0x16 /*!< \brief Connection terminated by local host */ +#define HCI_ERR_REPEATED_ATTEMPTS 0x17 /*!< \brief Repeated attempts */ +#define HCI_ERR_PAIRING_NOT_ALLOWED 0x18 /*!< \brief Pairing not allowed */ +#define HCI_ERR_UNKNOWN_LMP_PDU 0x19 /*!< \brief Unknown LMP PDU */ +#define HCI_ERR_UNSUP_REMOTE_FEAT 0x1A /*!< \brief Unsupported remote feature */ +#define HCI_ERR_SCO_OFFSET 0x1B /*!< \brief SCO offset rejected */ +#define HCI_ERR_SCO_INTERVAL 0x1C /*!< \brief SCO interval rejected */ +#define HCI_ERR_SCO_MODE 0x1D /*!< \brief SCO air mode rejected */ +#define HCI_ERR_LMP_PARAM 0x1E /*!< \brief Invalid LMP parameters */ +#define HCI_ERR_UNSPECIFIED 0x1F /*!< \brief Unspecified error */ +#define HCI_ERR_UNSUP_LMP_PARAM 0x20 /*!< \brief Unsupported LMP parameter value */ +#define HCI_ERR_ROLE_CHANGE 0x21 /*!< \brief Role change not allowed */ +#define HCI_ERR_LL_RESP_TIMEOUT 0x22 /*!< \brief LL response timeout */ +#define HCI_ERR_LMP_COLLISION 0x23 /*!< \brief LMP error transaction collision */ +#define HCI_ERR_LMP_PDU 0x24 /*!< \brief LMP pdu not allowed */ +#define HCI_ERR_ENCRYPT_MODE 0x25 /*!< \brief Encryption mode not acceptable */ +#define HCI_ERR_LINK_KEY 0x26 /*!< \brief Link key can not be changed */ +#define HCI_ERR_UNSUP_QOS 0x27 /*!< \brief Requested qos not supported */ +#define HCI_ERR_INSTANT_PASSED 0x28 /*!< \brief Instant passed */ +#define HCI_ERR_UNSUP_UNIT_KEY 0x29 /*!< \brief Pairing with unit key not supported */ +#define HCI_ERR_TRANSACT_COLLISION 0x2A /*!< \brief Different transaction collision */ +#define HCI_ERR_CHANNEL_CLASS 0x2E /*!< \brief Channel classification not supported */ +#define HCI_ERR_MEMORY 0x2F /*!< \brief Insufficient security */ +#define HCI_ERR_PARAMETER_RANGE 0x30 /*!< \brief Parameter out of mandatory range */ +#define HCI_ERR_ROLE_SWITCH_PEND 0x32 /*!< \brief Role switch pending */ +#define HCI_ERR_RESERVED_SLOT 0x34 /*!< \brief Reserved slot violation */ +#define HCI_ERR_ROLE_SWITCH 0x35 /*!< \brief Role switch failed */ +#define HCI_ERR_INQ_TOO_LARGE 0x36 /*!< \brief Extended inquiry response too large */ +#define HCI_ERR_UNSUP_SSP 0x37 /*!< \brief Secure simple pairing not supported by host */ +#define HCI_ERR_HOST_BUSY_PAIRING 0x38 /*!< \brief Host busy - pairing */ +#define HCI_ERR_NO_CHANNEL 0x39 /*!< \brief Connection rejected no suitable channel */ +#define HCI_ERR_CONTROLLER_BUSY 0x3A /*!< \brief Controller busy */ +#define HCI_ERR_CONN_INTERVAL 0x3B /*!< \brief Unacceptable connection interval */ +#define HCI_ERR_ADV_TIMEOUT 0x3C /*!< \brief Advertising timeout */ +#define HCI_ERR_MIC_FAILURE 0x3D /*!< \brief Connection terminated due to MIC failure */ +#define HCI_ERR_CONN_FAIL 0x3E /*!< \brief Connection failed to be established */ +#define HCI_ERR_MAC_CONN_FAIL 0x3F /*!< \brief MAC connection failed */ +#define HCI_ERR_COARSE_CLK_ADJ_REJ 0x40 /*!< \brief Coarse clock adjustment rejected */ +#define HCI_ERR_TYPE0_SUBMAP_NOT_DEF 0x41 /*!< \brief Type0 submap not defined */ +#define HCI_ERR_UNKNOWN_ADV_ID 0x42 /*!< \brief Unknown advertising identifier */ +#define HCI_ERR_LIMIT_REACHED 0x43 /*!< \brief Limit reached */ +#define HCI_ERR_OP_CANCELLED_BY_HOST 0x44 /*!< \brief Operation cancelled by host */ +/**@}*/ + +/** \name Command groups + * + */ +/**@{*/ +#define HCI_OGF_NOP 0x00 /*!< \brief No operation */ +#define HCI_OGF_LINK_CONTROL 0x01 /*!< \brief Link control */ +#define HCI_OGF_LINK_POLICY 0x02 /*!< \brief Link policy */ +#define HCI_OGF_CONTROLLER 0x03 /*!< \brief Controller and baseband */ +#define HCI_OGF_INFORMATIONAL 0x04 /*!< \brief Informational parameters */ +#define HCI_OGF_STATUS 0x05 /*!< \brief Status parameters */ +#define HCI_OGF_TESTING 0x06 /*!< \brief Testing */ +#define HCI_OGF_LE_CONTROLLER 0x08 /*!< \brief LE controller */ +#define HCI_OGF_VENDOR_SPEC 0x3F /*!< \brief Vendor specific */ +/**@}*/ + +/** \name NOP command + * + */ +/**@{*/ +#define HCI_OCF_NOP 0x00 +/**@}*/ + +/** \name Link control commands + * + */ +/**@{*/ +#define HCI_OCF_DISCONNECT 0x06 +#define HCI_OCF_READ_REMOTE_VER_INFO 0x1D +/**@}*/ + +/*! \brief Link policy commands (none used for LE) */ + +/** \name Controller and baseband commands + * + */ +/**@{*/ +#define HCI_OCF_SET_EVENT_MASK 0x01 +#define HCI_OCF_RESET 0x03 +#define HCI_OCF_READ_TX_PWR_LVL 0x2D +#define HCI_OCF_SET_CONTROLLER_TO_HOST_FC 0x31 +#define HCI_OCF_HOST_BUFFER_SIZE 0x33 +#define HCI_OCF_HOST_NUM_CMPL_PKTS 0x35 +#define HCI_OCF_SET_EVENT_MASK_PAGE2 0x63 +#define HCI_OCF_READ_AUTH_PAYLOAD_TO 0x7B +#define HCI_OCF_WRITE_AUTH_PAYLOAD_TO 0x7C +/**@}*/ + +/** \name Informational commands + * + */ +/**@{*/ +#define HCI_OCF_READ_LOCAL_VER_INFO 0x01 +#define HCI_OCF_READ_LOCAL_SUP_CMDS 0x02 +#define HCI_OCF_READ_LOCAL_SUP_FEAT 0x03 +#define HCI_OCF_READ_BUF_SIZE 0x05 +#define HCI_OCF_READ_BD_ADDR 0x09 +/**@}*/ + +/** \name Status commands + * + */ +/**@{*/ +#define HCI_OCF_READ_RSSI 0x05 +/**@}*/ + +/** \name LE controller commands + * + */ +/**@{*/ +#define HCI_OCF_LE_SET_EVENT_MASK 0x01 +#define HCI_OCF_LE_READ_BUF_SIZE 0x02 +#define HCI_OCF_LE_READ_LOCAL_SUP_FEAT 0x03 +#define HCI_OCF_LE_SET_RAND_ADDR 0x05 +#define HCI_OCF_LE_SET_ADV_PARAM 0x06 +#define HCI_OCF_LE_READ_ADV_TX_POWER 0x07 +#define HCI_OCF_LE_SET_ADV_DATA 0x08 +#define HCI_OCF_LE_SET_SCAN_RESP_DATA 0x09 +#define HCI_OCF_LE_SET_ADV_ENABLE 0x0A +#define HCI_OCF_LE_SET_SCAN_PARAM 0x0B +#define HCI_OCF_LE_SET_SCAN_ENABLE 0x0C +#define HCI_OCF_LE_CREATE_CONN 0x0D +#define HCI_OCF_LE_CREATE_CONN_CANCEL 0x0E +#define HCI_OCF_LE_READ_WHITE_LIST_SIZE 0x0F +#define HCI_OCF_LE_CLEAR_WHITE_LIST 0x10 +#define HCI_OCF_LE_ADD_DEV_WHITE_LIST 0x11 +#define HCI_OCF_LE_REMOVE_DEV_WHITE_LIST 0x12 +#define HCI_OCF_LE_CONN_UPDATE 0x13 +#define HCI_OCF_LE_SET_HOST_CHAN_CLASS 0x14 +#define HCI_OCF_LE_READ_CHAN_MAP 0x15 +#define HCI_OCF_LE_READ_REMOTE_FEAT 0x16 +#define HCI_OCF_LE_ENCRYPT 0x17 +#define HCI_OCF_LE_RAND 0x18 +#define HCI_OCF_LE_START_ENCRYPTION 0x19 +#define HCI_OCF_LE_LTK_REQ_REPL 0x1A +#define HCI_OCF_LE_LTK_REQ_NEG_REPL 0x1B +#define HCI_OCF_LE_READ_SUP_STATES 0x1C +#define HCI_OCF_LE_RECEIVER_TEST 0x1D +#define HCI_OCF_LE_TRANSMITTER_TEST 0x1E +#define HCI_OCF_LE_TEST_END 0x1F +/*! \brief New in version 4.1 */ +#define HCI_OCF_LE_REM_CONN_PARAM_REP 0x20 +#define HCI_OCF_LE_REM_CONN_PARAM_NEG_REP 0x21 +/*! \brief New in version 4.2 */ +#define HCI_OCF_LE_SET_DATA_LEN 0x22 +#define HCI_OCF_LE_READ_DEF_DATA_LEN 0x23 +#define HCI_OCF_LE_WRITE_DEF_DATA_LEN 0x24 +#define HCI_OCF_LE_READ_LOCAL_P256_PUB_KEY 0x25 +#define HCI_OCF_LE_GENERATE_DHKEY 0x26 +#define HCI_OCF_LE_ADD_DEV_RES_LIST 0x27 +#define HCI_OCF_LE_REMOVE_DEV_RES_LIST 0x28 +#define HCI_OCF_LE_CLEAR_RES_LIST 0x29 +#define HCI_OCF_LE_READ_RES_LIST_SIZE 0x2A +#define HCI_OCF_LE_READ_PEER_RES_ADDR 0x2B +#define HCI_OCF_LE_READ_LOCAL_RES_ADDR 0x2C +#define HCI_OCF_LE_SET_ADDR_RES_ENABLE 0x2D +#define HCI_OCF_LE_SET_RES_PRIV_ADDR_TO 0x2E +#define HCI_OCF_LE_READ_MAX_DATA_LEN 0x2F +/*! \brief New in version 5.0 */ +#define HCI_OCF_LE_READ_PHY 0x30 +#define HCI_OCF_LE_SET_DEF_PHY 0x31 +#define HCI_OCF_LE_SET_PHY 0x32 +#define HCI_OCF_LE_ENHANCED_RECEIVER_TEST 0x33 +#define HCI_OCF_LE_ENHANCED_TRANSMITTER_TEST 0x34 +#define HCI_OCF_LE_SET_ADV_SET_RAND_ADDR 0x35 +#define HCI_OCF_LE_SET_EXT_ADV_PARAM 0x36 +#define HCI_OCF_LE_SET_EXT_ADV_DATA 0x37 +#define HCI_OCF_LE_SET_EXT_SCAN_RESP_DATA 0x38 +#define HCI_OCF_LE_SET_EXT_ADV_ENABLE 0x39 +#define HCI_OCF_LE_READ_MAX_ADV_DATA_LEN 0x3A +#define HCI_OCF_LE_READ_NUM_SUP_ADV_SETS 0x3B +#define HCI_OCF_LE_REMOVE_ADV_SET 0x3C +#define HCI_OCF_LE_CLEAR_ADV_SETS 0x3D +#define HCI_OCF_LE_SET_PER_ADV_PARAM 0x3E +#define HCI_OCF_LE_SET_PER_ADV_DATA 0x3F +#define HCI_OCF_LE_SET_PER_ADV_ENABLE 0x40 +#define HCI_OCF_LE_SET_EXT_SCAN_PARAM 0x41 +#define HCI_OCF_LE_SET_EXT_SCAN_ENABLE 0x42 +#define HCI_OCF_LE_EXT_CREATE_CONN 0x43 +#define HCI_OCF_LE_PER_ADV_CREATE_SYNC 0x44 +#define HCI_OCF_LE_PER_ADV_CREATE_SYNC_CANCEL 0x45 +#define HCI_OCF_LE_PER_ADV_TERM_SYNC 0x46 +#define HCI_OCF_LE_ADD_DEV_PER_ADV_LIST 0x47 +#define HCI_OCF_LE_REMOVE_DEV_PER_ADV_LIST 0x48 +#define HCI_OCF_LE_CLEAR_PER_ADV_LIST 0x49 +#define HCI_OCF_LE_READ_PER_ADV_LIST_SIZE 0x4A +#define HCI_OCF_LE_READ_TX_POWER 0x4B +#define HCI_OCF_LE_READ_RF_PATH_COMP 0x4C +#define HCI_OCF_LE_WRITE_RF_PATH_COMP 0x4D +#define HCI_OCF_LE_SET_PRIVACY_MODE 0x4E +/**@}*/ + +/** \name Opcode manipulation macros + * + */ +/**@{*/ +#define HCI_OPCODE(ogf, ocf) (((ogf) << 10) + (ocf)) +#define HCI_OGF(opcode) ((opcode) >> 10) +#define HCI_OCF(opcode) ((opcode) & 0x03FF) +/**@}*/ + +/** \name Command opcodes + * + */ +/**@{*/ +#define HCI_OPCODE_NOP HCI_OPCODE(HCI_OGF_NOP, HCI_OCF_NOP) + +#define HCI_OPCODE_DISCONNECT HCI_OPCODE(HCI_OGF_LINK_CONTROL, HCI_OCF_DISCONNECT) +#define HCI_OPCODE_READ_REMOTE_VER_INFO HCI_OPCODE(HCI_OGF_LINK_CONTROL, HCI_OCF_READ_REMOTE_VER_INFO) + +#define HCI_OPCODE_SET_EVENT_MASK HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_SET_EVENT_MASK) +#define HCI_OPCODE_RESET HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_RESET) +#define HCI_OPCODE_READ_TX_PWR_LVL HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_READ_TX_PWR_LVL) +#define HCI_OPCODE_SET_EVENT_MASK_PAGE2 HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_SET_EVENT_MASK_PAGE2) +#define HCI_OPCODE_READ_AUTH_PAYLOAD_TO HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_READ_AUTH_PAYLOAD_TO) +#define HCI_OPCODE_WRITE_AUTH_PAYLOAD_TO HCI_OPCODE(HCI_OGF_CONTROLLER, HCI_OCF_WRITE_AUTH_PAYLOAD_TO) + +#define HCI_OPCODE_READ_LOCAL_VER_INFO HCI_OPCODE(HCI_OGF_INFORMATIONAL, HCI_OCF_READ_LOCAL_VER_INFO) +#define HCI_OPCODE_READ_LOCAL_SUP_CMDS HCI_OPCODE(HCI_OGF_INFORMATIONAL, HCI_OCF_READ_LOCAL_SUP_CMDS) +#define HCI_OPCODE_READ_LOCAL_SUP_FEAT HCI_OPCODE(HCI_OGF_INFORMATIONAL, HCI_OCF_READ_LOCAL_SUP_FEAT) +#define HCI_OPCODE_READ_BUF_SIZE HCI_OPCODE(HCI_OGF_INFORMATIONAL, HCI_OCF_READ_BUF_SIZE) +#define HCI_OPCODE_READ_BD_ADDR HCI_OPCODE(HCI_OGF_INFORMATIONAL, HCI_OCF_READ_BD_ADDR) + +#define HCI_OPCODE_READ_RSSI HCI_OPCODE(HCI_OGF_STATUS, HCI_OCF_READ_RSSI) + +#define HCI_OPCODE_LE_SET_EVENT_MASK HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EVENT_MASK) +#define HCI_OPCODE_LE_READ_BUF_SIZE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_BUF_SIZE) +#define HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_LOCAL_SUP_FEAT) +#define HCI_OPCODE_LE_SET_RAND_ADDR HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_RAND_ADDR) +#define HCI_OPCODE_LE_SET_ADV_PARAM HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_ADV_PARAM) +#define HCI_OPCODE_LE_READ_ADV_TX_POWER HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_ADV_TX_POWER) +#define HCI_OPCODE_LE_SET_ADV_DATA HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_ADV_DATA) +#define HCI_OPCODE_LE_SET_SCAN_RESP_DATA HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_SCAN_RESP_DATA) +#define HCI_OPCODE_LE_SET_ADV_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_ADV_ENABLE) +#define HCI_OPCODE_LE_SET_SCAN_PARAM HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_SCAN_PARAM) +#define HCI_OPCODE_LE_SET_SCAN_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_SCAN_ENABLE) +#define HCI_OPCODE_LE_CREATE_CONN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CREATE_CONN) +#define HCI_OPCODE_LE_CREATE_CONN_CANCEL HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CREATE_CONN_CANCEL) +#define HCI_OPCODE_LE_READ_WHITE_LIST_SIZE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_WHITE_LIST_SIZE) +#define HCI_OPCODE_LE_CLEAR_WHITE_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CLEAR_WHITE_LIST) +#define HCI_OPCODE_LE_ADD_DEV_WHITE_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ADD_DEV_WHITE_LIST) +#define HCI_OPCODE_LE_REMOVE_DEV_WHITE_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REMOVE_DEV_WHITE_LIST) +#define HCI_OPCODE_LE_CONN_UPDATE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CONN_UPDATE) +#define HCI_OPCODE_LE_SET_HOST_CHAN_CLASS HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_HOST_CHAN_CLASS) +#define HCI_OPCODE_LE_READ_CHAN_MAP HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_CHAN_MAP) +#define HCI_OPCODE_LE_READ_REMOTE_FEAT HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_REMOTE_FEAT) +#define HCI_OPCODE_LE_ENCRYPT HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ENCRYPT) +#define HCI_OPCODE_LE_RAND HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_RAND) +#define HCI_OPCODE_LE_START_ENCRYPTION HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_START_ENCRYPTION) +#define HCI_OPCODE_LE_LTK_REQ_REPL HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_LTK_REQ_REPL) +#define HCI_OPCODE_LE_LTK_REQ_NEG_REPL HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_LTK_REQ_NEG_REPL) +#define HCI_OPCODE_LE_READ_SUP_STATES HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_SUP_STATES) +#define HCI_OPCODE_LE_RECEIVER_TEST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_RECEIVER_TEST) +#define HCI_OPCODE_LE_TRANSMITTER_TEST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_TRANSMITTER_TEST) +#define HCI_OPCODE_LE_TEST_END HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_TEST_END) +/*! \brief New in version 4.1 */ +#define HCI_OPCODE_LE_REM_CONN_PARAM_REP HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REM_CONN_PARAM_REP) +#define HCI_OPCODE_LE_REM_CONN_PARAM_NEG_REP HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REM_CONN_PARAM_NEG_REP) +/*! \brief New in version 4.2 */ +#define HCI_OPCODE_LE_SET_DATA_LEN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_DATA_LEN) +#define HCI_OPCODE_LE_READ_DEF_DATA_LEN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_DEF_DATA_LEN) +#define HCI_OPCODE_LE_WRITE_DEF_DATA_LEN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_WRITE_DEF_DATA_LEN) +#define HCI_OPCODE_LE_READ_LOCAL_P256_PUB_KEY HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_LOCAL_P256_PUB_KEY) +#define HCI_OPCODE_LE_GENERATE_DHKEY HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_GENERATE_DHKEY) +#define HCI_OPCODE_LE_ADD_DEV_RES_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ADD_DEV_RES_LIST) +#define HCI_OPCODE_LE_REMOVE_DEV_RES_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REMOVE_DEV_RES_LIST) +#define HCI_OPCODE_LE_CLEAR_RES_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CLEAR_RES_LIST) +#define HCI_OPCODE_LE_READ_RES_LIST_SIZE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_RES_LIST_SIZE) +#define HCI_OPCODE_LE_READ_PEER_RES_ADDR HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_PEER_RES_ADDR) +#define HCI_OPCODE_LE_READ_LOCAL_RES_ADDR HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_LOCAL_RES_ADDR) +#define HCI_OPCODE_LE_SET_ADDR_RES_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_ADDR_RES_ENABLE) +#define HCI_OPCODE_LE_SET_RES_PRIV_ADDR_TO HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_RES_PRIV_ADDR_TO) +#define HCI_OPCODE_LE_READ_MAX_DATA_LEN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_MAX_DATA_LEN) +/*! \brief New in version 5.0 */ +#define HCI_OPCODE_LE_READ_PHY HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_PHY) +#define HCI_OPCODE_LE_SET_DEF_PHY HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_DEF_PHY) +#define HCI_OPCODE_LE_SET_PHY HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_PHY) +#define HCI_OPCODE_LE_ENHANCED_RECEIVER_TEST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ENHANCED_RECEIVER_TEST) +#define HCI_OPCODE_LE_ENHANCED_TRANSMITTER_TEST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ENHANCED_TRANSMITTER_TEST) +#define HCI_OPCODE_LE_SET_ADV_SET_RAND_ADDR HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_ADV_SET_RAND_ADDR) +#define HCI_OPCODE_LE_SET_EXT_ADV_PARAM HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_ADV_PARAM) +#define HCI_OPCODE_LE_SET_EXT_ADV_DATA HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_ADV_DATA) +#define HCI_OPCODE_LE_SET_EXT_SCAN_RESP_DATA HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_SCAN_RESP_DATA) +#define HCI_OPCODE_LE_SET_EXT_ADV_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_ADV_ENABLE) +#define HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_MAX_ADV_DATA_LEN) +#define HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_NUM_SUP_ADV_SETS) +#define HCI_OPCODE_LE_REMOVE_ADV_SET HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REMOVE_ADV_SET) +#define HCI_OPCODE_LE_CLEAR_ADV_SETS HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CLEAR_ADV_SETS) +#define HCI_OPCODE_LE_SET_PER_ADV_PARAM HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_PER_ADV_PARAM) +#define HCI_OPCODE_LE_SET_PER_ADV_DATA HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_PER_ADV_DATA) +#define HCI_OPCODE_LE_SET_PER_ADV_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_PER_ADV_ENABLE) +#define HCI_OPCODE_LE_SET_EXT_SCAN_PARAM HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_SCAN_PARAM) +#define HCI_OPCODE_LE_SET_EXT_SCAN_ENABLE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_EXT_SCAN_ENABLE) +#define HCI_OPCODE_LE_EXT_CREATE_CONN HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_EXT_CREATE_CONN) +#define HCI_OPCODE_LE_PER_ADV_CREATE_SYNC HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_PER_ADV_CREATE_SYNC) +#define HCI_OPCODE_LE_PER_ADV_CREATE_SYNC_CANCEL HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_PER_ADV_CREATE_SYNC_CANCEL) +#define HCI_OPCODE_LE_PER_ADV_TERMINATE_SYNC HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_PER_ADV_TERM_SYNC) +#define HCI_OPCODE_LE_ADD_DEV_PER_ADV_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_ADD_DEV_PER_ADV_LIST) +#define HCI_OPCODE_LE_REMOVE_DEV_PER_ADV_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_REMOVE_DEV_PER_ADV_LIST) +#define HCI_OPCODE_LE_CLEAR_PER_ADV_LIST HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_CLEAR_PER_ADV_LIST) +#define HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_PER_ADV_LIST_SIZE) +#define HCI_OPCODE_LE_READ_TX_POWER HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_TX_POWER) +#define HCI_OPCODE_LE_WRITE_RF_PATH_COMP HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_WRITE_RF_PATH_COMP) +#define HCI_OPCODE_LE_READ_RF_PATH_COMP HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_READ_RF_PATH_COMP) +#define HCI_OPCODE_LE_SET_PRIVACY_MODE HCI_OPCODE(HCI_OGF_LE_CONTROLLER, HCI_OCF_LE_SET_PRIVACY_MODE) +/**@}*/ + +/** \name ARM Vendor Specific + * + */ +/**@{*/ +#define HCI_OPCODE_LE_VS_ENABLE_READ_FEAT_ON_CONN ((uint16_t)(0xfff3)) +/**@}*/ + +/** \name Command parameter lengths + * + */ +/**@{*/ +#define HCI_LEN_NOP 0 + +#define HCI_LEN_DISCONNECT 3 +#define HCI_LEN_READ_REMOTE_VER_INFO 2 + +#define HCI_LEN_SET_EVENT_MASK 8 +#define HCI_LEN_SET_EVENT_MASK_PAGE2 8 +#define HCI_LEN_RESET 0 +#define HCI_LEN_READ_TX_PWR_LVL 3 +#define HCI_LEN_SET_CONTROLLER_TO_HOST_FC 1 +#define HCI_LEN_HOST_BUFFER_SIZE 8 +#define HCI_LEN_HOST_NUM_CMPL_PKTS 1 + +#define HCI_LEN_READ_LOCAL_VER_INFO 0 +#define HCI_LEN_READ_LOCAL_SUP_CMDS 0 +#define HCI_LEN_READ_LOCAL_SUP_FEAT 0 +#define HCI_LEN_READ_BUF_SIZE 0 +#define HCI_LEN_READ_BD_ADDR 0 + +#define HCI_LEN_READ_RSSI 2 +#define HCI_LEN_READ_AUTH_PAYLOAD_TO 2 +#define HCI_LEN_WRITE_AUTH_PAYLOAD_TO 4 + +#define HCI_LEN_LE_SET_EVENT_MASK 8 +#define HCI_LEN_LE_READ_BUF_SIZE 0 +#define HCI_LEN_LE_READ_LOCAL_SUP_FEAT 0 +#define HCI_LEN_LE_SET_RAND_ADDR 6 +#define HCI_LEN_LE_SET_ADV_PARAM 15 +#define HCI_LEN_LE_READ_ADV_TX_POWER 0 +#define HCI_LEN_LE_SET_ADV_DATA 32 +#define HCI_LEN_LE_SET_SCAN_RESP_DATA 32 +#define HCI_LEN_LE_SET_ADV_ENABLE 1 +#define HCI_LEN_LE_SET_SCAN_PARAM 7 +#define HCI_LEN_LE_SET_SCAN_ENABLE 2 +#define HCI_LEN_LE_CREATE_CONN 25 +#define HCI_LEN_LE_CREATE_CONN_CANCEL 0 +#define HCI_LEN_LE_READ_WHITE_LIST_SIZE 0 +#define HCI_LEN_LE_CLEAR_WHITE_LIST 0 +#define HCI_LEN_LE_ADD_DEV_WHITE_LIST 7 +#define HCI_LEN_LE_REMOVE_DEV_WHITE_LIST 7 +#define HCI_LEN_LE_CONN_UPDATE 14 +#define HCI_LEN_LE_SET_HOST_CHAN_CLASS 5 +#define HCI_LEN_LE_READ_CHAN_MAP 2 +#define HCI_LEN_LE_READ_REMOTE_FEAT 2 +#define HCI_LEN_LE_ENCRYPT 32 +#define HCI_LEN_LE_RAND 0 +#define HCI_LEN_LE_START_ENCRYPTION 28 +#define HCI_LEN_LE_LTK_REQ_REPL 18 +#define HCI_LEN_LE_LTK_REQ_NEG_REPL 2 +#define HCI_LEN_LE_READ_SUP_STATES 0 +#define HCI_LEN_LE_RECEIVER_TEST 1 +#define HCI_LEN_LE_TRANSMITTER_TEST 3 +#define HCI_LEN_LE_TEST_END 0 +/*! \brief New in version 4.1 */ +#define HCI_LEN_LE_REM_CONN_PARAM_REP 14 +#define HCI_LEN_LE_REM_CONN_PARAM_NEG_REP 3 +/*! \brief New in version 4.2 */ +#define HCI_LEN_LE_SET_DATA_LEN 6 +#define HCI_LEN_LE_READ_DEF_DATA_LEN 0 +#define HCI_LEN_LE_WRITE_DEF_DATA_LEN 4 +#define HCI_LEN_LE_READ_LOCAL_P256_PUB_KEY 0 +#define HCI_LEN_LE_GENERATE_DHKEY 64 +#define HCI_LEN_LE_ADD_DEV_RES_LIST 39 +#define HCI_LEN_LE_REMOVE_DEV_RES_LIST 7 +#define HCI_LEN_LE_CLEAR_RES_LIST 0 +#define HCI_LEN_LE_READ_RES_LIST_SIZE 0 +#define HCI_LEN_LE_READ_PEER_RES_ADDR 7 +#define HCI_LEN_LE_READ_LOCAL_RES_ADDR 7 +#define HCI_LEN_LE_SET_ADDR_RES_ENABLE 1 +#define HCI_LEN_LE_SET_RES_PRIV_ADDR_TO 2 +#define HCI_LEN_LE_READ_MAX_DATA_LEN 0 +/*! \brief New in version 5.0 */ +#define HCI_LEN_LE_READ_PHY 2 +#define HCI_LEN_LE_SET_DEF_PHY 3 +#define HCI_LEN_LE_SET_PHY 7 +#define HCI_LEN_LE_ENHANCED_RECEIVER_TEST 3 +#define HCI_LEN_LE_ENHANCED_TRANSMITTER_TEST 4 +#define HCI_LEN_LE_SET_ADV_SET_RAND_ADDR 7 +#define HCI_LEN_LE_SET_EXT_ADV_PARAM 25 +#define HCI_LEN_LE_SET_EXT_ADV_DATA(len) (4 + (len)) +#define HCI_LEN_LE_SET_EXT_SCAN_RESP_DATA(len) (4 + (len)) +#define HCI_LEN_LE_EXT_ADV_ENABLE(numSets) (2 + (4 * (numSets))) +#define HCI_LEN_LE_READ_MAX_ADV_DATA_LEN 0 +#define HCI_LEN_LE_READ_NUM_OF_SUP_ADV_SETS 0 +#define HCI_LEN_LE_REMOVE_ADV_SET 1 +#define HCI_LEN_LE_CLEAR_ADV_SETS 0 +#define HCI_LEN_LE_SET_PER_ADV_PARAM 7 +#define HCI_LEN_LE_SET_PER_ADV_DATA(len) (3 + (len)) +#define HCI_LEN_LE_SET_PER_ADV_ENABLE 2 +#define HCI_LEN_LE_SET_EXT_SCAN_PARAM(numPhys) (3 + (5 * (numPhys))) +#define HCI_LEN_LE_SET_EXT_SCAN_ENABLE 6 +#define HCI_LEN_LE_EXT_CREATE_CONN(numPhys) (10 + (16 * (numPhys))) +#define HCI_LEN_LE_PER_ADV_CREATE_SYNC 14 +#define HCI_LEN_LE_PER_ADV_CREATE_SYNC_CANCEL 0 +#define HCI_LEN_LE_PER_ADV_TERMINATE_SYNC 2 +#define HCI_LEN_LE_ADD_DEV_PER_ADV_LIST 8 +#define HCI_LEN_LE_REMOVE_DEV_PER_ADV_LIST 8 +#define HCI_LEN_LE_CLEAR_PER_ADV_LIST 0 +#define HCI_LEN_LE_READ_PER_ADV_LIST_SIZE 0 +#define HCI_LEN_LE_READ_TX_POWER 0 +#define HCI_LEN_LE_READ_RF_PATH_COMP 0 +#define HCI_LEN_LE_WRITE_RF_PATH_COMP 4 +#define HCI_LEN_LE_SET_PRIVACY_MODE 8 +/**@}*/ + +/** \name Events + * + */ +/**@{*/ +#define HCI_DISCONNECT_CMPL_EVT 0x05 +#define HCI_ENC_CHANGE_EVT 0x08 +#define HCI_READ_REMOTE_VER_INFO_CMPL_EVT 0x0C +#define HCI_CMD_CMPL_EVT 0x0E +#define HCI_CMD_STATUS_EVT 0x0F +#define HCI_HW_ERROR_EVT 0x10 +#define HCI_NUM_CMPL_PKTS_EVT 0x13 +#define HCI_DATA_BUF_OVERFLOW_EVT 0x1A +#define HCI_ENC_KEY_REFRESH_CMPL_EVT 0x30 +#define HCI_LE_META_EVT 0x3E +#define HCI_AUTH_PAYLOAD_TIMEOUT_EVT 0x57 +#define HCI_VENDOR_SPEC_EVT 0xFF +/**@}*/ + +/** \name LE Subevents + * + */ +/**@{*/ +#define HCI_LE_CONN_CMPL_EVT 0x01 +#define HCI_LE_ADV_REPORT_EVT 0x02 +#define HCI_LE_CONN_UPDATE_CMPL_EVT 0x03 +#define HCI_LE_READ_REMOTE_FEAT_CMPL_EVT 0x04 +#define HCI_LE_LTK_REQ_EVT 0x05 +/*! \brief New in version 4.1 */ +#define HCI_LE_REM_CONN_PARAM_REQ_EVT 0x06 +/*! \brief New in version 4.2 */ +#define HCI_LE_DATA_LEN_CHANGE_EVT 0x07 +#define HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_EVT 0x08 +#define HCI_LE_GENERATE_DHKEY_CMPL_EVT 0x09 +#define HCI_LE_ENHANCED_CONN_CMPL_EVT 0x0A +#define HCI_LE_DIRECT_ADV_REPORT_EVT 0x0B +/*! \brief New in version 5.0 */ +#define HCI_LE_PHY_UPDATE_CMPL_EVT 0x0C +#define HCI_LE_EXT_ADV_REPORT_EVT 0x0D +#define HCI_LE_PER_ADV_SYNC_EST_EVT 0x0E +#define HCI_LE_PER_ADV_REPORT_EVT 0x0F +#define HCI_LE_PER_ADV_SYNC_LOST_EVT 0x10 +#define HCI_LE_SCAN_TIMEOUT_EVT 0x11 +#define HCI_LE_ADV_SET_TERM_EVT 0x12 +#define HCI_LE_SCAN_REQ_RCVD_EVT 0x13 +#define HCI_LE_CH_SEL_ALGO_EVT 0x14 +/**@}*/ + +/** \name Event parameter lengths + * + */ +/**@{*/ +#define HCI_LEN_DISCONNECT_CMPL 4 /*!< \brief Disconnect event length. */ +#define HCI_LEN_READ_REMOTE_VER_INFO_CMPL 8 /*!< \brief Read remove version info complete event length. */ +#define HCI_LEN_CMD_CMPL 3 /*!< \brief Command complete event length. */ +#define HCI_LEN_CMD_STATUS 4 /*!< \brief Command status event length. */ +#define HCI_LEN_HW_ERR 1 /*!< \brief Hardware error event length. */ +#define HCI_LEN_NUM_CMPL_PKTS 5 /*!< \brief Number of completed packets event length. */ +#define HCI_LEN_ENC_CHANGE 4 /*!< \brief Encryption change event length. */ +#define HCI_LEN_ENC_KEY_REFRESH_CMPL 3 /*!< \brief Encryption key refresh complete event length. */ +#define HCI_LEN_LE_CONN_CMPL 19 /*!< \brief Connection complete event length. */ +#define HCI_LEN_LE_ADV_RPT_MIN 12 /*!< \brief Advertising report event minimum length. */ +#define HCI_LEN_LE_CONN_UPDATE_CMPL 10 /*!< \brief Connection update complete event length. */ +#define HCI_LEN_LE_READ_REMOTE_FEAT_CMPL 12 /*!< \brief Read remote feature event length. */ +#define HCI_LEN_LE_LTK_REQ 13 /*!< \brief LTK request event length. */ +/*! \brief New in version 4.1 */ +#define HCI_LEN_LE_REM_CONN_PARAM_REQ 11 /*!< \brief Remote connection parameter event length. */ +#define HCI_LEN_LE_DATA_LEN_CHANGE 11 /*!< \brief Data length change event length. */ +#define HCI_LEN_LE_READ_PUB_KEY_CMPL 66 /*!< \brief Read local P256 public key compete event length. */ +#define HCI_LEN_LE_GEN_DHKEY_CMPL 34 /*!< \brief Generate DH key complete event length. */ +#define HCI_LEN_LE_ENHANCED_CONN_CMPL 31 /*!< \brief Enhanced connection complete event length. */ +#define HCI_LEN_LE_DIRECT_ADV_REPORT 18 /*!< \brief Direct advertising report event length. */ +#define HCI_LEN_AUTH_PAYLOAD_TIMEOUT 2 /*!< \brief Authenticated payload timeout event length. */ +/*! \brief New in version 5.0 */ +#define HCI_LEN_LE_PHY_UPDATE_CMPL 6 /*!< \brief PHY update complete event length. */ +#define HCI_LEN_LE_CH_SEL_ALGO 4 /*!< \brief Channel selection algorithm event length. */ +#define HCI_LEN_LE_PHY_UPDATE_CMPL 6 /*!< \brief PHY update complete event length. */ +#define HCI_LEN_LE_EXT_ADV_REPORT_MIN 26 /*!< \brief Extended advertising report minimum length. */ +#define HCI_LEN_LE_PER_ADV_SYNC_EST 16 /*!< \brief Periodic advertising sync established event length. */ +#define HCI_LEN_LE_PER_ADV_REPORT 8 /*!< \brief Periodic advertising report event length. */ +#define HCI_LEN_LE_PER_ADV_SYNC_LOST 3 /*!< \brief Periodic advertising sync lost event length. */ +#define HCI_LEN_LE_SCAN_TIMEOUT 1 /*!< \brief Scan timeout event length. */ +#define HCI_LEN_LE_ADV_SET_TERM 6 /*!< \brief Advertising set terminated event length. */ +#define HCI_LEN_LE_SCAN_REQ_RCVD 9 /*!< \brief Scan request received event length. */ +/**@}*/ + +/** \name Supported commands + * + */ +/**@{*/ +#define HCI_SUP_DISCONNECT 0x20 /*!< \brief Byte 0 */ +#define HCI_SUP_READ_REMOTE_VER_INFO 0x80 /*!< \brief Byte 2 */ +#define HCI_SUP_SET_EVENT_MASK 0x40 /*!< \brief Byte 5 */ +#define HCI_SUP_RESET 0x80 /*!< \brief Byte 5 */ +#define HCI_SUP_READ_TX_PWR_LVL 0x04 /*!< \brief Byte 10 */ +#define HCI_SUP_READ_LOCAL_VER_INFO 0x08 /*!< \brief Byte 14 */ +#define HCI_SUP_READ_LOCAL_SUP_FEAT 0x20 /*!< \brief Byte 14 */ +#define HCI_SUP_READ_BD_ADDR 0x02 /*!< \brief Byte 15 */ +#define HCI_SUP_READ_RSSI 0x20 /*!< \brief Byte 15 */ +#define HCI_SUP_SET_EVENT_MASK_PAGE2 0x04 /*!< \brief Byte 22 */ +#define HCI_SUP_LE_SET_EVENT_MASK 0x01 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_READ_BUF_SIZE 0x02 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_READ_LOCAL_SUP_FEAT 0x04 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_SET_RAND_ADDR 0x10 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_SET_ADV_PARAM 0x20 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_READ_ADV_TX_POWER 0x40 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_SET_ADV_DATA 0x80 /*!< \brief Byte 25 */ +#define HCI_SUP_LE_SET_SCAN_RESP_DATA 0x01 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_SET_ADV_ENABLE 0x02 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_SET_SCAN_PARAM 0x04 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_SET_SCAN_ENABLE 0x08 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_CREATE_CONN 0x10 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_CREATE_CONN_CANCEL 0x20 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_READ_WHITE_LIST_SIZE 0x40 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_CLEAR_WHITE_LIST 0x80 /*!< \brief Byte 26 */ +#define HCI_SUP_LE_ADD_DEV_WHITE_LIST 0x01 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_REMOVE_DEV_WHITE_LIST 0x02 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_CONN_UPDATE 0x04 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_SET_HOST_CHAN_CLASS 0x08 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_READ_CHAN_MAP 0x10 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_READ_REMOTE_FEAT 0x20 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_ENCRYPT 0x40 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_RAND 0x80 /*!< \brief Byte 27 */ +#define HCI_SUP_LE_START_ENCRYPTION 0x01 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_LTK_REQ_REPL 0x02 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_LTK_REQ_NEG_REPL 0x04 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_READ_SUP_STATES 0x08 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_RECEIVER_TEST 0x10 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_TRANSMITTER_TEST 0x20 /*!< \brief Byte 28 */ +#define HCI_SUP_LE_TEST_END 0x40 /*!< \brief Byte 28 */ +#define HCI_SUP_READ_AUTH_PAYLOAD_TO 0x10 /*!< \brief Byte 32 */ +#define HCI_SUP_WRITE_AUTH_PAYLOAD_TO 0x20 /*!< \brief Byte 32 */ +/*! \brief New in version 4.1 */ +#define HCI_SUP_LE_REM_CONN_PARAM_REQ_REPL 0x10 /*!< \brief Byte 33 */ +#define HCI_SUP_LE_REM_CONN_PARAM_REQ_NEG_REPL 0x20 /*!< \brief Byte 33 */ +/*! \brief New in version 4.2 */ +#define HCI_SUP_LE_SET_DATA_LEN 0x40 /*!< \brief Byte 33 */ +#define HCI_SUP_LE_READ_DEF_DATA_LEN 0x80 /*!< \brief Byte 33 */ +#define HCI_SUP_LE_WRITE_DEF_DATA_LEN 0x01 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_READ_LOCAL_P256_PUB_KEY 0x02 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_GENERATE_DHKEY 0x04 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_ADD_DEV_RES_LIST_EVT 0x08 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_REMOVE_DEV_RES_LIST 0x10 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_CLEAR_RES_LIST 0x20 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_READ_RES_LIST_SIZE 0x40 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_READ_PEER_RES_ADDR 0x80 /*!< \brief Byte 34 */ +#define HCI_SUP_LE_READ_LOCAL_RES_ADDR 0x01 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_SET_ADDR_RES_ENABLE 0x02 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_SET_RES_PRIV_ADDR_TO 0x04 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_READ_MAX_DATA_LEN 0x08 /*!< \brief Byte 35 */ +/*! \brief New in version 5.0 */ +#define HCI_SUP_LE_READ_PHY 0x10 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_SET_DEF_PHY 0x20 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_SET_PHY 0x40 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_ENHANCED_RECEIVER_TEST 0x80 /*!< \brief Byte 35 */ +#define HCI_SUP_LE_ENHANCED_TRANSMITTER_TEST 0x01 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_SET_ADV_SET_RAND_ADDR 0x02 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_SET_EXT_ADV_PARAM 0x04 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_SET_EXT_ADV_DATA 0x08 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_SET_EXT_SCAN_RESP_DATA 0x10 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_SET_EXT_ADV_ENABLE 0x20 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_READ_MAX_ADV_DATA_LEN 0x40 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_READ_NUM_OF_SUP_ADV_SETS 0x80 /*!< \brief Byte 36 */ +#define HCI_SUP_LE_REMOVE_ADV_SET 0x01 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_CLEAR_ADV_SETS 0x02 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_SET_PER_ADV_PARAM 0x04 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_SET_PER_ADV_DATA 0x08 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_SET_PER_ADV_ENABLE 0x10 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_SET_EXT_SCAN_PARAM 0x20 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_SET_EXT_SCAN_ENABLE 0x40 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_EXT_CREATE_CONN 0x80 /*!< \brief Byte 37 */ +#define HCI_SUP_LE_PER_ADV_CREATE_SYNC 0x01 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_PER_ADV_CREATE_SYNC_CANCEL 0x02 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_PER_ADV_TERMINATE_SYNC 0x04 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_ADD_DEV_PER_ADV_LIST 0x08 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_REMOVE_DEV_PER_ADV_LIST 0x10 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_CLEAR_PER_ADV_LIST 0x20 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_READ_PER_ADV_LIST_SIZE 0x40 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_READ_TX_POWER 0x80 /*!< \brief Byte 38 */ +#define HCI_SUP_LE_READ_RF_PATH_COMP 0x01 /*!< \brief Byte 39 */ +#define HCI_SUP_LE_WRITE_RF_PATH_COMP 0x02 /*!< \brief Byte 39 */ +#define HCI_SUP_LE_SET_PRIVACY_MODE 0x04 /*!< \brief Byte 39 */ +#define HCI_SUP_LE_SET_MIN_NUM_OF_USED_CH 0x08 /*!< \brief Byte 39 */ +/**@}*/ + +/** \name Event mask + * + */ +/**@{*/ +#define HCI_EVT_MASK_DISCONNECT_CMPL 0x10 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_ENC_CHANGE 0x80 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL 0x08 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_HW_ERROR 0x80 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_DATA_BUF_OVERFLOW 0x02 /*!< \brief Byte 3 */ +#define HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL 0x80 /*!< \brief Byte 5 */ +#define HCI_EVT_MASK_LE_META 0x20 /*!< \brief Byte 7 */ +/**@}*/ + +/** \name Event mask page 2 + * + */ +/**@{*/ +#define HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT 0x80 /*!< \brief Byte 2 */ +/**@}*/ + +/** \name LE event mask + * + */ +/**@{*/ +#define HCI_EVT_MASK_LE_CONN_CMPL_EVT 0x01 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_ADV_REPORT_EVT 0x02 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT 0x04 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT 0x08 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_LTK_REQ_EVT 0x10 /*!< \brief Byte 0 */ +/*! \brief New in version 4.1 */ +#define HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT 0x20 /*!< \brief Byte 0 */ +/*! \brief New in version 4.2 */ +#define HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT 0x40 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL 0x80 /*!< \brief Byte 0 */ +#define HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL 0x01 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT 0x02 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT 0x04 /*!< \brief Byte 1 */ +/*! \brief New in version 5.0 */ +#define HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT 0x08 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT 0x10 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT 0x20 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT 0x40 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT 0x80 /*!< \brief Byte 1 */ +#define HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT 0x01 /*!< \brief Byte 2 */ +#define HCI_EVT_MASK_LE_ADV_SET_TERM_EVT 0x02 /*!< \brief Byte 2 */ +#define HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT 0x04 /*!< \brief Byte 2 */ +#define HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT 0x08 /*!< \brief Byte 2 */ +/**@}*/ + +/** \name LE supported features + * + */ +/**@{*/ +/*! \brief New in version 4.0 */ +#define HCI_LE_SUP_FEAT_ENCRYPTION 0x0001 /*!< \brief Encryption supported */ +/*! \brief New in version 4.1 */ +#define HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC 0x0002 /*!< \brief Connection Parameters Request Procedure supported */ +#define HCI_LE_SUP_FEAT_EXT_REJECT_IND 0x0004 /*!< \brief Extended Reject Indication supported */ +#define HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH 0x0008 /*!< \brief Slave-Initiated Features Exchange supported */ +#define HCI_LE_SUP_FEAT_LE_PING 0x0010 /*!< \brief LE Ping supported */ +/*! \brief New in version 4.2 */ +#define HCI_LE_SUP_FEAT_DATA_LEN_EXT 0x0020 /*!< \brief Data Length Extension supported */ +#define HCI_LE_SUP_FEAT_PRIVACY 0x0040 /*!< \brief LL Privacy supported */ +#define HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY 0x0080 /*!< \brief Extended Scan Filter Policy supported */ +/*! \brief New in version 5.0 */ +#define HCI_LE_SUP_FEAT_LE_2M_PHY 0x0100 /*!< \brief LE 2M PHY supported */ +#define HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER 0x0200 /*!< \brief Stable Modulation Index - Transmitter supported */ +#define HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER 0x0400 /*!< \brief Stable Modulation Index - Receiver supported */ +#define HCI_LE_SUP_FEAT_LE_CODED_PHY 0x0800 /*!< \brief LE Coded PHY supported */ +#define HCI_LE_SUP_FEAT_LE_EXT_ADV 0x1000 /*!< \brief LE Extended Advertising supported */ +#define HCI_LE_SUP_FEAT_LE_PER_ADV 0x2000 /*!< \brief LE Periodic Advertising supported */ +#define HCI_LE_SUP_FEAT_CH_SEL_2 0x4000 /*!< \brief Channel Selection Algorithm #2 supported */ +#define HCI_LE_SUP_FEAT_LE_POWER_CLASS_1 0x8000 /*!< \brief LE Power Class 1 supported */ +/**@}*/ + +/** \name Advertising command parameters + * + */ +/**@{*/ +#define HCI_ADV_MIN_INTERVAL 0x0020 /*!< \brief Minimum advertising interval */ +#define HCI_ADV_MAX_INTERVAL 0x4000 /*!< \brief Maximum advertising interval */ +#define HCI_ADV_DIRECTED_MAX_DURATION 0x0500 /*!< \brief Maximum high duty cycle connectable directed advertising duration */ +#define HCI_ADV_TYPE_CONN_UNDIRECT 0x00 /*!< \brief Connectable undirected advertising */ +#define HCI_ADV_TYPE_CONN_DIRECT 0x01 /*!< \brief Connectable directed high duty cycle advertising */ +#define HCI_ADV_TYPE_DISC_UNDIRECT 0x02 /*!< \brief Discoverable undirected advertising */ +#define HCI_ADV_TYPE_NONCONN_UNDIRECT 0x03 /*!< \brief Nonconnectable undirected advertising */ +#define HCI_ADV_TYPE_CONN_DIRECT_LO_DUTY 0x04 /*!< \brief Connectable directed low duty cycle advertising */ +#define HCI_ADV_CHAN_37 0x01 /*!< \brief Advertising channel 37 */ +#define HCI_ADV_CHAN_38 0x02 /*!< \brief Advertising channel 38 */ +#define HCI_ADV_CHAN_39 0x04 /*!< \brief Advertising channel 39 */ +#define HCI_ADV_FILT_NONE 0x00 /*!< \brief No scan request or connection filtering */ +#define HCI_ADV_FILT_SCAN 0x01 /*!< \brief White list filters scan requests */ +#define HCI_ADV_FILT_CONN 0x02 /*!< \brief White list filters connections */ +#define HCI_ADV_FILT_ALL 0x03 /*!< \brief White list filters scan req. and conn. */ +/**@}*/ + +/** \name Scan command parameters + * + */ +/**@{*/ +#define HCI_SCAN_TYPE_PASSIVE 0 /*!< \brief Passive scan */ +#define HCI_SCAN_TYPE_ACTIVE 1 /*!< \brief Active scan */ +#define HCI_SCAN_INTERVAL_MIN 0x0004 /*!< \brief Minimum scan interval */ +#define HCI_SCAN_INTERVAL_MAX 0x4000 /*!< \brief Maximum scan interval */ +#define HCI_SCAN_INTERVAL_DEFAULT 0x0010 /*!< \brief Default scan interval */ +#define HCI_SCAN_WINDOW_MIN 0x0004 /*!< \brief Minimum scan window */ +#define HCI_SCAN_WINDOW_MAX 0x4000 /*!< \brief Maximum scan window */ +#define HCI_SCAN_WINDOW_DEFAULT 0x0010 /*!< \brief Default scan window */ +/**@}*/ + +/** \name Connection command parameters + * + */ +/**@{*/ +#define HCI_CONN_INTERVAL_MIN 0x0006 /*!< \brief Minimum connection interval */ +#define HCI_CONN_INTERVAL_MAX 0x0C80 /*!< \brief Maximum connection interval */ +#define HCI_CONN_LATENCY_MAX 0x01F3 /*!< \brief Maximum connection latency */ +#define HCI_SUP_TIMEOUT_MIN 0x000A /*!< \brief Minimum supervision timeout */ +#define HCI_SUP_TIMEOUT_MAX 0x0C80 /*!< \brief Maximum supervision timeout */ +/**@}*/ + +/** \name Connection event parameters + * + */ +/**@{*/ +#define HCI_ROLE_MASTER 0 /*!< \brief Role is master */ +#define HCI_ROLE_SLAVE 1 /*!< \brief Role is slave */ +#define HCI_CLOCK_500PPM 0x00 /*!< \brief 500 ppm clock accuracy */ +#define HCI_CLOCK_250PPM 0x01 /*!< \brief 250 ppm clock accuracy */ +#define HCI_CLOCK_150PPM 0x02 /*!< \brief 150 ppm clock accuracy */ +#define HCI_CLOCK_100PPM 0x03 /*!< \brief 100 ppm clock accuracy */ +#define HCI_CLOCK_75PPM 0x04 /*!< \brief 75 ppm clock accuracy */ +#define HCI_CLOCK_50PPM 0x05 /*!< \brief 50 ppm clock accuracy */ +#define HCI_CLOCK_30PPM 0x06 /*!< \brief 30 ppm clock accuracy */ +#define HCI_CLOCK_20PPM 0x07 /*!< \brief 20 ppm clock accuracy */ +/**@}*/ + +/** \name Advertising report event parameters + * + */ +/**@{*/ +#define HCI_ADV_CONN_UNDIRECT 0x00 /*!< \brief Connectable undirected advertising */ +#define HCI_ADV_CONN_DIRECT 0x01 /*!< \brief Connectable directed advertising */ +#define HCI_ADV_DISC_UNDIRECT 0x02 /*!< \brief Discoverable undirected advertising */ +#define HCI_ADV_NONCONN_UNDIRECT 0x03 /*!< \brief Non-connectable undirected advertising */ +#define HCI_ADV_SCAN_RESPONSE 0x04 /*!< \brief Scan response */ +/**@}*/ + +/** \name Extended advertising data operations + * + */ +/**@{*/ +#define HCI_ADV_DATA_OP_FRAG_INTER 0x00 /*!< \brief Intermediate fragment */ +#define HCI_ADV_DATA_OP_FRAG_FIRST 0x01 /*!< \brief First fragment */ +#define HCI_ADV_DATA_OP_FRAG_LAST 0x02 /*!< \brief Last fragment */ +#define HCI_ADV_DATA_OP_COMP_FRAG 0x03 /*!< \brief Complete extended advertising data */ +#define HCI_ADV_DATA_OP_UNCHANGED_DATA 0x04 /*!< \brief Unchanged data (just update Advertising DID) */ +/**@}*/ + +/** \name Advertising data fragment preference + * + */ +/**@{*/ +#define HCI_ADV_DATA_FRAG_PREF_FRAG 0x00 /*!< \brief Controller may fragment all Host advertising data */ +#define HCI_ADV_DATA_FRAG_PREF_NO_FRAG 0x01 /*!< \brief Controller should not fragment nor minimize fragmentation of Host advertising data */ +/**@}*/ + +/** \name Number of advertising sets + * + */ +/**@{*/ +#define HCI_ADV_NUM_SETS_ALL_DISABLE 0x00 /*!< \brief Disable all advertising sets */ +/**@}*/ + +/** \name Maximum number of scanning or initiating PHYs + * + */ +/**@{*/ +#define HCI_MAX_NUM_PHYS 3 /*!< \brief Maximum number of scanning or initiating PHYs */ +/**@}*/ + +/** \name Advertising PHY values + * + */ +/**@{*/ +#define HCI_ADV_PHY_LE_1M 0x01 /*!< \brief LE 1M PHY */ +#define HCI_ADV_PHY_LE_2M 0x02 /*!< \brief LE 2M PHY */ +#define HCI_ADV_PHY_LE_CODED 0x03 /*!< \brief LE Coded PHY */ +/**@}*/ + +/** \name Scanner PHY value bits + * + */ +/**@{*/ +#define HCI_SCAN_PHY_LE_1M_BIT (1<<0) /*!< \brief LE 1M PHY */ +#define HCI_SCAN_PHY_LE_2M_BIT (1<<1) /*!< \brief LE 2M PHY */ +#define HCI_SCAN_PHY_LE_CODED_BIT (1<<2) /*!< \brief LE Coded PHY */ +/**@}*/ + +/** \name Initiator PHY value bits + * + */ +/**@{*/ +#define HCI_INIT_PHY_LE_1M_BIT (1<<0) /*!< \brief LE 1M PHY */ +#define HCI_INIT_PHY_LE_2M_BIT (1<<1) /*!< \brief LE 2M PHY */ +#define HCI_INIT_PHY_LE_CODED_BIT (1<<2) /*!< \brief LE Coded PHY */ +/**@}*/ + +/** \name Advertising event properties type bits + * + */ +/**@{*/ +#define HCI_ADV_PROP_CONN_ADV_BIT (1<<0) /*!< \brief Connectable advertising bit */ +#define HCI_ADV_PROP_SCAN_ADV_BIT (1<<1) /*!< \brief Scannable advertising bit */ +#define HCI_ADV_PROP_DIRECT_ADV_BIT (1<<2) /*!< \brief Directed advertising bit */ +#define HCI_ADV_PROP_CONN_DIRECT_ADV_BIT (1<<3) /*!< \brief High duty cycle connectable directed advertising bit */ +#define HCI_ADV_PROP_USE_LEG_PDU_BIT (1<<4) /*!< \brief Use legacy advertising PDUs bit */ +#define HCI_ADV_PROP_OMIT_ADV_ADDR_BIT (1<<5) /*!< \brief Omit advertiser's address from all PDUs (anonymous advertising) bit */ +#define HCI_ADV_PROP_INC_TX_PWR_BIT (1<<6) /*!< \brief Include TxPower in extended header of advertising PDU bit */ +/**@}*/ + +/** \name Advertising event properties for legacy PDUs + * + */ +/**@{*/ +#define HCI_ADV_PROP_LEG_CONN_UNDIRECT 0x13 /*!< \brief Connectable and scannable undirected advertising (00010011b) */ +#define HCI_ADV_PROP_LEG_CONN_DIRECT 0x1D /*!< \brief Connectable directed high duty cycle advertising (00011101b) */ +#define HCI_ADV_PROP_LEG_SCAN_UNDIRECT 0x12 /*!< \brief Scannable undirected advertising (00010010b) */ +#define HCI_ADV_PROP_LEG_NONCONN_UNDIRECT 0x10 /*!< \brief Non-connectable and non-scannable undirected advertising (00010000b) */ +#define HCI_ADV_PROP_LEG_CONN_DIRECT_LO_DUTY 0x15 /*!< \brief Connectable directed low duty cycle advertising (00010101b) */ +/**@}*/ + +/** \name Extended advertising report event type bits + * + */ +/**@{*/ +#define HCI_ADV_RPT_CONN_ADV_BIT (1<<0) /*!< \brief Connectable advertising event bit */ +#define HCI_ADV_RPT_SCAN_ADV_BIT (1<<1) /*!< \brief Scannable advertising event bit */ +#define HCI_ADV_RPT_DIRECT_ADV_BIT (1<<2) /*!< \brief Directed advertising event bit */ +#define HCI_ADV_RPT_SCAN_RSP_BIT (1<<3) /*!< \brief Scan response event bit */ +#define HCI_ADV_RPT_LEG_ADV_BIT (1<<4) /*!< \brief Legacy advertising PDU event bit */ +#define HCI_ADV_RPT_DATA_STATUS_BITS (3<<5) /*!< \brief Data status bits */ +/**@}*/ + +/** \name Advertising report event types for legacy PDUs + * + */ +/**@{*/ +#define HCI_ADV_RPT_LEG_CONN_UNDIRECT 0x13 /*!< \brief Connectable and scannable undirected advertising (0010011b) */ +#define HCI_ADV_RPT_LEG_CONN_DIRECT 0x15 /*!< \brief Connectable directed advertising (0010101b) */ +#define HCI_ADV_RPT_LEG_SCAN_UNDIRECT 0x12 /*!< \brief Scannable undirected advertising (0010010b) */ +#define HCI_ADV_RPT_LEG_NONCONN_UNDIRECT 0x10 /*!< \brief Non-connectable and non-scannable undirected advertising (0010000b) */ +#define HCI_ADV_RPT_LEG_CONN_UNDIRECT_SCAN_RSP 0x1B /*!< \brief Scan response to connectable and scannable undirected advertising (0011011b) */ +#define HCI_ADV_RPT_LEG_SCAN_UNDIRECT_SCAN_RSP 0x1A /*!< \brief Scan response to scannable undirected advertising (0011010b) */ +/**@}*/ + +/** \name Advertising report data status + * + */ +/**@{*/ +#define HCI_ADV_RPT_DATA_CMPL 0x00 /*!< \brief Data complete */ +#define HCI_ADV_RPT_DATA_INCMPL_MORE 0x01 /*!< \brief Data incomplete, more date to come */ +#define HCI_ADV_RPT_DATA_INCMPL_TRUNC 0x02 /*!< \brief Data incomplete, data truncated, no more date to come */ +/**@}*/ + +/** \name Extended advertising report event primary PHY values + * + */ +/**@{*/ +#define HCI_ADV_RPT_PHY_PRIM_LE_1M 0x01 /*!< \brief Advertiser PHY is LE 1M */ +#define HCI_ADV_RPT_PHY_PRIM_LE_CODED 0x03 /*!< \brief Advertiser PHY is LE Coded */ +/**@}*/ + +/** \name Extended advertising report event seconday PHY values + * + */ +/**@{*/ +#define HCI_ADV_RPT_PHY_SEC_NONE 0x00 /*!< \brief No packets on seconday advertising channel */ +#define HCI_ADV_RPT_PHY_SEC_LE_1M 0x01 /*!< \brief Advertiser PHY is LE 1M */ +#define HCI_ADV_RPT_PHY_SEC_LE_2M 0x02 /*!< \brief Advertiser PHY is LE 2M */ +#define HCI_ADV_RPT_PHY_SEC_LE_CODED 0x03 /*!< \brief Advertiser PHY is LE Coded */ +/**@}*/ + +/** \name Channel selection algorithm used + * + */ +/**@{*/ +#define HCI_CH_SEL_ALGO_1 0x00 /*!< \brief LE channel selection algorithm #1 used */ +#define HCI_CH_SEL_ALGO_2 0x01 /*!< \brief LE channel selection algorithm #2 used */ +/**@}*/ + +/** \name Minimum number of used channels + * + */ +/**@{*/ +#define HCI_MIN_NUM_OF_USED_CHAN 8 /*!< \brief Minimum number of used channels */ +/**@}*/ + +/** \name Misc command parameters + * + */ +/**@{*/ +#define HCI_READ_TX_PWR_CURRENT 0 /*!< \brief Read current tx power */ +#define HCI_READ_TX_PWR_MAX 1 /*!< \brief Read maximum tx power */ +#define HCI_TX_PWR_MIN -30 /*!< \brief Minimum tx power dBm */ +#define HCI_TX_PWR_MAX 20 /*!< \brief Maximum tx power dBm */ +#define HCI_TX_PWR_NO_PREFERENCE 127 /*!< \brief Tx power no preference */ +#define HCI_VERSION 6 /*!< \brief HCI specification version */ +#define HCI_RSSI_MIN -127 /*!< \brief Minimum RSSI dBm */ +#define HCI_RSSI_MAX 20 /*!< \brief Maximum RSSI dBm */ +#define HCI_ADDR_TYPE_PUBLIC 0 /*!< \brief Public device address */ +#define HCI_ADDR_TYPE_RANDOM 1 /*!< \brief Random device address */ +#define HCI_ADDR_TYPE_PUBLIC_IDENTITY 2 /*!< \brief Public identity address */ +#define HCI_ADDR_TYPE_RANDOM_IDENTITY 3 /*!< \brief Random identity address */ +#define HCI_ADDR_TYPE_ANONYMOUS 0xFF /*!< \brief Anonymous device address */ +#define HCI_FILT_NONE 0 /*!< \brief Accept all advertising packets */ +#define HCI_FILT_WHITE_LIST 1 /*!< \brief Accept from While List only */ +#define HCI_FILT_RES_INIT 2 /*!< \brief Accept directed advertisements with RPAs */ +#define HCI_FILT_WHITE_LIST_RES_INIT 3 /*!< \brief Accept from White List or directed advertisements with RPAs */ +#define HCI_FILT_PER_ADV_PARAM 0 /*!< \brief Listen to advertiser specified by create sync command parameters */ +#define HCI_FILT_PER_ADV_LIST 1 /*!< \brief Listen to advertiser from Periodic Advertiser List only */ +#define HCI_ROLE_MASTER 0 /*!< \brief Role is master */ +#define HCI_ROLE_SLAVE 1 /*!< \brief Role is slave */ +#define HCI_PRIV_MODE_NETWORK 0x00 /*!< \brief Network privacy mode (default) */ +#define HCI_PRIV_MODE_DEVICE 0x01 /*!< \brief Device privacy mode */ +/**@}*/ + +/** \name PHY types + * + */ +/**@{*/ +#define HCI_PHY_NONE 0x00 /*!< \brief No selected PHY */ +#define HCI_PHY_LE_1M_BIT (1<<0) /*!< \brief LE 1M PHY */ +#define HCI_PHY_LE_2M_BIT (1<<1) /*!< \brief LE 2M PHY */ +#define HCI_PHY_LE_CODED_BIT (1<<2) /*!< \brief LE Coded PHY */ +/**@}*/ + +/** \name All PHYs preference + * + */ +/**@{*/ +#define HCI_ALL_PHY_ALL_PREFERENCES 0x00 /*!< \brief All PHY preferences */ +#define HCI_ALL_PHY_TX_PREFERENCE_BIT (1<<0) /*!< \brief Tx PHY preference */ +#define HCI_ALL_PHY_RX_PREFERENCE_BIT (1<<1) /*!< \brief Rx PHY preference */ +/**@}*/ + +/** \name PHY options + * + */ +/**@{*/ +#define HCI_PHY_OPTIONS_NONE 0x00 /*!< \brief No preferences */ +#define HCI_PHY_OPTIONS_S2_PREFERRED 0x01 /*!< \brief S=2 coding preferred when transmitting on LE Coded PHY */ +#define HCI_PHY_OPTIONS_S8_PREFERRED 0x02 /*!< \brief S=8 coding preferred when transmitting on LE Coded PHY */ +/**@}*/ + +/** \name Parameter lengths + * + */ +/**@{*/ +#define HCI_EVT_MASK_LEN 8 /*!< \brief Length of event mask byte array */ +#define HCI_EVT_MASK_PAGE_2_LEN 8 /*!< \brief Length of event mask page 2 byte array */ +#define HCI_LE_EVT_MASK_LEN 8 /*!< \brief Length of LE event mask byte array */ +#define HCI_FEAT_LEN 8 /*!< \brief Length of features byte array */ +#define HCI_ADV_DATA_LEN 31 /*!< \brief Length of advertising data */ +#define HCI_SCAN_DATA_LEN 31 /*!< \brief Length of scan response data */ +#define HCI_EXT_ADV_DATA_LEN 251 /*!< \brief Length of extended advertising data */ +#define HCI_PER_ADV_DATA_LEN 252 /*!< \brief Length of periodic advertising data */ +#define HCI_EXT_ADV_RPT_DATA_LEN 229 /*!< \brief Length of extended advertising report data */ +#define HCI_PER_ADV_RPT_DATA_LEN 248 /*!< \brief Length of periodic advertising report data */ +#define HCI_CHAN_MAP_LEN 5 /*!< \brief Length of channel map byte array */ +#define HCI_KEY_LEN 16 /*!< \brief Length of encryption key */ +#define HCI_ENCRYPT_DATA_LEN 16 /*!< \brief Length of data used in encryption */ +#define HCI_RAND_LEN 8 /*!< \brief Length of random number */ +#define HCI_LE_STATES_LEN 8 /*!< \brief Length of LE states byte array */ +#define HCI_P256_KEY_LEN 64 /*!< \brief Length of P256 key */ +#define HCI_DH_KEY_LEN 32 /*!< \brief Length of DH Key */ + +#define HCI_EXT_ADV_RPT_DATA_LEN_OFFSET 23 /*!< \brief Length field offset of extended advertising report data */ +#define HCI_PER_ADV_RPT_DATA_LEN_OFFSET 6 /*!< \brief Length field offset of periodic advertising report data */ +/**@}*/ + +/** \name Company ID + * + */ +/**@{*/ +#define HCI_ID_ARM 0x005F /*!< \brief ARM Ltd. company ID */ +/**@}*/ + +/** \name Manufacturer location in Local version + * + */ +/**@{*/ +#define HCI_LOCAL_VER_MANUFACTURER_POS 4 +/**@}*/ + +/* \} */ /* STACK_HCI_API */ + +#ifdef __cplusplus +}; +#endif + +#endif /* HCI_DEFS_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_defs.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_defs.h new file mode 100644 index 0000000000..c1a5c16cc2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_defs.h @@ -0,0 +1,351 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link layer constant definitions. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef LL_DEFS_H +#define LL_DEFS_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Constants +**************************************************************************************************/ + +/*** Version ***/ + +#define LL_VER_BT_CORE_SPEC_4_0 0x06 /*!< Bluetooth core specification 4.0 */ +#define LL_VER_BT_CORE_SPEC_4_1 0x07 /*!< Bluetooth core specification 4.1 */ +#define LL_VER_BT_CORE_SPEC_4_2 0x08 /*!< Bluetooth core specification 4.2 */ +#define LL_VER_BT_CORE_SPEC_5_0 0x09 /*!< Bluetooth core specification 5.0 */ + +#define LL_COMP_ID_ARM 0x005F /*!< ARM Ltd. company ID. */ + +/*** Common ***/ + +#define LL_RSSI_MIN -127 /*!< Minimum RSSI value. */ +#define LL_RSSI_MAX 20 /*!< Maximum RSSI value. */ +#define LL_RSSI_NOT_AVAIL 127 /*!< RSSI is not available. */ + +#define LL_CRC_LEN 3 /*!< CRC length. */ +#define LL_AA_LEN 4 /*!< Access address length. */ +#define LL_PREAMBLE_LEN_1M 1 /*!< Preamble length (LE 1M PHY). */ +#define LL_PREAMBLE_LEN_2M 2 /*!< Preamble length (LE 2M PHY). */ +#define LL_PREAMBLE_LEN_CODED_BITS 10 /*!< Preamble length (LE Coded PHY). */ +#define LL_CI_LEN_BITS 2 /*!< Coding indicator length (LE Coded PHY). */ +#define LL_TERM1_LEN_BITS 3 /*!< TERM1 length (LE Coded PHY). */ +#define LL_TERM2_LEN_BITS 3 /*!< TERM2 length (LE Coded PHY). */ + +#define LL_RAND_ADDR_TYPE_MASK UINT64_C(0xC00000000000) /*!< BD Random Address type mask. */ +#define LL_RAND_ADDR_TYPE_STATIC UINT64_C(0xC00000000000) /*!< Static Random Address type. */ +#define LL_RAND_ADDR_TYPE_RPA UINT64_C(0x400000000000) /*!< Resolvable Private Address type. */ +#define LL_RAND_ADDR_TYPE_NRPA UINT64_C(0x000000000000) /*!< Non-Resolvable Private Address type. */ + +/*** Advertising PDU ***/ + +/*! \brief Advertising channel PDU types. */ +enum +{ + /* --- Core Spec 4.0 --- */ + LL_PDU_ADV_IND = 0, /*!< Connectable undirected advertising PDU. */ + LL_PDU_ADV_DIRECT_IND = 1, /*!< Connectable directed advertising PDU. */ + LL_PDU_ADV_NONCONN_IND = 2, /*!< Non-connectable undirected advertising PDU. */ + LL_PDU_SCAN_REQ = 3, /*!< Scan request PDU. */ + LL_PDU_SCAN_RSP = 4, /*!< Scan response PDU. */ + LL_PDU_CONNECT_IND = 5, /*!< Connect indication PDU. */ + LL_PDU_ADV_SCAN_IND = 6, /*!< Scannable undirected advertising PDU. */ + /* --- Core Spec 5.0 --- */ + LL_PDU_AUX_SCAN_REQ = 3, /*!< Auxiliary scan request PDU. */ + LL_PDU_AUX_CONNECT_REQ = 5, /*!< Auxiliary connect request PDU. */ + LL_PDU_ADV_EXT_IND = 7, /*!< Extended advertising PDU. */ + LL_PDU_AUX_ADV_IND = 7, /*!< Auxiliary advertising PDU. */ + LL_PDU_AUX_SCAN_RSP = 7, /*!< Auxiliary scan response PDU. */ + LL_PDU_AUX_SYNC_IND = 7, /*!< Auxiliary synchronize PDU. */ + LL_PDU_AUX_CHAIN_IND = 7, /*!< Auxiliary chain PDU. */ + LL_PDU_AUX_CONNECT_RSP = 8, /*!< Auxiliary connect response PDU. */ +}; + +#define LL_SCAN_REQ_PDU_LEN 12 /*!< Size of a scan request PDU. */ +#define LL_CONN_IND_PDU_LEN 34 /*!< Size of a connect indication PDU. */ +#define LL_CONN_RSP_PDU_LEN 14 /*!< Size of an auxiliary connect response PDU. */ + +#define LL_CHAN_ADV_MIN_IDX 37 /*!< Minimum advertising channel index. */ +#define LL_CHAN_ADV_MAX_IDX 39 /*!< Maximum advertising channel index. */ +#define LL_NUM_CHAN_ADV 3 /*!< Total number of advertising channels. */ + +#define LL_ADVBU_MAX_LEN 31 /*!< Maximum advertising channel host data length. */ +#define LL_ADVB_MAX_LEN 39 /*!< Maximum advertising channel PDU length. */ +#define LL_ADVB_MIN_LEN (LL_ADVB_MAX_LEN - LL_ADVBU_MAX_LEN) /*!< Minimum advertising channel packet length. */ +#define LL_ADVB_MAX_TIME_1M ((LL_BLE_US_PER_BYTE_1M * (LL_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_1M) + /*!< Maximum time for a 1M advertising channel PDU. */ +#define LL_ADVB_MAX_TIME_2M ((LL_BLE_US_PER_BYTE_2M * (LL_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_2M) + /*!< Maximum time for a 2M advertising channel PDU. */ +#define LL_ADVB_MAX_TIME_S2 ((LL_BLE_US_PER_BYTE_CODED_S2 * (LL_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_CODED_S2) + /*!< Maximum time for a Coded S2 advertising channel PDU. */ +#define LL_ADVB_MAX_TIME_S8 ((LL_BLE_US_PER_BYTE_CODED_S8 * (LL_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_CODED_S8) + /*!< Maximum time for a Coded S8 advertising channel PDU. */ + +#define LL_ADV_PKT_MAX_USEC LL_ADVB_MAX_TIME_1M /*!< Maximum time in microseconds for an advertising packet. */ +#define LL_SCAN_REQ_MAX_USEC ((8 * (LL_ADV_PREFIX_LEN + LL_SCAN_PREFIX_LEN)) + LL_MIN_PKT_TIME_US_1M) + /*!< Maximum time in microseconds for a scan request packet. */ +#define LL_SCAN_RSP_MAX_USEC LL_ADVB_MAX_TIME_1M /*!< Maximum time in microseconds for a scan response packet. */ + +#define LL_ADV_HDR_LEN 2 /*!< Advertising channel header length. */ +#define LL_ADV_HDR_TYPE_OFFS 0 /*!< Advertising header type offset. */ +#define LL_ADV_HDR_TYPE_MSK 0x0F /*!< Advertising header type mask. */ +#define LL_ADV_HDR_LEN_OFFS 1 /*!< Advertising header length offset. */ +#define LL_ADV_HDR_LEN_MSK 0x3F /*!< Advertising header length mask for 4.2. */ +#define LL_ADV_EXT_HDR_LEN_MSK 0xFF /*!< Advertising extension header length mask for 5.0. */ +#define LL_ADV_PREFIX_LEN 6 /*!< Advertising PDU payload prefix length (AdvA). */ +#define LL_SCAN_PREFIX_LEN 6 /*!< Scan request/response PDU payload prefix length (AdvA). */ + +#define LL_ADV_ACCESS_ADDR UINT32_C(0x8E89BED6) /*!< Advertising channel access address. */ +#define LL_ADV_CRC_INIT UINT32_C(0x555555) /*!< Advertising CRC initial value. */ + +#define LL_DIR_ADV_INTER_TICKS 6 /*!< Advertising interval between directed advertising events (3.75 ms). */ +#define LL_DIR_ADV_DUR_TICKS 2048 /*!< Maximum high duty cycle directed advertising duration (1.28 seconds). */ + +/*! \brief Extended header bit definition. */ +enum +{ + LL_EXT_HDR_ADV_ADDR_BIT = (1 << 0), /*!< Extended header AdvA bit. */ + LL_EXT_HDR_TGT_ADDR_BIT = (1 << 1), /*!< Extended header TargetA bit. */ + LL_EXT_HDR_SUPP_INFO_BIT = (1 << 2), /*!< Extended header SuppInfo bit. */ + LL_EXT_HDR_ADI_BIT = (1 << 3), /*!< Extended header AdvDataInfo bit. */ + LL_EXT_HDR_AUX_PTR_BIT = (1 << 4), /*!< Extended header AuxPtr bit. */ + LL_EXT_HDR_SYNC_INFO_BIT = (1 << 5), /*!< Extended header SyncInfo bit. */ + LL_EXT_HDR_TX_PWR_BIT = (1 << 6), /*!< Extended header TxPower bit. */ +}; + +#define LL_MAX_ADV_HANDLE 0xEF /*!< Maximum advertising handle. */ +#define LL_MAX_ADV_SID 0x0F /*!< Maximum advertising SID */ + +#define LL_EXT_ADV_HDR_MIN_LEN 1 /*!< Minimum extended advertising header length (ExtHdrLen and AdvMode fields). */ +#define LL_EXT_ADV_HDR_MAX_LEN 64 /*!< Maximum extended advertising header length (ExtHdrLen, AdvMode fields and Extended header). */ +#define LL_EXT_ADVBU_MAX_LEN 251 /*!< Maximum extended advertising channel PDU host data length. */ +#define LL_EXT_ADVB_MAX_LEN 257 /*!< Maximum extended advertising channel PDU length. */ + +#define LL_EXT_ADVB_MAX_TIME_1M ((LL_BLE_US_PER_BYTE_1M * (LL_EXT_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_1M) + /*!< Maximum time for a 1M advertising channel PDU. */ +#define LL_EXT_ADVB_MAX_TIME_2M ((LL_BLE_US_PER_BYTE_2M * (LL_EXT_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_2M) + /*!< Maximum time for a 2M advertising channel PDU. */ +#define LL_EXT_ADVB_MAX_TIME_S2 ((LL_BLE_US_PER_BYTE_CODED_S2 * (LL_EXT_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_CODED_S2) + /*!< Maximum time for a Coded S2 advertising channel PDU. */ +#define LL_EXT_ADVB_MAX_TIME_S8 ((LL_BLE_US_PER_BYTE_CODED_S8 * (LL_EXT_ADVB_MAX_LEN - LL_ADV_HDR_LEN)) + LL_MIN_PKT_TIME_US_CODED_S8) + /*!< Maximum time for a Coded S8 advertising channel PDU. */ + +#define LL_AUX_PTR_MAX_USEC 2457600 /*!< Maximum AuxPtr offset value in microseconds. */ + +#define LL_SYNC_MIN_TIMEOUT 0x000A /*!< Minimum synchronization timeout. */ +#define LL_SYNC_MAX_TIMEOUT 0x4000 /*!< Maximum synchronization timeout. */ +#define LL_SYNC_MAX_SKIP 0x01F3 /*!< Maximum synchronization skip. */ +#define LL_SYNC_MAX_HANDLE 0x0EFF /*!< Maximum synchronization handle. */ + +#define LL_PER_ADV_INT_MIN 0x0006 /*!< Minimum periodic advertising interval. */ + + +/*** Data PDU ***/ + +/*! \brief Data channel LL Control PDU types. */ +enum +{ + /* --- Core Spec 4.0 --- */ + LL_PDU_CONN_UPDATE_IND = 0x00, /*!< Connection update indication PDU. */ + LL_PDU_CHANNEL_MAP_IND = 0x01, /*!< Channel map indication PDU. */ + LL_PDU_TERMINATE_IND = 0x02, /*!< Terminate indication PDU. */ + LL_PDU_ENC_REQ = 0x03, /*!< Encryption request PDU. */ + LL_PDU_ENC_RSP = 0x04, /*!< Encryption response PDU. */ + LL_PDU_START_ENC_REQ = 0x05, /*!< Start encryption request PDU. */ + LL_PDU_START_ENC_RSP = 0x06, /*!< Start encryption response PDU. */ + LL_PDU_UNKNOWN_RSP = 0x07, /*!< Unknown response PDU. */ + LL_PDU_FEATURE_REQ = 0x08, /*!< Feature request PDU. */ + LL_PDU_FEATURE_RSP = 0x09, /*!< Feature response PDU. */ + LL_PDU_PAUSE_ENC_REQ = 0x0A, /*!< Pause encryption request PDU. */ + LL_PDU_PAUSE_ENC_RSP = 0x0B, /*!< Pause encryption response PDU. */ + LL_PDU_VERSION_IND = 0x0C, /*!< Version indication PDU. */ + LL_PDU_REJECT_IND = 0x0D, /*!< Reject indication PDU. */ + /* --- Core Spec 4.2 --- */ + LL_PDU_SLV_FEATURE_REQ = 0x0E, /*!< Slave feature request PDU. */ + LL_PDU_CONN_PARAM_REQ = 0x0F, /*!< Connection parameter request PDU. */ + LL_PDU_CONN_PARAM_RSP = 0x10, /*!< Connection parameter response PDU. */ + LL_PDU_REJECT_EXT_IND = 0x11, /*!< Reject extended indication PDU. */ + LL_PDU_PING_REQ = 0x12, /*!< Ping request PDU. */ + LL_PDU_PING_RSP = 0x13, /*!< Ping response PDU. */ + LL_PDU_LENGTH_REQ = 0x14, /*!< Data length request PDU. */ + LL_PDU_LENGTH_RSP = 0x15, /*!< Data length response PDU. */ + /* --- Core Spec 5.0 --- */ + LL_PDU_PHY_REQ = 0x16, /*!< PHY request PDU. */ + LL_PDU_PHY_RSP = 0x17, /*!< PHY response PDU. */ + LL_PDU_PHY_UPDATE_IND = 0x18, /*!< PHY update indication PDU. */ + LL_PDU_MIN_USED_CHAN_IND = 0x19, /*!< Minimum used channels indication PDU. */ + LL_PDU_UNSPECIFIED = 0xFF /*!< Unspecified PDU. */ +}; + +/* Data PDU length */ +/* --- Core Spec 4.0 --- */ +#define LL_CONN_UPD_IND_PDU_LEN 12 /*!< Connection update indication PDU length. */ +#define LL_CHAN_MAP_IND_PDU_LEN 8 /*!< Channel map indication PDU length. */ +#define LL_TERMINATE_IND_PDU_LEN 2 /*!< Terminate indication PDU length. */ +#define LL_ENC_REQ_LEN 23 /*!< Encryption request PDU length. */ +#define LL_ENC_RSP_LEN 13 /*!< Encryption response PDU length. */ +#define LL_START_ENC_LEN 1 /*!< Start encryption request/response PDU length. */ +#define LL_UNKNOWN_RSP_LEN 2 /*!< Unknown response PDU length. */ +#define LL_FEATURE_PDU_LEN 9 /*!< Feature request/response PDU length. */ +#define LL_PAUSE_ENC_LEN 1 /*!< Pause encryption request/response PDU length. */ +#define LL_VERSION_IND_PDU_LEN 6 /*!< Version indication PDU length. */ +#define LL_REJECT_IND_PDU_LEN 2 /*!< Reject indication PDU length. */ +/* --- Core Spec 4.2 --- */ +#define LL_CONN_PARAM_PDU_LEN 24 /*!< Connection parameter request or response PDU length. */ +#define LL_REJECT_EXT_IND_PDU_LEN 3 /*!< Reject extended indication PDU length. */ +#define LL_PING_PDU_LEN 1 /*!< Ping request/response PDU length. */ +#define LL_DATA_LEN_PDU_LEN 9 /*!< Data length request or response PDU length. */ +/* --- Core Spec 5.0 --- */ +#define LL_PHY_PDU_LEN 3 /*!< PHY request/response PDU length. */ +#define LL_PHY_UPD_IND_PDU_LEN 5 /*!< PHY update indication PDU length. */ +#define LL_MIN_USED_CHAN_PDU_LEN 3 /*!< Minimum used channels indication PDU length. */ + +#define LL_EMPTY_PDU_LEN 2 /*!< Length of an empty data PDU. */ + +#define LL_DATA_HDR_LEN 2 /*!< Data channel header length. */ +#define LL_DATA_MIC_LEN 4 /*!< Data channel PDU MIC length. */ + +#define LL_DATA_HDR_LLID_MSK 0x03 /*!< Data PDU LLID mask. */ +#define LL_DATA_HDR_LEN_MSK 0xFF /*!< Data header length mask. BLE 4.2 data len extension allows 8 bits. */ + +#define LL_MAX_NUM_CHAN_DATA 37 /*!< Maximum number of used data channels. */ +#define LL_MIN_NUM_CHAN_DATA 2 /*!< Minimum number of used data channels. */ + +/*! \brief Data PDU LLID types. */ +enum +{ + LL_LLID_VS_PDU = 0x00, /*!< Vendor specific PDU. */ + /* N.B. next two enumerations intentionally use identical values. */ + LL_LLID_EMPTY_PDU = 0x01, /*!< Empty PDU. */ + LL_LLID_CONT_PDU = 0x01, /*!< Data PDU: continuation fragment of an L2CAP message. */ + LL_LLID_START_PDU = 0x02, /*!< Data PDU: start of an L2CAP message or a complete L2CAP message with no fragmentation. */ + LL_LLID_CTRL_PDU = 0x03, /*!< Control PDU. */ +}; + +/*** Encryption ***/ + +#define LL_ECC_KEY_LEN 32 /*!< ECC key length. */ + +#define LL_DEF_RES_ADDR_TO_SEC 900 /*!< Default resolvable address timeout in seconds. */ + +#define LL_RAND_LEN 8 /*!< Length of random number */ +#define LL_KEY_LEN 16 /*!< Encryption key length. */ +#define LL_SKD_LEN LL_KEY_LEN /*!< Session key diversifier length. */ +#define LL_IV_LEN 8 /*!< Initialization vector length. */ + +#define LL_DEF_AUTH_TO_MS 30000 /*!< Default authentication timeout in milliseconds. */ + +/*** LLCP ***/ + +#define LL_DATA_LEN_TO_TIME_1M(len) ((LL_BLE_US_PER_BYTE_1M * ((len) + LL_DATA_MIC_LEN)) + LL_MIN_PKT_TIME_US_1M) + /*!< Convert data length to time. */ +#define LL_DATA_LEN_TO_TIME_2M(len) ((LL_BLE_US_PER_BYTE_2M * ((len) + LL_DATA_MIC_LEN)) + LL_MIN_PKT_TIME_US_2M) + /*!< Convert data length to time. */ +#define LL_DATA_LEN_TO_TIME_CODED_S8(len) ((LL_BLE_US_PER_BYTE_CODED_S8 * ((len) + LL_DATA_MIC_LEN)) + LL_MIN_PKT_TIME_US_CODED_S8) + /*!< Convert data length to time. */ +#define LL_DATA_LEN_TO_TIME_CODED_S2(len) ((LL_BLE_US_PER_BYTE_CODED_S2 * ((len) + LL_DATA_MIC_LEN)) + LL_MIN_PKT_TIME_US_CODED_S2) + /*!< Convert data length to time. */ + +#define LL_MIN_INSTANT 6 /*!< Minimum number of CE to apply a CONN_UPD or CHAN_MAP. */ + +#define LL_MAX_ADV_DATA_LEN 1650 /*!< Maximum advertising data length. */ + +#define LL_MAX_DATA_LEN_MIN 27 /*!< Minimum value for maximum Data PDU length */ +#define LL_MAX_DATA_LEN_ABS_MAX 251 /*!< Absolute maximum limit for maximum Data PDU length */ + +#define LL_MAX_DATA_TIME_MIN 328 /*!< Minimum value for maximum Data PDU time */ +#define LL_MAX_DATA_TIME_ABS_MAX 17040 /*!< Absolute maximum limit for maximum Data PDU time */ +#define LL_MAX_DATA_TIME_ABS_MAX_1M 2120 /*!< Absolute maximum limit for maximum Data PDU time (LE 1M PHY) */ + +#define LL_T_PRT_SEC 40 /*!< LLCP procedure response timeout in seconds. */ + +#define LL_MAX_ADV_DLY_MS 10 /*!< Maximum advertising delay in milliseconds. */ + +#define LL_MIN_CONN_INTERVAL 6 /*!< Minimum value for connection interval. */ +#define LL_MAX_CONN_INTERVAL 3200 /*!< Maximum value for connection interval. */ + +#define LL_MIN_TX_WIN_SIZE 1 /*!< Minimum value for transmit window size. */ +#define LL_MAX_TX_WIN_SIZE 8 /*!< Maximum value for transmit window size. */ + +#define LL_MAX_CONN_LATENCY 499 /*!< Maximum value for connection slave latency. */ + +#define LL_MIN_SUP_TIMEOUT 10 /*!< Minimum value for connection supervision timeout. */ +#define LL_MAX_SUP_TIMEOUT 3200 /*!< Maximum value for connection supervision timeout. */ + +#define LL_MIN_POWER_THRESHOLD -128 /*!< Minimum value for power threshold. */ +#define LL_MAX_POWER_THRESHOLD 127 /*!< Maximum value for power threshold. */ + +#define LL_MAX_PHYS 3 /*!< Number of LE PHYs. */ +#define LL_ALL_PHYS_MSK 0x7 /*!< All supported LE PHYs mask. */ + +/*** DTM ***/ + +#define LL_DTM_HDR_LEN 2 /*!< Direct Test Mode PDU header length. */ +#define LL_DTM_SYNC_WORD UINT32_C(0x71764129) /*!< Direct Test Mode sync word. */ +#define LL_DTM_CRC_INIT UINT32_C(0x555555) /*!< Direct Test Mode CRC initial value. */ +#define LL_DTM_MAX_INT_US 12500 /*!< Maximum time interval between packets in microseconds. */ +#define LL_DTM_PDU_ABS_MAX_LEN 255 /*!< Absolute maximum DTM PDU length. */ +#define LL_DTM_MAX_CHAN_IDX 39 /*!< Maximum channel index. */ + +/*** Baseband ***/ + +#define LL_CHAN_DATA_MIN_IDX 0 /*!< Minimum data channel index. */ +#define LL_CHAN_DATA_MAX_IDX 36 /*!< Maximum data channel index. */ +#define LL_CHAN_DATA_ALL UINT64_C(0x0000001FFFFFFFFF) /*!< Maximum data channel index. */ + +#define LL_BLE_BIT_PER_US 1 /*!< BLE PHY rate. */ +#define LL_BLE_US_PER_BYTE_1M 8 /*!< BLE PHY speed (LE 1M PHY). */ +#define LL_BLE_US_PER_BYTE_2M 4 /*!< BLE PHY speed (LE 2M PHY). */ +#define LL_BLE_US_PER_BYTE_CODED_S8 64 /*!< BLE PHY speed (LE Coded PHY, S=8). */ +#define LL_BLE_US_PER_BIT_CODED_S8 8 /*!< BLE PHY speed (LE Coded PHY, S=8). */ +#define LL_BLE_US_PER_BYTE_CODED_S2 16 /*!< BLE PHY speed (LE Coded PHY, S=2). */ +#define LL_BLE_US_PER_BIT_CODED_S2 2 /*!< BLE PHY speed (LE Coded PHY, S=2). */ +#define LL_BLE_TIFS_US 150 /*!< BLE inter-frame space. */ +#define LL_BLE_MAFS_US 300 /*!< BLE minimum AUX frame space. */ +#define LL_BLE_US_PER_TICK 625 /*!< Microseconds per BLE tick. */ + +#define LL_MIN_PKT_TIME_US_1M 80 /*!< Minimum packet time (i.e. empty PDU) on LE 1M PHY. */ +#define LL_MIN_PKT_TIME_US_2M 44 /*!< Minimum packet time (i.e. empty PDU) on LE 2M PHY. */ +#define LL_MIN_PKT_TIME_US_CODED_S8 720 /*!< Minimum packet time (i.e. empty PDU) on LE Coded PHY, S=8. */ +#define LL_MIN_PKT_TIME_US_CODED_S2 462 /*!< Minimum packet time (i.e. empty PDU) on LE Coded PHY, S=2. */ + +#define LL_MIN_ADV_TX_PWR_LVL -20 /*!< Minimum Tx power level for advertising. */ +#define LL_MAX_ADV_TX_PWR_LVL 10 /*!< Maximum Tx power level for advertising. */ + +#define LL_MIN_TX_PWR_LVL -30 /*!< Minimum Tx power level for connections. */ +#define LL_MAX_TX_PWR_LVL 20 /*!< Maximum Tx power level for connections. */ + +#define LL_MAX_TIFS_DEVIATION 2 /*!< Maximum TIFS deviation in microseconds. */ + +#define LL_MAX_CE_DEVIATION_USEC 16 /*!< Maximum connection event deviation in microseconds. */ + +#ifdef __cplusplus +}; +#endif + +#endif /* LL_DEFS_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_math.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_math.h new file mode 100644 index 0000000000..d6f3d140d4 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/ll_math.h @@ -0,0 +1,216 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Link Layer math utilities. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ +#ifndef LL_MATH_H +#define LL_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wsf_types.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! \brief Binary divide with 1,000 divisor (n[max]=7,999). */ +#define LL_MATH_DIV_10E3(n) (((n) * UINT32_C(536871)) >> 29) + +/*! \brief Binary divide with 1,000,000 divisor (n[max]=0xFFFFFFFF). */ +#define LL_MATH_DIV_10E6(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(4295)) >> 32)) + +/*! \brief Binary divide with 10 divisor (n[max]=0xFFFFFFFF). */ +#define LL_MATH_DIV_10(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(419431)) >> 22)) + +/*! \brief Binary divide with 27 divisor (n[max]=55,295). */ +#define LL_MATH_DIV_27(n) (((n) * UINT32_C(77673)) >> 21) + +/*! \brief Binary divide with 37 divisor (n[max]=75,776). */ +#define LL_MATH_DIV_37(n) (((n) * UINT32_C(56680)) >> 21) + +/*! \brief Binary modulo 37. */ +#define LL_MATH_MOD_37(n) ((n) - (LL_MATH_DIV_37(n) * 37)) + +/*! \brief Binary divide with 1250 divisor (n[max]=0xFFFFFFFF). */ +#define LL_MATH_DIV_1250(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(1717987)) >> 31)) + +/*! \brief Binary divide with 625 divisor (n[max]=0xFFFFFFFF). */ +#define LL_MATH_DIV_625(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(1717987)) >> 30)) + +/*! \brief Binary divide with 30 divisor (n[max]=0xFFFFFFFF). */ +#define LL_MATH_DIV_30(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(286331154)) >> 33)) + +/*! \brief Binary divide with 300 divisor (n[max]=0x3FFFFFFF). */ +#define LL_MATH_DIV_300(n) ((uint32_t)(((uint64_t)(n) * UINT64_C(14660155038)) >> 42)) + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief ECC service callback. */ +typedef void (*LlMathEccServiceCback_t)(uint8_t op); + +/*! \brief ECC operations. */ +enum +{ + LL_MATH_ECC_OP_GENERATE_P256_KEY_PAIR, /*!< Generate P-256 key pair. */ + LL_MATH_ECC_OP_GENERATE_DH_KEY /*!< Generate Diffie-Hellman key. */ +}; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Generate random number. + * + * \return 32-bit random number. + */ +/*************************************************************************************************/ +uint32_t LlMathRandNum(void); + +/*************************************************************************************************/ +/*! + * \brief Calculate AES ECB. + * + * \param pKey Encryption key. + * \param pOut Output data. + * \param pIn Input data. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathAesEcb(const uint8_t *pKey, uint8_t *pOut, const uint8_t *pIn); + +/*************************************************************************************************/ +/*! + * \brief Set service callback for ECC generation. + * + * \param cback Callback to invoke when driver needs servicing. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccSetServiceCback(LlMathEccServiceCback_t cback); + +/*************************************************************************************************/ +/*! + * \brief Start generating P-256 key pair. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccGenerateP256KeyPairStart(void); + +/*************************************************************************************************/ +/*! + * \brief Start generating P-256 public key with a specified private key. + * + * \param pPrivKey Private key. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccGenerateP256PublicKeyStart(const uint8_t *pPrivKey); + +/*************************************************************************************************/ +/*! + * \brief Continue generating P-256 key pair. + * + * \return TRUE if key generation complete. + */ +/*************************************************************************************************/ +bool_t LlMathEccGenerateP256KeyPairContinue(void); + +/*************************************************************************************************/ +/*! + * \brief Get results from generating P-256 key pair. + * + * \param pPubKey Storage for public key. + * \param pPrivKey Storage for private key. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccGenerateP256KeyPairComplete(uint8_t *pPubKey, uint8_t *pPrivKey); + +/*************************************************************************************************/ +/*! + * \brief Start generating Diffie-Hellman key. + * + * \param pPubKey Public key. + * \param pPrivKey Private key. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccGenerateDhKeyStart(const uint8_t *pPubKey, const uint8_t *pPrivKey); + +/*************************************************************************************************/ +/*! + * \brief Continue generating Diffie-Hellman key. + * + * \return TRUE if Diffie-Hellman key generation complete. + */ +/*************************************************************************************************/ +bool_t LlMathEccGenerateDhKeyContinue(void); + +/*************************************************************************************************/ +/*! + * \brief Get results from generating Diffie-Hellman key. + * + * \param pDhKey Storage for Diffie-Hellman key. + * + * \return None. + */ +/*************************************************************************************************/ +void LlMathEccGenerateDhKeyComplete(uint8_t *pDhKey); + +/*************************************************************************************************/ +/*! + * \brief Return the number of bits which are set. + * + * \param num Input parameter. + * + * \return Number of bits which are set. + */ +/*************************************************************************************************/ +uint8_t LlMathGetNumBitsSet(uint64_t num); + +/*************************************************************************************************/ +/*! + * \brief Return result of a division. + * + * \param nu32 Numerator of size 32 bits. + * \param de32 Denominator of size 32 bits. + * + * \return Result of a division. + */ +/*************************************************************************************************/ +uint32_t LlMathDivideUint32(uint32_t nu32, uint32_t de32); + +#ifdef __cplusplus +}; +#endif + +#endif /* LL_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_154_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_154_api.h new file mode 100644 index 0000000000..c3d125166b --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_154_api.h @@ -0,0 +1,51 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Platform interface file: mac154-specific. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef PLATFORM_154_API_H +#define PLATFORM_154_API_H + +#include "wsf_types.h" + +/************************************************************************************************** + Type Definitions +**************************************************************************************************/ + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Load extended 802.15.4 MAC device address. + * + * \param pDevAddr Return buffer for address. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformLoadExtMac154Address(uint8_t *pDevAddr); + +#endif /* PLATFORM_154_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_api.h new file mode 100644 index 0000000000..0e00692da2 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_api.h @@ -0,0 +1,283 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef PLATFORM_API_H +#define PLATFORM_API_H + +#include "wsf_types.h" + +/************************************************************************************************** + Type Definitions +**************************************************************************************************/ + +/*! \brief Status callback. */ +typedef bool_t (*PlatformStatus_t)(uint32_t *); + +/*! \brief Sleep enter callback. */ +typedef void (*PlatformSleepEnter_t)(void); + +/*! \brief Sleep exit callback. */ +typedef void (*PlatformSleepExit_t)(void); + +/*! \brief BB configuration. */ +typedef struct +{ + uint16_t clkPpm; /*!< Clock accuracy in PPM. */ + uint8_t rfSetupDelayUsec; /*!< RF setup delay in microseconds. */ + uint16_t maxScanPeriodMsec; /*!< Maximum scan period in milliseconds. */ + uint16_t schSetupDelayUsec; /*!< Schedule setup delay in microseconds. */ +} PlatformBbCfg_t; + +/*! \brief Version component IDs. */ +typedef enum +{ + PLATFORM_VER_ID_RADIO = 0, /*!< Radio version. */ + PLATFORM_VER_ID_HW_BLE = 1, /*!< BLE HW version. */ + PLATFORM_VER_ID_PHY = 2, /*!< PHY HW version. */ + PLATFORM_VER_ID_HW_SYS = 3, /*!< System HW version. */ + PLATFORM_VER_ID_SW_DRV = 4, /*!< Software version. */ + PLATFORM_VER_ID_15P4_MAC = 5, /*!< 802.15.4 HW version. */ + PLATFORM_VER_INFO_NUM = 6 /*!< Total number of version IDs. */ +} PlatformVersionId_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/*! \brief Number of assertions. */ +extern uint32_t PlatformAssertCount; + +/*! \brief Trap enabled flag. */ +extern volatile bool_t PlatformAssertTrapEnable; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Initialization */ +/*************************************************************************************************/ +/*! + * \brief Common platform initialization. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformInit(void); + +/*************************************************************************************************/ +/*! + * \brief Hardware initialization for controller operation. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformInitControllerHardware(void); + +/*************************************************************************************************/ +/*! + * \brief Hardware initialization for host operation. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformInitHostHardware(void); + +/*************************************************************************************************/ +/*! + * \brief Hardware initialization for controller operation. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformInitBootloaderHardware(void); + +/*************************************************************************************************/ +/*! + * \brief Initialize Dual Chip LL + * + * \return None + * + * \note Initilization that takes place after WsfBufInit is performed here + */ +/*************************************************************************************************/ +void PlatformInitDualChip(void); + +/* Bootloader */ +/*************************************************************************************************/ +/*! + * \brief Execute application from RAM. + * + * \return None. + * + * \note This routine does not return. + */ +/*************************************************************************************************/ +void PlatformExecApplication(void); + +/* Memory */ +/*************************************************************************************************/ +/*! + * \brief Get memory regions. + * + * \param pCodeMemAddr If non-NULL, return starting address of code memory. + * \param pCodeMemSize If non-NULL, return size of code memory. + * \param pDataMemAddr If non-NULL, return starting address of data memory. + * \param pDataMemSize If non-NULL, return size of data memory. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformGetMemoryRegions(uint32_t *pCodeMemAddr, uint32_t *pCodeMemSize, + uint32_t *pDataMemAddr, uint32_t *pDataMemSize); + +/*************************************************************************************************/ +/*! + * \brief Get code memory region used by ROM bootloader. + * + * \param pCodeMemAddr If non-NULL, return starting address of code memory. + * \param pCodeMemSize If non-NULL, return size of code memory. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformGetBootRegions(uint32_t *pCodeMemAddr, uint32_t *pCodeMemSize); + +/*************************************************************************************************/ +/*! + * \brief Count stack usage. + * + * \return Stack high watermark in bytes. + */ +/*************************************************************************************************/ +uint32_t PlatformCountStackUsage(void); + +/*************************************************************************************************/ +/*! + * \brief Get heap available. + * + * \return Number of bytes of heap memory available. + */ +/*************************************************************************************************/ +uint32_t PlatformGetHeapAvailable(void); + +/*************************************************************************************************/ +/*! + * \brief Get heap used. + * + * \return Number of bytes of heap memory used. + */ +/*************************************************************************************************/ +uint32_t PlatformGetHeapUsed(void); + +/*************************************************************************************************/ +/*! + * \brief Reserve heap memory. + * + * \param size Number of bytes of heap memory used. + * + * \return None + */ +/*************************************************************************************************/ +void PlatformReserveHeap(uint32_t size); + +/*************************************************************************************************/ +/*! + * \brief Get next available heap memory. + * + * \return Address of the start of heap memory. + */ +/*************************************************************************************************/ +void *PlatformGetHeapStart(void); + +/* Configuration */ +/*************************************************************************************************/ +/*! + * \brief Load BB timing configuration. + * + * \param pCfg Return configuration values. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformLoadBbConfig(PlatformBbCfg_t *pCfg); + +/* Power Management */ +/*************************************************************************************************/ +/*! + * \brief Register sleep callback functions. + * + * \param protId Protocol ID. + * \param statusCback Callback function for checking status + * \param enterCback Callback function before entering sleep. + * \param exitCback Callback function after exiting sleep. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformRegisterSleep(uint8_t protId, PlatformStatus_t statusCback, PlatformSleepEnter_t enterCback, PlatformSleepExit_t exitCback); + +/*************************************************************************************************/ +/*! + * \brief Set Sleep mode. + * + * \param sleepMode Deep sleep or shallow sleep. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformSetSleepMode(uint8_t sleepMode); + +/*************************************************************************************************/ +/*! + * \brief Function for checking if there is an active timer and if there is enough time to + * go to sleep and going to sleep. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformTimeSleep(void); + +/*************************************************************************************************/ +/*! + * \brief Function for updating WSF timer based on elapsed RTC ticks. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformTimeUpdate(void); + +/* Version */ +/*************************************************************************************************/ +/*! + * \brief Get the hardware version code. + * + * \param id Version ID. + * \param pCode Hardware version code. + * + * \return TRUE if version code valid, FALSE otherwise. + * + * Interrogate the hardware for its version code. + */ +/*************************************************************************************************/ +bool_t PlatformGetVersionCode(PlatformVersionId_t id, uint32_t *pCode); + +#endif /* PLATFORM_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_ble_api.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_ble_api.h new file mode 100644 index 0000000000..f3c8b5e3d8 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/platform_ble_api.h @@ -0,0 +1,101 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Platform interface file: ble-specific. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef PLATFORM_BLE_API_H +#define PLATFORM_BLE_API_H + +#include "wsf_types.h" + +/************************************************************************************************** + Type Definitions +**************************************************************************************************/ + +/*! \brief LL configuration. */ +typedef struct +{ + /* Advertiser */ + uint8_t maxAdvSets; /*!< Maximum number of advertising sets. */ + uint8_t maxAdvReports; /*!< Maximum number of pending legacy or extended advertising reports. */ + uint16_t maxExtAdvDataLen; /*!< Maximum extended advertising data size. */ + uint8_t defExtAdvDataFragLen; /*!< Default extended advertising data fragmentation size. */ + uint32_t auxDelayUsec; /*!< Additional Auxiliary Offset delay above T_MAFS in microseconds. */ + /* Scanner */ + uint8_t maxScanReqRcvdEvt; /*!< Maximum scan request received events. */ + uint16_t maxExtScanDataLen; /*!< Maximum extended scan data size. */ + /* Connection */ + uint8_t maxConn; /*!< Maximum number of connections. */ + uint8_t numTxBufs; /*!< Default number of transmit buffers. */ + uint8_t numRxBufs; /*!< Default number of receive buffers. */ + uint16_t maxAclLen; /*!< Maximum ACL buffer size. */ + int8_t defTxPwrLvl; /*!< Default Tx power level for connections. */ + uint8_t ceJitterUsec; /*!< Allowable CE jitter on a slave (account for master's sleep clock resolution). */ + /* DTM */ + uint16_t dtmRxSyncMs; /*!< DTM Rx synchronization window in milliseconds. */ +} PlatformLlCfg_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Configuration */ +/*************************************************************************************************/ +/*! + * \brief Get PHY feature configuration. + * + * \param pPhy2mSup 2M PHY supported. + * \param pPhyCodedSup Coded PHY supported. + * \param pStableModIdxTxSup Tx stable modulation index supported. + * \param pStableModIdxRxSup Rx stable modulation index supported. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformGetBlePhyFeatures(bool_t *pPhy2mSup, bool_t *pPhyCodedSup, + bool_t *pStableModIdxTxSup, bool_t *pStableModIdxRxSup); + +/*************************************************************************************************/ +/*! + * \brief Load LL advertising configuration. + * + * \param pCfg Return configuration values. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformLoadLlConfig(PlatformLlCfg_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Load device Bluetooth device address. + * + * \param pDevAddr Bluetooth device address. + * + * \return None. + */ +/*************************************************************************************************/ +void PlatformLoadBdAddress(uint8_t *pDevAddr); + +#endif /* PLATFORM_BLE_API_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/prand.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/prand.h new file mode 100644 index 0000000000..83a872e44e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/prand.h @@ -0,0 +1,61 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Cordio pseudo-random number generator interface. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef CORDIO_PRAND_H +#define CORDIO_PRAND_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Functions +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Initialize random number generator. + * + * \return None. + */ +/*************************************************************************************************/ +void PrandInit(void); + +/*************************************************************************************************/ +/*! + * \brief Generate random data. + * + * \param pBuf Storage for random data. + * \param len Length of data to generate, in bytes. + * + * \return None. + */ +/*************************************************************************************************/ +void PrandGen(uint8_t *pBuf, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* CORDIO_PRAND_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/radio_drv.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/radio_drv.h new file mode 100644 index 0000000000..8e837fdf27 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/cordio_stack/platform/common/include/radio_drv.h @@ -0,0 +1,320 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Radio driver interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef RADIO_DRV_H +#define RADIO_DRV_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief Operation types. */ +enum +{ + RADIO_DRV_BLE_OP_TEST_TX, /*!< Continuous Tx test mode. */ + RADIO_DRV_BLE_OP_TEST_RX, /*!< Continuous Rx test mode. */ + RADIO_DRV_BLE_OP_MST_ADV_EVENT, /*!< Master advertising event. */ + RADIO_DRV_BLE_OP_SLV_ADV_EVENT, /*!< Slave advertising event. */ + RADIO_DRV_BLE_OP_MST_CONN_EVENT, /*!< Master connection event. */ + RADIO_DRV_BLE_OP_SLV_CONN_EVENT, /*!< Slave connection event. */ + RADIO_DRV_15P4_EVENT /*!< 15P4 event. */ +}; + +/*! \brief Radio timing. */ +typedef struct +{ + uint32_t txOnLatency; /*!< Latency between radio on signal and transmit. */ + uint32_t rxOnLatency; /*!< Latency between radio on signal and receive. */ + uint32_t txDataPathLatency; /*!< Transmit data path latency. */ + uint32_t rxDataPathLatency; /*!< Receive data path latency. */ +} RadioDrvTiming_t; + +/*! \brief Abort callback. */ +typedef void (*RadioDrvAbortCback_t)(void); + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/*************************************************************************************************/ +/*! + * \brief Handle radio configuration. + * + * \param len Length of configuration data, in octets. + * \param pCfg Configuration data. + * + * \return TRUE if radio configuration was handled. + * + * The data block pCfg is only valid during the execution of this function, so configuration + * data must be stored or copied. + */ +/*************************************************************************************************/ +bool_t RadioDrvCfgHandler(uint16_t len, const uint8_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Set radio configuration values. + * + * \param len Length of configuration data, in octets. + * \param pCfg Configuration data. + * + * \return TRUE if radio configuration was handled. + * + * The data block pCfg is only valid during the execution of this function, so configuration + * data must be stored or copied. + */ +/*************************************************************************************************/ +bool_t RadioDrvSetConfiguration(uint16_t len, const uint8_t *pCfg); + +/*************************************************************************************************/ +/*! + * \brief Initialize the BB radio. + * + * \return None. + * + * Initialization occurs once upon startup of MAC-layer software to load trim, calibrate clocks, + * or perform any other one-time operations. + */ +/*************************************************************************************************/ +void RadioDrvInit(void); + +/*************************************************************************************************/ +/*! + * \brief Get timing parameters for radio. + * + * \param pTiming Storage for timing parameters. + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvGetTiming(RadioDrvTiming_t *pTiming); + +/*************************************************************************************************/ +/*! + * \brief Get supported transmit power levels. + * + * \param pMinTxPwr Storage for minimum transmit power (expressed in 1dBm units). + * \param pMaxTxPwr Storage for maximum transmit power (expressed in 1dBm units). + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvGetSupTxPower(int8_t *pMinTxPwr, int8_t *pMaxTxPwr); + +/*************************************************************************************************/ +/*! + * \brief Get the actual Tx power at the antenna (expressed in 1dBm units). + * + * \param txPwr Tx power provided by the host (expressed in 1dBm units). + * + * \return Actual Tx power at the antenna (expressed in 1dBm units). + */ +/*************************************************************************************************/ +int8_t RadioDrvGetActualTxPower(int8_t txPwr); + +/*************************************************************************************************/ +/*! + * \brief Get the radio version. + * + * \param pVerCode Version code return value. + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvGetVersion(uint32_t *pVerCode); + +/*************************************************************************************************/ +/*! + * \brief Set abort callback. + * + * \param cback Abort callback. + * + * \return None. + * + * If the abort callback is called after RadioDrvStartTx() or RadioDrvStartRx() but before + * RadioDrvStop(), the BB will abort the current operation. Otherwise, the function is ignored. + * + * The BB will set the callback to NULL to clear the callback. + */ +/*************************************************************************************************/ +void RadioDrvSetAbortCback(RadioDrvAbortCback_t cback); + +/*************************************************************************************************/ +/*! + * \brief Enable the BB radio. + * + * \return None. + * + * The radio should be enabled, possibly after leaving sleep. The XTAL warmup must be started, but + * no radio operation will be attempted for xtalWarmup time, when the XTAL must be ready. + */ +/*************************************************************************************************/ +void RadioDrvEnable(void); + +/*************************************************************************************************/ +/*! + * \brief Disable the BB radio. + * + * \return None. + * + * The radio should be disabled, possibly before entering sleep. Any ongoing transmit or receive + * should be stopped. The XTAL may be disabled. + */ +/*************************************************************************************************/ +void RadioDrvDisable(void); + +/*************************************************************************************************/ +/*! + * \brief Set RF Debug Mode. + * + * \param ddmSetting DDM mode for different modules. + * \param ddmDir DDM mode direction. + * \param peripheralSetting RF setting for debug mode. + * \param peripheralDir RX or TX. + * + * \return bool_t TRUE if handled here. + */ +/*************************************************************************************************/ +bool_t RadioDrvSetDdm(uint32_t ddmSetting, uint32_t ddmDir, uint32_t peripheralSetting, uint32_t peripheralDir); + +/*************************************************************************************************/ +/*! + * \brief Wait until radio is in idle state. + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvWaitForIdle(void); + +/*************************************************************************************************/ +/*! + * \brief Set radio channel parameters. + * + * \param opType Operation type. + * \param rfFreq RF frequency in MHz. + * \param txPhy Transmitter PHY. + * \param rxPhy Receiver PHY. + * \param phyOptions PHY options. + * \param txPower Transmit power in dBm. + * + * \return None. + * + * The channel parameters remain active until new parameters are set, the radio is disabled, or a + * radio operation is stopped. + */ +/*************************************************************************************************/ +void RadioDrvSetChannelParam(uint8_t opType, uint16_t rfFreq, uint8_t txPhy, uint8_t rxPhy, uint8_t phyOptions, int8_t txPower); + +/*************************************************************************************************/ +/*! + * \brief Start transmitter. + * + * \return None. + * + * Prepare the transmitter, so that the warmup will begin at the radio request, with the + * modulator producing the first bit after txOnLatency. The transmitter should automatically stop + * when the transmit ends so that another transmit or a receive can be started. + */ +/*************************************************************************************************/ +void RadioDrvStartTx(void); + +/*************************************************************************************************/ +/*! + * \brief Start receiver. + * + * \return None. + * + * Prepare the receiver, so that warmup will begin at the radio request, with the demodulator + * expecting the first bit after rxOnLatency. The receiver should automatically stop when the + * receive ends so that another recieve or a transmit can be started. + */ +/*************************************************************************************************/ +void RadioDrvStartRx(void); + +/*************************************************************************************************/ +/*! + * \brief Start transmitter in continuous mode. + * + * \return None. + * + * Start the transmitter immediately and stay on indefinitely. + */ +/*************************************************************************************************/ +void RadioDrvStartContinuousTx(void); + +/*************************************************************************************************/ +/*! + * \brief Start receiver in continuous mode. + * + * \return None. + * + * Start the receiver immediately and stay on indefinitely. + */ +/*************************************************************************************************/ +void RadioDrvStartContinuousRx(void); + +/*************************************************************************************************/ +/*! + * \brief Stop transmitter or receiver. + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvStop(void); + +/*************************************************************************************************/ +/*! + * \brief Radio driver set PMU and clk. + * + * \return None. + */ +/*************************************************************************************************/ +void RadioDrvSetPMUClk(void); + +/*************************************************************************************************/ +/*! + * \brief Fill the buffer with random bytes + * + * \param pBufferRandom Pointer to buffer + * \param numRandomBytes Number of bytes to write + * + * \return None. + * + * \note Because this function takes manual control of the radio it cannot be used when + * the radio is, or might become active. Typically this function will only be used + * during boot time to provide random numbers that are used for initialising other + * parts of the system. + */ +/*************************************************************************************************/ +void RadioDrvGetRandomBytes(uint8_t *pBufferRandom, uint8_t numRandomBytes); + +#ifdef __cplusplus +}; +#endif + +#endif /* RADIO_DRV_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/LICENSE.txt b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/LICENSE.txt new file mode 100644 index 0000000000..ab099ae5a5 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) 2014, Kenneth MacKay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * 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. + +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_CORDIO_LL/thirdparty/uecc/README.txt b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/README.txt new file mode 100644 index 0000000000..24f1231c1e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/README.txt @@ -0,0 +1,208 @@ +micro-ecc +========== + +A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. + +The old version of micro-ecc can be found in the "old" branch. + +Features +-------- + + * Resistant to known side-channel attacks. + * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. + * Supports 8, 32, and 64-bit architectures. + * Small code size. + * No dynamic memory allocation. + * Support for 4 standard curves: secp160r1, secp192r1, secp256r1, and secp256k1. + * BSD 2-clause license. + +Usage Notes +----------- +### Point Representation ### +Compressed points are represented in the standard format as defined in http://www.secg.org/collateral/sec1_final.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. `uECC_make_key()`, `uECC_shared_secret()`, `uECC_sign()`, and `uECC_verify()` only handle uncompressed points; you can use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. + +Private keys are represented in the standard format. + +### Using the Code ### + +I recommend just copying (or symlink) uECC.h, uECC.c, and the appropriate asm\_<arch>\_.inc (if any) into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. + +For use with Arduino, you can just create a symlink to the `uECC` directory in your Arduino `libraries` directory. You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). + +See uECC.h for documentation for each function. + +### Compilation Notes ### + + * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). + * If you want to change the defaults for `uECC_CURVE` and `uECC_ASM`, you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_CURVE=uECC_secp256r1` or whatever). + * When compiling for a Thumb-1 platform with inline assembly enabled (ie, `uECC_ASM` is defined to `uECC_asm_small` or `uECC_asm_fast`), you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). + * When compiling for an ARM/Thumb-2 platform with fast inline assembly enabled (ie, `uECC_ASM` is defined to `uECC_asm_fast`), you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). + * When compiling for AVR with inline assembly enabled, you must have optimizations enabled (compile with `-O1` or higher). + * When building for Windows, you will need to link in the `advapi32.lib` system library. + +ARM Performance +--------------- + +All tests were built using gcc 4.8.2 with `-O3`, and were run on a Raspberry Pi B+. `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases. All times are in milliseconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
secp160r1secp192r1secp256r1secp256k1
ECDH:2.32.77.96.5
ECDSA sign:2.83.18.67.2
ECDSA verify:2.73.29.27.0
+ +AVR Performance +--------------- + +All tests were built using avr-gcc 4.8.1 with `-Os`, and were run on a 16 MHz ATmega256RFR2. Code size refers to the space used by micro-ecc code and data. + +#### ECDH (fast) #### + +In these tests, `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases. + + + + + + + + + + + + + + + + + + + + + + + +
secp160r1secp192r1secp256r1secp256k1
ECDH time (ms):47081022201615
Code size (bytes):10768131122088621126
+ +#### ECDH (small) #### + +In these tests, `uECC_ASM` was defined to `uECC_asm_small` and `ECC_SQUARE_FUNC` was defined to `0` in all cases. + + + + + + + + + + + + + + + + + + + + + + + +
secp160r1secp192r1secp256r1secp256k1
ECDH time (ms):1250181047904700
Code size (bytes):3244340052743426
+ +#### ECDSA (fast) #### + +In these tests, `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
secp160r1secp192r1secp256r1secp256k1
ECDSA sign time (ms):55590223861773
ECDSA verify time (ms):59099026501800
Code size (bytes):13246147982259422826
+ +#### ECDSA (small) #### + +In these tests, `uECC_ASM` was defined to `uECC_asm_small` and `ECC_SQUARE_FUNC` was defined to `0` in all cases. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
secp160r1secp192r1secp256r1secp256k1
ECDSA sign time (ms):1359193149984904
ECDSA verify time (ms):1515216057005220
Code size (bytes):5690505469805080
diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/asm_arm.inc b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/asm_arm.inc new file mode 100644 index 0000000000..c5f9672be6 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/asm_arm.inc @@ -0,0 +1,2455 @@ +#define DEC_5 4 +#define DEC_6 5 +#define DEC_7 6 +#define DEC_8 7 + +#define DEC(N) uECC_CONCAT(DEC_, N) + +#define REPEAT_1(stuff) stuff +#define REPEAT_2(stuff) REPEAT_1(stuff) stuff +#define REPEAT_3(stuff) REPEAT_2(stuff) stuff +#define REPEAT_4(stuff) REPEAT_3(stuff) stuff +#define REPEAT_5(stuff) REPEAT_4(stuff) stuff +#define REPEAT_6(stuff) REPEAT_5(stuff) stuff +#define REPEAT_7(stuff) REPEAT_6(stuff) stuff +#define REPEAT_8(stuff) REPEAT_7(stuff) stuff + +#define REPEAT(N, stuff) uECC_CONCAT(REPEAT_, N)(stuff) + +#define STR2(thing) #thing +#define STR(thing) STR2(thing) + +#if (uECC_ASM == uECC_asm_fast) + +static uint32_t vli_add(uint32_t *result, const uint32_t *left, const uint32_t *right) { + uint32_t carry = 0; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "adds %[left], %[right] \n\t" /* Add first word. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + + /* Now we just do the remaining words with the carry bit (using ADC) */ + REPEAT(DEC(uECC_WORDS), + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "adcs %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t") + + "adcs %[carry], %[carry] \n\t" /* Store carry bit. */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + #if (uECC_PLATFORM == uECC_arm_thumb) + : [dptr] "+l" (result), [lptr] "+l" (left), [rptr] "+l" (right), + [carry] "+l" (carry), [left] "=l" (left_word), [right] "=l" (right_word) + #else + : [dptr] "+r" (result), [lptr] "+r" (left), [rptr] "+r" (right), + [carry] "+r" (carry), [left] "=r" (left_word), [right] "=r" (right_word) + #endif + : + : "cc", "memory" + ); + return carry; +} +#define asm_add 1 + +static uint32_t vli_sub(uint32_t *result, const uint32_t *left, const uint32_t *right) { + uint32_t carry = 0; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "subs %[left], %[right] \n\t" /* Subtract. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + + /* Now we just do the remaining words with the carry bit (using SBC) */ + REPEAT(DEC(uECC_WORDS), + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "sbcs %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t") + + "adcs %[carry], %[carry] \n\t" /* Store carry bit. */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + #if (uECC_PLATFORM == uECC_arm_thumb) + : [dptr] "+l" (result), [lptr] "+l" (left), [rptr] "+l" (right), + [carry] "+l" (carry), [left] "=l" (left_word), [right] "=l" (right_word) + #else + : [dptr] "+r" (result), [lptr] "+r" (left), [rptr] "+r" (right), + [carry] "+r" (carry), [left] "=r" (left_word), [right] "=r" (right_word) + #endif + : + : "cc", "memory" + ); + return !carry; // note that on ARM, carry flag set means "no borrow" when subtracting + // (for some reason...) +} +#define asm_sub 1 + +#if (uECC_PLATFORM != uECC_arm_thumb) +#if (uECC_WORDS == 5) +static void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + + __asm__ volatile ( + ".syntax unified \n\t" + "add r0, 12 \n\t" + "add r2, 12 \n\t" + "ldmia r1!, {r3,r4} \n\t" + "ldmia r2!, {r6,r7} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adc r10, r14 \n\t" + "stmia r0!, {r9, r10} \n\t" + + "sub r0, 28 \n\t" + "sub r2, 20 \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + "ldmia r1!, {r5} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r4, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r5, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r4, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "umull r14, r9, r4, r7 \n\t" + "adds r10, r14 \n\t" + "adc r11, r9 \n\t" + "stmia r0!, {r10, r11} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1), "+r" (r2) + : + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_mult 1 +#endif /* (uECC_WORDS == 5) */ + +#if (uECC_WORDS == 6) +static void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + + __asm__ volatile ( + ".syntax unified \n\t" + "add r0, 12 \n\t" + "add r2, 12 \n\t" + "ldmia r1!, {r3,r4,r5} \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "mov r12, #0 \n\t" + "umull r14, r9, r4, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "umull r9, r10, r5, r8 \n\t" + "adds r11, r9 \n\t" + "adc r12, r10 \n\t" + "stmia r0!, {r11, r12} \n\t" + + "sub r0, 36 \n\t" + "sub r2, 24 \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r4, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r5, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r4, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r1!, {r5} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r2!, {r8} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r3, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r4, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "mov r14, #0 \n\t" + "umull r9, r10, r4, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r5, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "umull r10, r11, r5, r8 \n\t" + "adds r12, r10 \n\t" + "adc r14, r11 \n\t" + "stmia r0!, {r12, r14} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1), "+r" (r2) + : + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_mult 1 +#endif /* (uECC_WORDS == 6) */ + +#if (uECC_WORDS == 7) +static void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + + __asm__ volatile ( + ".syntax unified \n\t" + "add r0, 24 \n\t" + "add r2, 24 \n\t" + "ldmia r1!, {r3} \n\t" + "ldmia r2!, {r6} \n\t" + + "umull r9, r10, r3, r6 \n\t" + "stmia r0!, {r9, r10} \n\t" + + "sub r0, 20 \n\t" + "sub r2, 16 \n\t" + "ldmia r2!, {r6, r7, r8} \n\t" + "ldmia r1!, {r4, r5} \n\t" + + "umull r9, r10, r3, r6 \n\t" + "stmia r0!, {r9} \n\t" + + "mov r14, #0 \n\t" + "umull r9, r12, r3, r7 \n\t" + "adds r10, r9 \n\t" + "adc r12, #0 \n\t" + "umull r9, r11, r4, r6 \n\t" + "adds r10, r9 \n\t" + "adcs r12, r11 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "mov r12, #0 \n\t" + "umull r14, r9, r5, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "umull r9, r10, r3, r6 \n\t" + "adds r11, r9 \n\t" + "adc r12, r10 \n\t" + "stmia r0!, {r11, r12} \n\t" + + "sub r0, 44 \n\t" + "sub r1, 16 \n\t" + "sub r2, 28 \n\t" + "ldmia r1!, {r3,r4,r5} \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + + "umull r9, r10, r3, r6 \n\t" + "stmia r0!, {r9} \n\t" + + "mov r14, #0 \n\t" + "umull r9, r12, r3, r7 \n\t" + "adds r10, r9 \n\t" + "adc r12, #0 \n\t" + "umull r9, r11, r4, r6 \n\t" + "adds r10, r9 \n\t" + "adcs r12, r11 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r5, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r1!, {r5} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r3, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r4, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r4, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r5, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r4, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r5, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r3, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r4, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r5, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r2!, {r8} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r4, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r3, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r4, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "mov r14, #0 \n\t" + "umull r9, r10, r5, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "umull r10, r11, r3, r6 \n\t" + "adds r12, r10 \n\t" + "adc r14, r11 \n\t" + "stmia r0!, {r12, r14} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1), "+r" (r2) + : + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_mult 1 +#endif /* (uECC_WORDS == 7) */ + +#if (uECC_WORDS == 8) +static void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + + __asm__ volatile ( + ".syntax unified \n\t" + "add r0, 24 \n\t" + "add r2, 24 \n\t" + "ldmia r1!, {r3,r4} \n\t" + "ldmia r2!, {r6,r7} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adc r10, r14 \n\t" + "stmia r0!, {r9, r10} \n\t" + + "sub r0, 28 \n\t" + "sub r2, 20 \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + "ldmia r1!, {r5} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r4, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r5, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r4, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "umull r14, r9, r4, r7 \n\t" + "adds r10, r14 \n\t" + "adc r11, r9 \n\t" + "stmia r0!, {r10, r11} \n\t" + + "sub r0, 52 \n\t" + "sub r1, 20 \n\t" + "sub r2, 32 \n\t" + "ldmia r1!, {r3,r4,r5} \n\t" + "ldmia r2!, {r6,r7,r8} \n\t" + + "umull r11, r12, r3, r6 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r9, r3, r7 \n\t" + "adds r12, r11 \n\t" + "adc r9, #0 \n\t" + "umull r11, r14, r4, r6 \n\t" + "adds r12, r11 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r11, #0 \n\t" + "umull r12, r14, r3, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r5, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r4, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r5, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r5, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r4, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r1!, {r5} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r3, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r5, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r4, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r5, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r1!, {r4} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r5, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r3, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r12, #0 \n\t" + "umull r14, r9, r5, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r3, r8 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r4, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r10, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r14, #0 \n\t" + "umull r9, r10, r5, r7 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r3, r6 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "umull r9, r10, r4, r8 \n\t" + "adds r11, r9 \n\t" + "adcs r12, r10 \n\t" + "adc r14, #0 \n\t" + "ldr r9, [r0] \n\t" + "adds r11, r9 \n\t" + "adcs r12, #0 \n\t" + "adc r14, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "ldmia r2!, {r8} \n\t" + "mov r9, #0 \n\t" + "umull r10, r11, r5, r8 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r3, r7 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "umull r10, r11, r4, r6 \n\t" + "adds r12, r10 \n\t" + "adcs r14, r11 \n\t" + "adc r9, #0 \n\t" + "ldr r10, [r0] \n\t" + "adds r12, r10 \n\t" + "adcs r14, #0 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "ldmia r2!, {r6} \n\t" + "mov r10, #0 \n\t" + "umull r11, r12, r5, r6 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r8 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r4, r7 \n\t" + "adds r14, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "ldr r11, [r0] \n\t" + "adds r14, r11 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r14} \n\t" + + "ldmia r2!, {r7} \n\t" + "mov r11, #0 \n\t" + "umull r12, r14, r5, r7 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r3, r6 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "umull r12, r14, r4, r8 \n\t" + "adds r9, r12 \n\t" + "adcs r10, r14 \n\t" + "adc r11, #0 \n\t" + "ldr r12, [r0] \n\t" + "adds r9, r12 \n\t" + "adcs r10, #0 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "mov r12, #0 \n\t" + "umull r14, r9, r3, r7 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "umull r14, r9, r4, r6 \n\t" + "adds r10, r14 \n\t" + "adcs r11, r9 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r10} \n\t" + + "umull r9, r10, r4, r7 \n\t" + "adds r11, r9 \n\t" + "adc r12, r10 \n\t" + "stmia r0!, {r11, r12} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1), "+r" (r2) + : + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_mult 1 +#endif /* (uECC_WORDS == 8) */ + +#if uECC_SQUARE_FUNC +#if (uECC_WORDS == 5) +static void vli_square(uint32_t *result, const uint32_t *left) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia r1!, {r2,r3,r4,r5,r6} \n\t" + + "umull r11, r12, r2, r2 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r2, r3 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11, #0 \n\t" + "adc r9, #0 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r12, r2, r4 \n\t" + "adds r11, r11 \n\t" + "adcs r12, r12 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r3 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r5 \n\t" + "umull r1, r14, r3, r4 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r2, r6 \n\t" + "umull r1, r14, r3, r5 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "umull r1, r14, r4, r4 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r3, r6 \n\t" + "umull r1, r14, r4, r5 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r8, #0 \n\t" + "umull r1, r10, r4, r6 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r8, #0 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "umull r1, r10, r5, r5 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r11, #0 \n\t" + "umull r1, r10, r5, r6 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r11, #0 \n\t" + "adds r12, r1 \n\t" + "adcs r8, r10 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r1, r10, r6, r6 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r10 \n\t" + "stmia r0!, {r8, r11} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1) + : + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_square 1 +#endif /* (uECC_WORDS == 5) */ + +#if (uECC_WORDS == 6) +static void vli_square(uint32_t *result, const uint32_t *left) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia r1!, {r2,r3,r4,r5,r6,r7} \n\t" + + "umull r11, r12, r2, r2 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r2, r3 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11, #0 \n\t" + "adc r9, #0 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r12, r2, r4 \n\t" + "adds r11, r11 \n\t" + "adcs r12, r12 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r3 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r5 \n\t" + "umull r1, r14, r3, r4 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r2, r6 \n\t" + "umull r1, r14, r3, r5 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "umull r1, r14, r4, r4 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r7 \n\t" + "umull r1, r14, r3, r6 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "umull r1, r14, r4, r5 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r3, r7 \n\t" + "umull r1, r14, r4, r6 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "umull r1, r14, r5, r5 \n\t" + "adds r8, r1 \n\t" + "adcs r9, r14 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r4, r7 \n\t" + "umull r1, r14, r5, r6 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r14 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r8, #0 \n\t" + "umull r1, r10, r5, r7 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r8, #0 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "umull r1, r10, r6, r6 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r11, #0 \n\t" + "umull r1, r10, r6, r7 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r11, #0 \n\t" + "adds r12, r1 \n\t" + "adcs r8, r10 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r1, r10, r7, r7 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r10 \n\t" + "stmia r0!, {r8, r11} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1) + : + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_square 1 +#endif /* (uECC_WORDS == 6) */ + +#if (uECC_WORDS == 7) +static void vli_square(uint32_t *result, const uint32_t *left) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia r1!, {r2} \n\t" + "add r1, 20 \n\t" + "ldmia r1!, {r5} \n\t" + "add r0, 24 \n\t" + "umull r8, r9, r2, r5 \n\t" + "stmia r0!, {r8, r9} \n\t" + "sub r0, 32 \n\t" + "sub r1, 28 \n\t" + + "ldmia r1!, {r2, r3, r4, r5, r6, r7} \n\t" + + "umull r11, r12, r2, r2 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r2, r3 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11, #0 \n\t" + "adc r9, #0 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r12, r2, r4 \n\t" + "adds r11, r11 \n\t" + "adcs r12, r12 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r3 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r5 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r3, r4 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r2, r6 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r3, r5 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r4, r4 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r7 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r3, r6 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r4, r5 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "ldmia r1!, {r2} \n\t" + "mov r10, #0 \n\t" + "umull r8, r9, r3, r7 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r4, r6 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r5, r5 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r3, r2 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r4, r7 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r5, r6 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r4, r2 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r5, r7 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r6, r6 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r5, r2 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r6, r7 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r8, #0 \n\t" + "umull r1, r10, r6, r2 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r8, #0 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "umull r1, r10, r7, r7 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r11, #0 \n\t" + "umull r1, r10, r7, r2 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r11, #0 \n\t" + "adds r12, r1 \n\t" + "adcs r8, r10 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r1, r10, r2, r2 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r10 \n\t" + "stmia r0!, {r8, r11} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1) + : + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_square 1 +#endif /* (uECC_WORDS == 7) */ + +#if (uECC_WORDS == 8) +static void vli_square(uint32_t *result, const uint32_t *left) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + + __asm__ volatile ( + ".syntax unified \n\t" + "ldmia r1!, {r2, r3} \n\t" + "add r1, 16 \n\t" + "ldmia r1!, {r5, r6} \n\t" + "add r0, 24 \n\t" + + "umull r8, r9, r2, r5 \n\t" + "stmia r0!, {r8} \n\t" + + "umull r12, r10, r2, r6 \n\t" + "adds r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r9} \n\t" + + "umull r8, r9, r3, r6 \n\t" + "adds r10, r8 \n\t" + "adc r11, r9, #0 \n\t" + "stmia r0!, {r10, r11} \n\t" + + "sub r0, 40 \n\t" + "sub r1, 32 \n\t" + "ldmia r1!, {r2,r3,r4,r5,r6,r7} \n\t" + + "umull r11, r12, r2, r2 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r9, #0 \n\t" + "umull r10, r11, r2, r3 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11, #0 \n\t" + "adc r9, #0 \n\t" + "adds r12, r10 \n\t" + "adcs r8, r11 \n\t" + "adc r9, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "mov r10, #0 \n\t" + "umull r11, r12, r2, r4 \n\t" + "adds r11, r11 \n\t" + "adcs r12, r12 \n\t" + "adc r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "umull r11, r12, r3, r3 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r5 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r3, r4 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r2, r6 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r3, r5 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r4, r4 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r2, r7 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r3, r6 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r4, r5 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "ldmia r1!, {r2} \n\t" + "mov r10, #0 \n\t" + "umull r8, r9, r3, r7 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r4, r6 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r5, r5 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r3, r2 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r4, r7 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r5, r6 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "ldmia r1!, {r3} \n\t" + "mov r10, #0 \n\t" + "umull r8, r9, r4, r2 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r5, r7 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r9, #0 \n\t" + "adc r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r6, r6 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r4, r3 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r5, r2 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r6, r7 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "ldr r14, [r0] \n\t" + "adds r8, r14 \n\t" + "adcs r11, #0 \n\t" + "adc r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r10, #0 \n\t" + "umull r8, r9, r5, r3 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r6, r2 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r9, r9 \n\t" + "adc r10, r10 \n\t" + "mov r14, r9 \n\t" + "umlal r8, r9, r7, r7 \n\t" + "cmp r14, r9 \n\t" + "it hi \n\t" + "adchi r10, #0 \n\t" + "adds r8, r11 \n\t" + "adcs r9, r12 \n\t" + "adc r10, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r12, #0 \n\t" + "umull r8, r11, r6, r3 \n\t" + "mov r14, r11 \n\t" + "umlal r8, r11, r7, r2 \n\t" + "cmp r14, r11 \n\t" + "it hi \n\t" + "adchi r12, #0 \n\t" + "adds r8, r8 \n\t" + "adcs r11, r11 \n\t" + "adc r12, r12 \n\t" + "adds r8, r9 \n\t" + "adcs r11, r10 \n\t" + "adc r12, #0 \n\t" + "stmia r0!, {r8} \n\t" + + "mov r8, #0 \n\t" + "umull r1, r10, r7, r3 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r8, #0 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "umull r1, r10, r2, r2 \n\t" + "adds r11, r1 \n\t" + "adcs r12, r10 \n\t" + "adc r8, #0 \n\t" + "stmia r0!, {r11} \n\t" + + "mov r11, #0 \n\t" + "umull r1, r10, r2, r3 \n\t" + "adds r1, r1 \n\t" + "adcs r10, r10 \n\t" + "adc r11, #0 \n\t" + "adds r12, r1 \n\t" + "adcs r8, r10 \n\t" + "adc r11, #0 \n\t" + "stmia r0!, {r12} \n\t" + + "umull r1, r10, r3, r3 \n\t" + "adds r8, r1 \n\t" + "adcs r11, r10 \n\t" + "stmia r0!, {r8, r11} \n\t" + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : "+r" (r0), "+r" (r1) + : + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_square 1 +#endif /* (uECC_WORDS == 8) */ +#endif /* uECC_SQUARE_FUNC */ + +#endif /* (uECC_PLATFORM != uECC_arm_thumb) */ +#endif /* (uECC_ASM == uECC_asm_fast) */ + +#if !defined(asm_add) || !asm_add +static uint32_t vli_add(uint32_t *result, const uint32_t *left, const uint32_t *right) { + uint32_t counter = uECC_WORDS; + uint32_t carry = 0; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "1: \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ + "adcs %[left], %[right] \n\t" /* Add with carry. */ + "adcs %[carry], %[carry] \n\t" /* Store carry bit. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + "subs %[ctr], #1 \n\t" /* Decrement counter. */ + "bne 1b \n\t" /* Loop until counter == 0. */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + #if (uECC_PLATFORM == uECC_arm_thumb) + : [dptr] "+l" (result), [lptr] "+l" (left), [rptr] "+l" (right), + [ctr] "+l" (counter), [carry] "+l" (carry), + [left] "=l" (left_word), [right] "=l" (right_word) + #else + : [dptr] "+r" (result), [lptr] "+r" (left), [rptr] "+r" (right), + [ctr] "+r" (counter), [carry] "+r" (carry), + [left] "=r" (left_word), [right] "=r" (right_word) + #endif + : + : "cc", "memory" + ); + return carry; +} +#define asm_add 1 +#endif + +#if !defined(asm_sub) || !asm_sub +static uint32_t vli_sub(uint32_t *result, const uint32_t *left, const uint32_t *right) { + uint32_t counter = uECC_WORDS; + uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */ + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "1: \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ + "sbcs %[left], %[right] \n\t" /* Subtract with borrow. */ + "adcs %[carry], %[carry] \n\t" /* Store carry bit. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + "subs %[ctr], #1 \n\t" /* Decrement counter. */ + "bne 1b \n\t" /* Loop until counter == 0. */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + #if (uECC_PLATFORM == uECC_arm_thumb) + : [dptr] "+l" (result), [lptr] "+l" (left), [rptr] "+l" (right), + [ctr] "+l" (counter), [carry] "+l" (carry), + [left] "=l" (left_word), [right] "=l" (right_word) + #else + : [dptr] "+r" (result), [lptr] "+r" (left), [rptr] "+r" (right), + [ctr] "+r" (counter), [carry] "+r" (carry), + [left] "=r" (left_word), [right] "=r" (right_word) + #endif + : + : "cc", "memory" + ); + return !carry; +} +#define asm_sub 1 +#endif + +#if !defined(asm_mult) || !asm_mult +static void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) { +#if (uECC_PLATFORM != uECC_arm_thumb) + uint32_t c0 = 0; + uint32_t c1 = 0; + uint32_t c2 = 0; + uint32_t k = 0; + uint32_t i; + uint32_t t0, t1; + + __asm__ volatile ( + ".syntax unified \n\t" + + "1: \n\t" /* outer loop (k < uECC_WORDS) */ + "movs %[i], #0 \n\t" /* i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= uECC_WORDS) */ + "movs %[i], %[k] \n\t" /* i = k */ + "subs %[i], %[eccdm1] \n\t" /* i = k - (uECC_WORDS - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ + + "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */ + "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ + + "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ + + "adds %[c0], %[t0] \n\t" /* add low word to c0 */ + "adcs %[c1], %[t1] \n\t" /* add high word to c1, including carry */ + "adcs %[c2], #0 \n\t" /* add carry to c2 */ + + "adds %[i], #4 \n\t" /* i += 4 */ + "cmp %[i], %[eccd] \n\t" /* i < uECC_WORDS (times 4)? */ + "bge 4f \n\t" /* if not, exit the loop */ + "cmp %[i], %[k] \n\t" /* i <= k? */ + "ble 3b \n\t" /* if so, continue looping */ + + "4: \n\t" /* end inner loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ + "mov %[c0], %[c1] \n\t" /* c0 = c1 */ + "mov %[c1], %[c2] \n\t" /* c1 = c2 */ + "movs %[c2], #0 \n\t" /* c2 = 0 */ + "adds %[k], #4 \n\t" /* k += 4 */ + "cmp %[k], %[eccd] \n\t" /* k < uECC_WORDS (times 4) ? */ + "blt 1b \n\t" /* if not, loop back, start with i = 0 */ + "cmp %[k], %[eccd2m1] \n\t" /* k < uECC_WORDS * 2 - 1 (times 4) ? */ + "blt 2b \n\t" /* if not, loop back, start with i = (k + 1) - uECC_WORDS */ + /* end outer loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[uECC_WORDS * 2 - 1] = c0 */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), + [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) + : [result] "r" (result), [left] "r" (left), [right] "r" (right), + [eccd] "I" (uECC_WORDS * 4), [eccdm1] "I" ((uECC_WORDS-1) * 4), + [eccd2m1] "I" ((uECC_WORDS * 2 - 1) * 4) + : "cc", "memory" + ); + +#else /* Thumb-1 */ + + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + + __asm__ volatile ( + ".syntax unified \n\t" + "movs r3, #0 \n\t" /* c0 = 0 */ + "movs r4, #0 \n\t" /* c1 = 0 */ + "movs r5, #0 \n\t" /* c2 = 0 */ + "movs r6, #0 \n\t" /* k = 0 */ + + "push {r0} \n\t" /* keep result on the stack */ + + "1: \n\t" /* outer loop (k < uECC_WORDS) */ + "movs r7, #0 \n\t" /* r7 = i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= uECC_WORDS) */ + "movs r7, r6 \n\t" /* r7 = k */ + "subs r7, %[eccdm1] \n\t" /* r7 = i = k - (uECC_WORDS - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "push {r3, r4, r5, r6} \n\t" /* push things, r3 (c0) is at the top of stack. */ + "subs r0, r6, r7 \n\t" /* r0 = k - i */ + + "ldr r4, [r2, r0] \n\t" /* r4 = right[k - i] */ + "ldr r0, [r1, r7] \n\t" /* r0 = left[i] */ + + "lsrs r3, r0, #16 \n\t" /* r3 = a1 */ + "uxth r0, r0 \n\t" /* r0 = a0 */ + + "lsrs r5, r4, #16 \n\t" /* r5 = b1 */ + "uxth r4, r4 \n\t" /* r4 = b0 */ + + "movs r6, r3 \n\t" /* r6 = a1 */ + "muls r6, r5, r6 \n\t" /* r6 = a1 * b1 */ + "muls r3, r4, r3 \n\t" /* r3 = b0 * a1 */ + "muls r5, r0, r5 \n\t" /* r5 = a0 * b1 */ + "muls r0, r4, r0 \n\t" /* r0 = a0 * b0 */ + + "movs r4, #0 \n\t" /* r4 = 0 */ + "adds r3, r5 \n\t" /* r3 = b0 * a1 + a0 * b1 */ + "adcs r4, r4 \n\t" /* r4 = carry */ + "lsls r4, #16 \n\t" /* r4 = carry << 16 */ + "adds r6, r4 \n\t" /* r6 = a1 * b1 + carry */ + + "lsls r4, r3, #16 \n\t" /* r4 = (b0 * a1 + a0 * b1) << 16 */ + "lsrs r3, #16 \n\t" /* r3 = (b0 * a1 + a0 * b1) >> 16 */ + "adds r0, r4 \n\t" /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */ + "adcs r6, r3 \n\t" /* r6 = high word = a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */ + + "pop {r3, r4, r5} \n\t" /* r3 = c0, r4 = c1, r5 = c2 */ + "adds r3, r0 \n\t" /* add low word to c0 */ + "adcs r4, r6 \n\t" /* add high word to c1, including carry */ + "movs r0, #0 \n\t" /* r0 = 0 (does not affect carry bit) */ + "adcs r5, r0 \n\t" /* add carry to c2 */ + + "pop {r6} \n\t" /* r6 = k */ + + "adds r7, #4 \n\t" /* i += 4 */ + "cmp r7, %[eccd] \n\t" /* i < uECC_WORDS (times 4)? */ + "bge 4f \n\t" /* if not, exit the loop */ + "cmp r7, r6 \n\t" /* i <= k? */ + "ble 3b \n\t" /* if so, continue looping */ + + "4: \n\t" /* end inner loop */ + + "ldr r0, [sp, #0] \n\t" /* r0 = result */ + + "str r3, [r0, r6] \n\t" /* result[k] = c0 */ + "mov r3, r4 \n\t" /* c0 = c1 */ + "mov r4, r5 \n\t" /* c1 = c2 */ + "movs r5, #0 \n\t" /* c2 = 0 */ + "adds r6, #4 \n\t" /* k += 4 */ + "cmp r6, %[eccd] \n\t" /* k < uECC_WORDS (times 4) ? */ + "blt 1b \n\t" /* if not, loop back, start with i = 0 */ + "cmp r6, %[eccd2m1] \n\t" /* k < uECC_WORDS * 2 - 1 (times 4) ? */ + "blt 2b \n\t" /* if not, loop back, start with i = (k + 1) - uECC_WORDS */ + /* end outer loop */ + + "str r3, [r0, r6] \n\t" /* result[uECC_WORDS * 2 - 1] = c0 */ + "pop {r0} \n\t" /* pop result off the stack */ + + ".syntax divided \n\t" + : + : [r0] "l" (r0), [r1] "l" (r1), [r2] "l" (r2), [eccd] "I" (uECC_WORDS * 4), [eccdm1] "I" ((uECC_WORDS-1) * 4), [eccd2m1] "I" ((uECC_WORDS * 2 - 1) * 4) + : "r3", "r4", "r5", "r6", "r7", "cc", "memory" + ); +#endif +} +#define asm_mult 1 +#endif /* !asm_mult */ + +#if uECC_SQUARE_FUNC +#if !defined(asm_square) || !asm_square +static void vli_square(uint32_t *result, const uint32_t *left) { +#if (uECC_PLATFORM != uECC_arm_thumb) + uint32_t c0 = 0; + uint32_t c1 = 0; + uint32_t c2 = 0; + uint32_t k = 0; + uint32_t i, tt; + uint32_t t0, t1; + + __asm__ volatile ( + ".syntax unified \n\t" + + "1: \n\t" /* outer loop (k < uECC_WORDS) */ + "movs %[i], #0 \n\t" /* i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= uECC_WORDS) */ + "movs %[i], %[k] \n\t" /* i = k */ + "subs %[i], %[eccdm1] \n\t" /* i = k - (uECC_WORDS - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ + + "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */ + "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ + + "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ + + "cmp %[i], %[tt] \n\t" /* (i < k - i) ? */ + "bge 4f \n\t" /* if i >= k - i, skip */ + "lsls %[t1], #1 \n\t" /* high word << 1 */ + "adc %[c2], #0 \n\t" /* add carry bit to c2 */ + "lsls %[t0], #1 \n\t" /* low word << 1 */ + "adc %[t1], #0 \n\t" /* add carry bit to high word */ + + "4: \n\t" + + "adds %[c0], %[t0] \n\t" /* add low word to c0 */ + "adcs %[c1], %[t1] \n\t" /* add high word to c1, including carry */ + "adc %[c2], #0 \n\t" /* add carry to c2 */ + + "adds %[i], #4 \n\t" /* i += 4 */ + "cmp %[i], %[k] \n\t" /* i <= k? */ + "bge 5f \n\t" /* if not, exit the loop */ + "subs %[tt], %[k], %[i] \n\t" /* tt = k - i */ + "cmp %[i], %[tt] \n\t" /* i <= k - i? */ + "ble 3b \n\t" /* if so, continue looping */ + + "5: \n\t" /* end inner loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ + "mov %[c0], %[c1] \n\t" /* c0 = c1 */ + "mov %[c1], %[c2] \n\t" /* c1 = c2 */ + "movs %[c2], #0 \n\t" /* c2 = 0 */ + "adds %[k], #4 \n\t" /* k += 4 */ + "cmp %[k], %[eccd] \n\t" /* k < uECC_WORDS (times 4) ? */ + "blt 1b \n\t" /* if not, loop back, start with i = 0 */ + "cmp %[k], %[eccd2m1] \n\t" /* k < uECC_WORDS * 2 - 1 (times 4) ? */ + "blt 2b \n\t" /* if not, loop back, start with i = (k + 1) - uECC_WORDS */ + /* end outer loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[uECC_WORDS * 2 - 1] = c0 */ + #if (uECC_PLATFORM != uECC_arm_thumb2) + ".syntax divided \n\t" + #endif + : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), + [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) + : [result] "r" (result), [left] "r" (left), + [eccd] "I" (uECC_WORDS * 4), [eccdm1] "I" ((uECC_WORDS-1) * 4), + [eccd2m1] "I" ((uECC_WORDS * 2 - 1) * 4) + : "cc", "memory" + ); + +#else + + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + + __asm__ volatile ( + ".syntax unified \n\t" + "movs r2, #0 \n\t" /* c0 = 0 */ + "movs r3, #0 \n\t" /* c1 = 0 */ + "movs r4, #0 \n\t" /* c2 = 0 */ + "movs r5, #0 \n\t" /* k = 0 */ + + "push {r0} \n\t" /* keep result on the stack */ + + "1: \n\t" /* outer loop (k < uECC_WORDS) */ + "movs r6, #0 \n\t" /* r6 = i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= uECC_WORDS) */ + "movs r6, r5 \n\t" /* r6 = k */ + "subs r6, %[eccdm1] \n\t" /* r6 = i = k - (uECC_WORDS - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "push {r2, r3, r4, r5} \n\t" /* push things, r2 (c0) is at the top of stack. */ + "subs r7, r5, r6 \n\t" /* r7 = k - i */ + + "ldr r3, [r1, r7] \n\t" /* r3 = left[k - i] */ + "ldr r0, [r1, r6] \n\t" /* r0 = left[i] */ + + "lsrs r2, r0, #16 \n\t" /* r2 = a1 */ + "uxth r0, r0 \n\t" /* r0 = a0 */ + + "lsrs r4, r3, #16 \n\t" /* r4 = b1 */ + "uxth r3, r3 \n\t" /* r3 = b0 */ + + "movs r5, r2 \n\t" /* r5 = a1 */ + "muls r5, r4, r5 \n\t" /* r5 = a1 * b1 */ + "muls r2, r3, r2 \n\t" /* r2 = b0 * a1 */ + "muls r4, r0, r4 \n\t" /* r4 = a0 * b1 */ + "muls r0, r3, r0 \n\t" /* r0 = a0 * b0 */ + + "movs r3, #0 \n\t" /* r3 = 0 */ + "adds r2, r4 \n\t" /* r2 = b0 * a1 + a0 * b1 */ + "adcs r3, r3 \n\t" /* r3 = carry */ + "lsls r3, #16 \n\t" /* r3 = carry << 16 */ + "adds r5, r3 \n\t" /* r5 = a1 * b1 + carry */ + + "lsls r3, r2, #16 \n\t" /* r3 = (b0 * a1 + a0 * b1) << 16 */ + "lsrs r2, #16 \n\t" /* r2 = (b0 * a1 + a0 * b1) >> 16 */ + "adds r0, r3 \n\t" /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */ + "adcs r5, r2 \n\t" /* r5 = high word = a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */ + + "movs r3, #0 \n\t" /* r3 = 0 */ + "cmp r6, r7 \n\t" /* (i < k - i) ? */ + "mov r7, r3 \n\t" /* r7 = 0 (does not affect condition)*/ + "bge 4f \n\t" /* if i >= k - i, skip */ + "lsls r5, #1 \n\t" /* high word << 1 */ + "adcs r7, r3 \n\t" /* r7 = carry bit for c2 */ + "lsls r0, #1 \n\t" /* low word << 1 */ + "adcs r5, r3 \n\t" /* add carry from shift to high word */ + + "4: \n\t" + "pop {r2, r3, r4} \n\t" /* r2 = c0, r3 = c1, r4 = c2 */ + "adds r2, r0 \n\t" /* add low word to c0 */ + "adcs r3, r5 \n\t" /* add high word to c1, including carry */ + "movs r0, #0 \n\t" /* r0 = 0 (does not affect carry bit) */ + "adcs r4, r0 \n\t" /* add carry to c2 */ + "adds r4, r7 \n\t" /* add carry from doubling (if any) */ + + "pop {r5} \n\t" /* r5 = k */ + + "adds r6, #4 \n\t" /* i += 4 */ + "cmp r6, r5 \n\t" /* i <= k? */ + "bge 5f \n\t" /* if not, exit the loop */ + "subs r7, r5, r6 \n\t" /* r7 = k - i */ + "cmp r6, r7 \n\t" /* i <= k - i? */ + "ble 3b \n\t" /* if so, continue looping */ + + "5: \n\t" /* end inner loop */ + + "ldr r0, [sp, #0] \n\t" /* r0 = result */ + + "str r2, [r0, r5] \n\t" /* result[k] = c0 */ + "mov r2, r3 \n\t" /* c0 = c1 */ + "mov r3, r4 \n\t" /* c1 = c2 */ + "movs r4, #0 \n\t" /* c2 = 0 */ + "adds r5, #4 \n\t" /* k += 4 */ + "cmp r5, %[eccd] \n\t" /* k < uECC_WORDS (times 4) ? */ + "blt 1b \n\t" /* if not, loop back, start with i = 0 */ + "cmp r5, %[eccd2m1] \n\t" /* k < uECC_WORDS * 2 - 1 (times 4) ? */ + "blt 2b \n\t" /* if not, loop back, start with i = (k + 1) - uECC_WORDS */ + /* end outer loop */ + + "str r2, [r0, r5] \n\t" /* result[uECC_WORDS * 2 - 1] = c0 */ + "pop {r0} \n\t" /* pop result off the stack */ + + ".syntax divided \n\t" + : [r0] "+l" (r0), [r1] "+l" (r1) + : [eccd] "I" (uECC_WORDS * 4), [eccdm1] "I" ((uECC_WORDS-1) * 4), + [eccd2m1] "I" ((uECC_WORDS * 2 - 1) * 4) + : "r2", "r3", "r4", "r5", "r6", "r7", "cc", "memory" + ); +#endif +} +#define asm_square 1 +#endif /* !asm_square */ +#endif /* uECC_SQUARE_FUNC */ diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.c b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.c new file mode 100644 index 0000000000..c15cbcf1b7 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.c @@ -0,0 +1,1038 @@ +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#include +#include "uECC_ll.h" + +#ifndef uECC_PLATFORM + #if defined(__AVR__) && __AVR__ + #define uECC_PLATFORM uECC_avr + #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ + #define uECC_PLATFORM uECC_arm_thumb2 + #elif defined(__thumb__) + #define uECC_PLATFORM uECC_arm_thumb + #elif defined(__arm__) || defined(_M_ARM) + #define uECC_PLATFORM uECC_arm + #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) + #define uECC_PLATFORM uECC_x86 + #elif defined(__amd64__) || defined(_M_X64) + #define uECC_PLATFORM uECC_x86_64 + #else + #define uECC_PLATFORM uECC_arch_other + #endif +#endif + +#define uECC_WORD_SIZE 4 + +#if __STDC_VERSION__ >= 199901L + #define RESTRICT restrict +#else + #define RESTRICT +#endif + +#define SUPPORTS_INT128 0 + +#define MAX_TRIES 64 + +/* #if uECC_WORD_SIZE == 4 */ +typedef uint32_t uECC_word_t; +typedef uint64_t uECC_dword_t; +typedef unsigned wordcount_t; +typedef int swordcount_t; +typedef int bitcount_t; +typedef int cmpresult_t; + +#define HIGH_BIT_SET 0x80000000 +#define uECC_WORD_BITS 32 +#define uECC_WORD_BITS_SHIFT 5 +#define uECC_WORD_BITS_MASK 0x01F + +#define uECC_WORDS_1 5 +#define uECC_WORDS_2 6 +#define uECC_WORDS_3 8 +#define uECC_WORDS_4 8 +#define uECC_WORDS_5 7 + +#define uECC_N_WORDS_1 6 +#define uECC_N_WORDS_2 6 +#define uECC_N_WORDS_3 8 +#define uECC_N_WORDS_4 8 +#define uECC_N_WORDS_5 7 + +#define Curve_P_1 {0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_P_2 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_P_3 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF} +#define Curve_P_4 {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, \ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_P_5 {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, \ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} + +#define Curve_B_1 {0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC} +#define Curve_B_2 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519} +#define Curve_B_3 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, \ + 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8} +#define Curve_B_4 {0x00000007, 0x00000000, 0x00000000, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000000, 0x00000000} +#define Curve_B_5 {0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, \ + 0xF5413256, 0x0C04B3AB, 0xB4050A85} + +#define Curve_G_1 { \ + {0x13CBFC82, 0x68C38BB9, 0x46646989, 0x8EF57328, 0x4A96B568}, \ + {0x7AC5FB32, 0x04235137, 0x59DCC912, 0x3168947D, 0x23A62855}} + +#define Curve_G_2 { \ + {0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E}, \ + {0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95}} + +#define Curve_G_3 { \ + {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, \ + 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \ + {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, \ + 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}} + +#define Curve_G_4 { \ + {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, \ + 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \ + {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, \ + 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}} + +#define Curve_G_5 { \ + {0x115C1D21, 0x343280D6, 0x56C21122, 0x4A03C1D3, \ + 0x321390B9, 0x6BB4BF7F, 0xB70E0CBD}, \ + {0x85007E34, 0x44D58199, 0x5A074764, 0xCD4375A0, \ + 0x4C22DFE6, 0xB5F723FB, 0xBD376388}} + +#define Curve_N_1 {0xCA752257, 0xF927AED3, 0x0001F4C8, 0x00000000, 0x00000000, 0x00000001} +#define Curve_N_2 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_N_3 {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, \ + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF} +#define Curve_N_4 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, \ + 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_N_5 {0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, \ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} + +/* #endif */ + +#define uECC_WORDS uECC_CONCAT(uECC_WORDS_, uECC_CURVE) +#define uECC_N_WORDS uECC_CONCAT(uECC_N_WORDS_, uECC_CURVE) + +typedef struct EccPoint { + uECC_word_t x[uECC_WORDS]; + uECC_word_t y[uECC_WORDS]; +} EccPoint; + +static const uECC_word_t curve_p[uECC_WORDS] = uECC_CONCAT(Curve_P_, uECC_CURVE); +static const EccPoint curve_G = uECC_CONCAT(Curve_G_, uECC_CURVE); +static const uECC_word_t curve_n[uECC_N_WORDS] = uECC_CONCAT(Curve_N_, uECC_CURVE); + +static void vli_clear(uECC_word_t *vli); +static uECC_word_t vli_isZero(const uECC_word_t *vli); +static uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit); +static void vli_set(uECC_word_t *dest, const uECC_word_t *src); +static cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right); +static void vli_rshift1(uECC_word_t *vli); +static uECC_word_t vli_add(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right); +static uECC_word_t vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right); +static void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right); +static void vli_modAdd(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod); +static void vli_modSub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod); +static void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product); +static void vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right); +static void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod); +#if uECC_SQUARE_FUNC +static void vli_square(uECC_word_t *result, const uECC_word_t *left); +static void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left); +#endif + +static int default_RNG(uint8_t *dest, unsigned size) { + return 0; +} + + +static uECC_RNG_Function g_rng_function = &default_RNG; + +void uECC_set_rng(uECC_RNG_Function rng_function) { + g_rng_function = rng_function; +} + +#ifdef __GNUC__ /* Only support GCC inline asm for now */ + #if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ + uECC_PLATFORM == uECC_arm_thumb2)) + #include "asm_arm.inc" + #endif +#endif + +#if !defined(asm_clear) || !asm_clear +static void vli_clear(uECC_word_t *vli) { + wordcount_t i; + for (i = 0; i < uECC_WORDS; ++i) { + vli[i] = 0; + } +} +#endif + +/* Returns 1 if vli == 0, 0 otherwise. */ +#if !defined(asm_isZero) || !asm_isZero +static uECC_word_t vli_isZero(const uECC_word_t *vli) { + wordcount_t i; + for (i = 0; i < uECC_WORDS; ++i) { + if (vli[i]) { + return 0; + } + } + return 1; +} +#endif + +/* Returns nonzero if bit 'bit' of vli is set. */ +#if !defined(asm_testBit) || !asm_testBit +static uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit) { + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); +} +#endif + +/* Sets dest = src. */ +#if !defined(asm_set) || !asm_set +static void vli_set(uECC_word_t *dest, const uECC_word_t *src) { + wordcount_t i; + for (i = 0; i < uECC_WORDS; ++i) { + dest[i] = src[i]; + } +} +#endif + +/* Returns sign of left - right. */ +#if !defined(asm_cmp) || !asm_cmp +static cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right) { + swordcount_t i; + for (i = uECC_WORDS - 1; i >= 0; --i) { + if (left[i] > right[i]) { + return 1; + } else if (left[i] < right[i]) { + return -1; + } + } + return 0; +} +#endif + +/* Computes vli = vli >> 1. */ +#if !defined(asm_rshift1) || !asm_rshift1 +static void vli_rshift1(uECC_word_t *vli) { + uECC_word_t *end = vli; + uECC_word_t carry = 0; + + vli += uECC_WORDS; + while (vli-- > end) { + uECC_word_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << (uECC_WORD_BITS - 1); + } +} +#endif + +/* Computes result = left + right, returning carry. Can modify in place. */ +#if !defined(asm_add) || !asm_add +static uECC_word_t vli_add(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) { + uECC_word_t carry = 0; + wordcount_t i; + for (i = 0; i < uECC_WORDS; ++i) { + uECC_word_t sum = left[i] + right[i] + carry; + if (sum != left[i]) { + carry = (sum < left[i]); + } + result[i] = sum; + } + return carry; +} +#endif + +/* Computes result = left - right, returning borrow. Can modify in place. */ +#if !defined(asm_sub) || !asm_sub +static uECC_word_t vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) { + uECC_word_t borrow = 0; + wordcount_t i; + for (i = 0; i < uECC_WORDS; ++i) { + uECC_word_t diff = left[i] - right[i] - borrow; + if (diff != left[i]) { + borrow = (diff > left[i]); + } + result[i] = diff; + } + return borrow; +} +#endif + +#if (!asm_mult || (uECC_SQUARE_FUNC && !asm_square) || uECC_CURVE == uECC_secp256k1) +static void muladd(uECC_word_t a, + uECC_word_t b, + uECC_word_t *r0, + uECC_word_t *r1, + uECC_word_t *r2) { + uECC_dword_t p = (uECC_dword_t)a * b; + uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; + r01 += p; + *r2 += (r01 < p); + *r1 = r01 >> uECC_WORD_BITS; + *r0 = (uECC_word_t)r01; +} +#define muladd_exists 1 +#endif + +#if !asm_mult +static void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) { + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + wordcount_t i, k; + + /* Compute each digit of result in sequence, maintaining the carries. */ + for (k = 0; k < uECC_WORDS; ++k) { + for (i = 0; i <= k; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + for (k = uECC_WORDS; k < uECC_WORDS * 2 - 1; ++k) { + for (i = (k + 1) - uECC_WORDS; i < uECC_WORDS; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + result[uECC_WORDS * 2 - 1] = r0; +} +#endif + +#if uECC_SQUARE_FUNC + +#if !asm_square +static void mul2add(uECC_word_t a, + uECC_word_t b, + uECC_word_t *r0, + uECC_word_t *r1, + uECC_word_t *r2) { + uECC_dword_t p = (uECC_dword_t)a * b; + uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; + *r2 += (p >> (uECC_WORD_BITS * 2 - 1)); + p *= 2; + r01 += p; + *r2 += (r01 < p); + *r1 = r01 >> uECC_WORD_BITS; + *r0 = (uECC_word_t)r01; +} + +static void vli_square(uECC_word_t *result, const uECC_word_t *left) { + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + + wordcount_t i, k; + + for (k = 0; k < uECC_WORDS * 2 - 1; ++k) { + uECC_word_t min = (k < uECC_WORDS ? 0 : (k + 1) - uECC_WORDS); + for (i = min; i <= k && i <= k - i; ++i) { + if (i < k-i) { + mul2add(left[i], left[k - i], &r0, &r1, &r2); + } else { + muladd(left[i], left[k - i], &r0, &r1, &r2); + } + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + + result[uECC_WORDS * 2 - 1] = r0; +} +#endif + +#else /* uECC_SQUARE_FUNC */ + +#define vli_square(result, left, size) vli_mult((result), (left), (left), (size)) + +#endif /* uECC_SQUARE_FUNC */ + + +/* Computes result = (left + right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +#if !defined(asm_modAdd) || !asm_modAdd +static void vli_modAdd(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod) { + uECC_word_t carry = vli_add(result, left, right); + if (carry || vli_cmp(result, mod) >= 0) { + /* result > mod (result = mod + remainder), so subtract mod to get remainder. */ + vli_sub(result, result, mod); + } +} +#endif + +/* Computes result = (left - right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +#if !defined(asm_modSub) || !asm_modSub +static void vli_modSub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod) { + uECC_word_t l_borrow = vli_sub(result, left, right); + if (l_borrow) { + /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, + we can get the correct result from result + mod (with overflow). */ + vli_add(result, result, mod); + } +} +#endif + +#if !defined(asm_modSub_fast) || !asm_modSub_fast + #define vli_modSub_fast(result, left, right) vli_modSub((result), (left), (right), curve_p) +#endif + +#if !defined(asm_mmod_fast) || !asm_mmod_fast + +#if uECC_CURVE == uECC_secp256r1 + +/* Computes result = product % curve_p + from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +#if uECC_WORD_SIZE == 4 +static void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) { + uint32_t tmp[uECC_WORDS]; + int carry; + + /* t */ + vli_set(result, product); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = 0; + tmp[3] = product[11]; + tmp[4] = product[12]; + tmp[5] = product[13]; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry = vli_add(tmp, tmp, tmp); + carry += vli_add(result, result, tmp); + + /* s2 */ + tmp[3] = product[12]; + tmp[4] = product[13]; + tmp[5] = product[14]; + tmp[6] = product[15]; + tmp[7] = 0; + carry += vli_add(tmp, tmp, tmp); + carry += vli_add(result, result, tmp); + + /* s3 */ + tmp[0] = product[8]; + tmp[1] = product[9]; + tmp[2] = product[10]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry += vli_add(result, result, tmp); + + /* s4 */ + tmp[0] = product[9]; + tmp[1] = product[10]; + tmp[2] = product[11]; + tmp[3] = product[13]; + tmp[4] = product[14]; + tmp[5] = product[15]; + tmp[6] = product[13]; + tmp[7] = product[8]; + carry += vli_add(result, result, tmp); + + /* d1 */ + tmp[0] = product[11]; + tmp[1] = product[12]; + tmp[2] = product[13]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[8]; + tmp[7] = product[10]; + carry -= vli_sub(result, result, tmp); + + /* d2 */ + tmp[0] = product[12]; + tmp[1] = product[13]; + tmp[2] = product[14]; + tmp[3] = product[15]; + tmp[4] = tmp[5] = 0; + tmp[6] = product[9]; + tmp[7] = product[11]; + carry -= vli_sub(result, result, tmp); + + /* d3 */ + tmp[0] = product[13]; + tmp[1] = product[14]; + tmp[2] = product[15]; + tmp[3] = product[8]; + tmp[4] = product[9]; + tmp[5] = product[10]; + tmp[6] = 0; + tmp[7] = product[12]; + carry -= vli_sub(result, result, tmp); + + /* d4 */ + tmp[0] = product[14]; + tmp[1] = product[15]; + tmp[2] = 0; + tmp[3] = product[9]; + tmp[4] = product[10]; + tmp[5] = product[11]; + tmp[6] = 0; + tmp[7] = product[13]; + carry -= vli_sub(result, result, tmp); + + if (carry < 0) { + do { + carry += vli_add(result, result, curve_p); + } while (carry < 0); + } else { + while (carry || vli_cmp(curve_p, result) != 1) { + carry -= vli_sub(result, result, curve_p); + } + } +} +#endif /* uECC_WORD_SIZE */ +#endif /* uECC_CURVE */ +#endif /* !asm_mmod_fast */ + +/* Computes result = (left * right) % curve_p. */ +static void vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right) { + uECC_word_t product[2 * uECC_WORDS]; + vli_mult(product, left, right); + vli_mmod_fast(result, product); +} + +#if uECC_SQUARE_FUNC + +/* Computes result = left^2 % curve_p. */ +static void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left) { + uECC_word_t product[2 * uECC_WORDS]; + vli_square(product, left); + vli_mmod_fast(result, product); +} + +#else /* uECC_SQUARE_FUNC */ + +#define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left)) + +#endif /* uECC_SQUARE_FUNC */ + + +#define EVEN(vli) (!(vli[0] & 1)) +/* Computes result = (1 / input) % mod. All VLIs are the same size. + See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" + https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */ +#if !defined(asm_modInv) || !asm_modInv +static void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) { + uECC_word_t a[uECC_WORDS], b[uECC_WORDS], u[uECC_WORDS], v[uECC_WORDS]; + uECC_word_t carry; + cmpresult_t cmpResult; + + if (vli_isZero(input)) { + vli_clear(result); + return; + } + + vli_set(a, input); + vli_set(b, mod); + vli_clear(u); + u[0] = 1; + vli_clear(v); + while ((cmpResult = vli_cmp(a, b)) != 0) { + carry = 0; + if (EVEN(a)) { + vli_rshift1(a); + if (!EVEN(u)) { + carry = vli_add(u, u, mod); + } + vli_rshift1(u); + if (carry) { + u[uECC_WORDS - 1] |= HIGH_BIT_SET; + } + } else if (EVEN(b)) { + vli_rshift1(b); + if (!EVEN(v)) { + carry = vli_add(v, v, mod); + } + vli_rshift1(v); + if (carry) { + v[uECC_WORDS - 1] |= HIGH_BIT_SET; + } + } else if (cmpResult > 0) { + vli_sub(a, a, b); + vli_rshift1(a); + if (vli_cmp(u, v) < 0) { + vli_add(u, u, mod); + } + vli_sub(u, u, v); + if (!EVEN(u)) { + carry = vli_add(u, u, mod); + } + vli_rshift1(u); + if (carry) { + u[uECC_WORDS - 1] |= HIGH_BIT_SET; + } + } else { + vli_sub(b, b, a); + vli_rshift1(b); + if (vli_cmp(v, u) < 0) { + vli_add(v, v, mod); + } + vli_sub(v, v, u); + if (!EVEN(v)) { + carry = vli_add(v, v, mod); + } + vli_rshift1(v); + if (carry) { + v[uECC_WORDS - 1] |= HIGH_BIT_SET; + } + } + } + vli_set(result, u); +} +#endif /* !asm_modInv */ + +/* ------ Point operations ------ */ + +/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ +static cmpresult_t EccPoint_isZero(const EccPoint *point) { + return (vli_isZero(point->x) && vli_isZero(point->y)); +} + +/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. +From http://eprint.iacr.org/2011/338.pdf +*/ + +/* Double in place */ +static void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1, + uECC_word_t * RESTRICT Y1, + uECC_word_t * RESTRICT Z1) { + /* t1 = X, t2 = Y, t3 = Z */ + uECC_word_t t4[uECC_WORDS]; + uECC_word_t t5[uECC_WORDS]; + + if (vli_isZero(Z1)) { + return; + } + + vli_modSquare_fast(t4, Y1); /* t4 = y1^2 */ + vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */ + vli_modSquare_fast(t4, t4); /* t4 = y1^4 */ + vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */ + vli_modSquare_fast(Z1, Z1); /* t3 = z1^2 */ + + vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */ + vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */ + vli_modSub_fast(Z1, X1, Z1); /* t3 = x1 - z1^2 */ + vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */ + + vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */ + vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */ + if (vli_testBit(X1, 0)) { + uECC_word_t l_carry = vli_add(X1, X1, curve_p); + vli_rshift1(X1); + X1[uECC_WORDS - 1] |= l_carry << (uECC_WORD_BITS - 1); + } else { + vli_rshift1(X1); + } + /* t1 = 3/2*(x1^2 - z1^4) = B */ + + vli_modSquare_fast(Z1, X1); /* t3 = B^2 */ + vli_modSub_fast(Z1, Z1, t5); /* t3 = B^2 - A */ + vli_modSub_fast(Z1, Z1, t5); /* t3 = B^2 - 2A = x3 */ + vli_modSub_fast(t5, t5, Z1); /* t5 = A - x3 */ + vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */ + vli_modSub_fast(t4, X1, t4); /* t4 = B * (A - x3) - y1^4 = y3 */ + + vli_set(X1, Z1); + vli_set(Z1, Y1); + vli_set(Y1, t4); +} + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(uECC_word_t * RESTRICT X1, + uECC_word_t * RESTRICT Y1, + const uECC_word_t * RESTRICT Z) { + uECC_word_t t1[uECC_WORDS]; + + vli_modSquare_fast(t1, Z); /* z^2 */ + vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */ + vli_modMult_fast(t1, t1, Z); /* z^3 */ + vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */ +} + +/* P = (x1, y1) => 2P, (x2, y2) => P' */ +static void XYcZ_initial_double(uECC_word_t * RESTRICT X1, + uECC_word_t * RESTRICT Y1, + uECC_word_t * RESTRICT X2, + uECC_word_t * RESTRICT Y2, + const uECC_word_t * RESTRICT initial_Z) { + uECC_word_t z[uECC_WORDS]; + if (initial_Z) { + vli_set(z, initial_Z); + } else { + vli_clear(z); + z[0] = 1; + } + + vli_set(X2, X1); + vli_set(Y2, Y1); + + apply_z(X1, Y1, z); + EccPoint_double_jacobian(X1, Y1, z); + apply_z(X2, Y2, z); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) + or P => P', Q => P + Q +*/ +static void XYcZ_add(uECC_word_t * RESTRICT X1, + uECC_word_t * RESTRICT Y1, + uECC_word_t * RESTRICT X2, + uECC_word_t * RESTRICT Y2) { + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[uECC_WORDS]; + + vli_modSub_fast(t5, X2, X1); /* t5 = x2 - x1 */ + vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ + vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ + vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ + vli_modSub_fast(Y2, Y2, Y1); /* t4 = y2 - y1 */ + vli_modSquare_fast(t5, Y2); /* t5 = (y2 - y1)^2 = D */ + + vli_modSub_fast(t5, t5, X1); /* t5 = D - B */ + vli_modSub_fast(t5, t5, X2); /* t5 = D - B - C = x3 */ + vli_modSub_fast(X2, X2, X1); /* t3 = C - B */ + vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */ + vli_modSub_fast(X2, X1, t5); /* t3 = B - x3 */ + vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */ + vli_modSub_fast(Y2, Y2, Y1); /* t4 = y3 */ + + vli_set(X2, t5); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) + or P => P - Q, Q => P + Q +*/ +static void XYcZ_addC(uECC_word_t * RESTRICT X1, + uECC_word_t * RESTRICT Y1, + uECC_word_t * RESTRICT X2, + uECC_word_t * RESTRICT Y2) { + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[uECC_WORDS]; + uECC_word_t t6[uECC_WORDS]; + uECC_word_t t7[uECC_WORDS]; + + vli_modSub_fast(t5, X2, X1); /* t5 = x2 - x1 */ + vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ + vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ + vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ + vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */ + vli_modSub_fast(Y2, Y2, Y1); /* t4 = y2 - y1 */ + + vli_modSub_fast(t6, X2, X1); /* t6 = C - B */ + vli_modMult_fast(Y1, Y1, t6); /* t2 = y1 * (C - B) = E */ + vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */ + vli_modSquare_fast(X2, Y2); /* t3 = (y2 - y1)^2 = D */ + vli_modSub_fast(X2, X2, t6); /* t3 = D - (B + C) = x3 */ + + vli_modSub_fast(t7, X1, X2); /* t7 = B - x3 */ + vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */ + vli_modSub_fast(Y2, Y2, Y1); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ + + vli_modSquare_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */ + vli_modSub_fast(t7, t7, t6); /* t7 = F - (B + C) = x3' */ + vli_modSub_fast(t6, t7, X1); /* t6 = x3' - B */ + vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */ + vli_modSub_fast(Y1, t6, Y1); /* t2 = (y2 + y1)*(x3' - B) - E = y3' */ + + vli_set(X1, t7); +} + +enum +{ + ECC_POINT_MULT_STATE_INIT, + ECC_POINT_MULT_STATE_BIT_ADDC, + ECC_POINT_MULT_STATE_BIT_ADD, + ECC_POINT_MULT_STATE_EXIT_ADDC, + ECC_POINT_MULT_STATE_EXIT_ADD, + ECC_POINT_MULT_STATE_COMPLETE +}; + +typedef struct +{ + uint8_t state; + uECC_word_t Rx[2][uECC_WORDS]; + uECC_word_t Ry[2][uECC_WORDS]; + bitcount_t i; +} EccPointMultCtx; + +static int EccPoint_mult(EccPointMultCtx *pCtx, + EccPoint * RESTRICT result, + const EccPoint * RESTRICT point, + const uECC_word_t * RESTRICT scalar, + const uECC_word_t * RESTRICT initialZ, + bitcount_t numBits) { + uECC_word_t nb; + uECC_word_t z[uECC_WORDS]; + + switch (pCtx->state) { + case ECC_POINT_MULT_STATE_INIT: + vli_set(pCtx->Rx[1], point->x); + vli_set(pCtx->Ry[1], point->y); + + XYcZ_initial_double(pCtx->Rx[1], pCtx->Ry[1], pCtx->Rx[0], pCtx->Ry[0], initialZ); + + pCtx->i = numBits - 2; + pCtx->state = ECC_POINT_MULT_STATE_BIT_ADDC; + return 0; + + case ECC_POINT_MULT_STATE_BIT_ADDC: + nb = !vli_testBit(scalar, pCtx->i); + XYcZ_addC(pCtx->Rx[1 - nb], pCtx->Ry[1 - nb], pCtx->Rx[nb], pCtx->Ry[nb]); + + pCtx->state = ECC_POINT_MULT_STATE_BIT_ADD; + return 0; + + case ECC_POINT_MULT_STATE_BIT_ADD: + nb = !vli_testBit(scalar, pCtx->i); + XYcZ_add(pCtx->Rx[nb], pCtx->Ry[nb], pCtx->Rx[1 - nb], pCtx->Ry[1 - nb]); + + pCtx->i--; + pCtx->state = (pCtx->i > 0) ? ECC_POINT_MULT_STATE_BIT_ADDC : ECC_POINT_MULT_STATE_EXIT_ADDC; + return 0; + + case ECC_POINT_MULT_STATE_EXIT_ADDC: + nb = !vli_testBit(scalar, 0); + XYcZ_addC(pCtx->Rx[1 - nb], pCtx->Ry[1 - nb], pCtx->Rx[nb], pCtx->Ry[nb]); + + pCtx->state = ECC_POINT_MULT_STATE_EXIT_ADD; + return 0; + + case ECC_POINT_MULT_STATE_EXIT_ADD: + nb = !vli_testBit(scalar, 0); + + /* Find final 1/Z value. */ + vli_modSub_fast(z, pCtx->Rx[1], pCtx->Rx[0]); /* X1 - X0 */ + vli_modMult_fast(z, z, pCtx->Ry[1 - nb]); /* Yb * (X1 - X0) */ + vli_modMult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */ + vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */ + vli_modMult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */ + vli_modMult_fast(z, z, pCtx->Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */ + /* End 1/Z calculation */ + + XYcZ_add(pCtx->Rx[nb], pCtx->Ry[nb], pCtx->Rx[1 - nb], pCtx->Ry[1 - nb]); + apply_z(pCtx->Rx[0], pCtx->Ry[0], z); + + vli_set(result->x, pCtx->Rx[0]); + vli_set(result->y, pCtx->Ry[0]); + + pCtx->state = ECC_POINT_MULT_STATE_COMPLETE; + return 1; + + case ECC_POINT_MULT_STATE_COMPLETE: + default: + return 1; + } +} + +#if uECC_WORD_SIZE == 4 + +static void vli_nativeToBytes(uint8_t *bytes, const uint32_t *native) { + unsigned i; + for (i = 0; i < uECC_WORDS; ++i) { + uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i); + digit[0] = (uint8_t)(native[i] >> 24); + digit[1] = (uint8_t)(native[i] >> 16); + digit[2] = (uint8_t)(native[i] >> 8); + digit[3] = (uint8_t)(native[i]); + } +} + +static void vli_bytesToNative(uint32_t *native, const uint8_t *bytes) { + unsigned i; + for (i = 0; i < uECC_WORDS; ++i) { + const uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i); + native[i] = ((uint32_t)digit[0] << 24) | ((uint32_t)digit[1] << 16) | + ((uint32_t)digit[2] << 8) | (uint32_t)digit[3]; + } +} + +#endif /* uECC_WORD_SIZE */ + +enum +{ + ECC_MAKE_KEY_STATE_INIT, + ECC_MAKE_KEY_STATE_ECC_POINT_MULT, + ECC_MAKE_KEY_STATE_EXIT, + ECC_MAKE_KEY_STATE_COMPLETE +}; + +typedef struct EccMakeKeyCtx { + uint8_t state; + uECC_word_t private[uECC_WORDS]; + EccPoint public; + uECC_word_t tmp1[uECC_WORDS]; + uECC_word_t tmp2[uECC_WORDS]; + uECC_word_t *p2[2]; + uECC_word_t carry; + + EccPointMultCtx pointMultCtx; +} EccMakeKeyCtx; + +typedef struct EccSharedSecretCtx { + uECC_word_t random[uECC_WORDS]; + uECC_word_t *initial_Z; + EccPoint public; + EccPoint product; + uECC_word_t private[uECC_WORDS]; + uECC_word_t tmp[uECC_WORDS]; + uECC_word_t *p2[2]; + uECC_word_t carry; + + EccPointMultCtx pointMultCtx; +} EccSharedSecretCtx; + +typedef union EccCtx { + EccMakeKeyCtx makeKey; + EccSharedSecretCtx sharedSecret; +} EccCtx; + +static EccCtx uECC_ctx; + +/************************************************************************************************** + Make Key +**************************************************************************************************/ + +void uECC_make_key_start(const uint8_t private_key[uECC_BYTES]) { + memset(&uECC_ctx, 0, sizeof(uECC_ctx)); + uECC_ctx.makeKey.state = ECC_MAKE_KEY_STATE_INIT; + vli_bytesToNative(uECC_ctx.makeKey.private, private_key); +} + +int uECC_make_key_continue(void) { + switch (uECC_ctx.makeKey.state) { + case ECC_MAKE_KEY_STATE_INIT: + /* Make sure the private key is in the range [1, n-1]. */ + if (vli_isZero(uECC_ctx.makeKey.private)) { + return 0; + } + + if (vli_cmp(curve_n, uECC_ctx.makeKey.private) != 1) { + return 0; + } + + // Regularize the bitcount for the private key so that attackers cannot use a side channel + // attack to learn the number of leading zeros. + uECC_ctx.makeKey.p2[0] = uECC_ctx.makeKey.tmp1; + uECC_ctx.makeKey.p2[1] = uECC_ctx.makeKey.tmp2; + uECC_ctx.makeKey.carry = vli_add(uECC_ctx.makeKey.tmp1, uECC_ctx.makeKey.private, curve_n); + vli_add(uECC_ctx.makeKey.tmp2, uECC_ctx.makeKey.tmp1, curve_n); + + uECC_ctx.makeKey.pointMultCtx.state = 0; + uECC_ctx.makeKey.state = ECC_MAKE_KEY_STATE_ECC_POINT_MULT; + return 0; + + case ECC_MAKE_KEY_STATE_ECC_POINT_MULT: + if (EccPoint_mult(&uECC_ctx.makeKey.pointMultCtx, + &uECC_ctx.makeKey.public, + &curve_G, + uECC_ctx.makeKey.p2[!uECC_ctx.makeKey.carry], + 0, + (uECC_BYTES * 8) + 1)) { + uECC_ctx.makeKey.state = ECC_MAKE_KEY_STATE_EXIT; + } + return 0; + + case ECC_MAKE_KEY_STATE_EXIT: + if (EccPoint_isZero(&uECC_ctx.makeKey.public)) { + uECC_ctx.makeKey.state = ECC_MAKE_KEY_STATE_INIT; + return 0; + } + + uECC_ctx.makeKey.state = ECC_MAKE_KEY_STATE_COMPLETE; + return 1; + + case ECC_MAKE_KEY_STATE_COMPLETE: + default: + return 1; + } +} + +void uECC_make_key_complete(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]) { + vli_nativeToBytes(private_key, uECC_ctx.makeKey.private); + vli_nativeToBytes(public_key, uECC_ctx.makeKey.public.x); + vli_nativeToBytes(public_key + uECC_BYTES, uECC_ctx.makeKey.public.y); +} + +/************************************************************************************************** + Shared Secret +**************************************************************************************************/ + +void uECC_shared_secret_start(const uint8_t public_key[uECC_BYTES*2], + const uint8_t private_key[uECC_BYTES]) { + uECC_word_t tries; + + memset(&uECC_ctx, 0, sizeof(uECC_ctx)); + + // Try to get a random initial Z value to improve protection against side-channel + // attacks. If the RNG fails every time (eg it was not defined), we continue so that + // uECC_shared_secret() can still work without an RNG defined. + uECC_ctx.sharedSecret.initial_Z = NULL; + for (tries = 0; tries < MAX_TRIES; ++tries) { + if (g_rng_function((uint8_t *)uECC_ctx.sharedSecret.random, sizeof(uECC_ctx.sharedSecret.random)) && !vli_isZero(uECC_ctx.sharedSecret.random)) { + uECC_ctx.sharedSecret.initial_Z = uECC_ctx.sharedSecret.random; + break; + } + } + + vli_bytesToNative(uECC_ctx.sharedSecret.private, private_key); + vli_bytesToNative(uECC_ctx.sharedSecret.public.x, public_key); + vli_bytesToNative(uECC_ctx.sharedSecret.public.y, public_key + uECC_BYTES); + + // Regularize the bitcount for the private key so that attackers cannot use a side channel + // attack to learn the number of leading zeros. + uECC_ctx.sharedSecret.p2[0] = uECC_ctx.sharedSecret.private; + uECC_ctx.sharedSecret.p2[1] = uECC_ctx.sharedSecret.tmp; + uECC_ctx.sharedSecret.carry = vli_add(uECC_ctx.sharedSecret.private, uECC_ctx.sharedSecret.private, curve_n); + vli_add(uECC_ctx.sharedSecret.tmp, uECC_ctx.sharedSecret.private, curve_n); + + uECC_ctx.sharedSecret.pointMultCtx.state = 0; +} + +int uECC_shared_secret_continue(void) { + return EccPoint_mult(&uECC_ctx.sharedSecret.pointMultCtx, + &uECC_ctx.sharedSecret.product, + &uECC_ctx.sharedSecret.public, + uECC_ctx.sharedSecret.p2[!uECC_ctx.sharedSecret.carry], + uECC_ctx.sharedSecret.initial_Z, + (uECC_BYTES * 8) + 1); +} + +void uECC_shared_secret_complete(uint8_t secret[uECC_BYTES]) { + vli_nativeToBytes(secret, uECC_ctx.sharedSecret.product.x); +} diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.h b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.h new file mode 100644 index 0000000000..e0fab320de --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO_LL/thirdparty/uecc/uECC_ll.h @@ -0,0 +1,134 @@ +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _MICRO_ECC_LL_H_ +#define _MICRO_ECC_LL_H_ + +#include "wsf_types.h" + +/* Platform selection options. +If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. +Possible values for uECC_PLATFORM are defined below: */ +#define uECC_arch_other 0 +#define uECC_x86 1 +#define uECC_x86_64 2 +#define uECC_arm 3 +#define uECC_arm_thumb 4 +#define uECC_avr 5 +#define uECC_arm_thumb2 6 + +/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes). +If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your +platform. */ + +/* Inline assembly options. +uECC_asm_none - Use standard C99 only. +uECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for + minimum size. +uECC_asm_fast - Use GCC inline assembly optimized for maximum speed. */ +#define uECC_asm_none 0 +#define uECC_asm_small 1 +#define uECC_asm_fast 2 +#ifndef uECC_ASM + #define uECC_ASM uECC_asm_fast +#endif + +/* Curve selection options. */ +#define uECC_secp160r1 1 +#define uECC_secp192r1 2 +#define uECC_secp256r1 3 +#define uECC_secp256k1 4 +#define uECC_secp224r1 5 +#ifndef uECC_CURVE + #define uECC_CURVE uECC_secp256r1 +#endif + +/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be +used for (scalar) squaring instead of the generic multiplication function. This will make things +faster by about 8% but increases the code size. */ +#ifndef uECC_SQUARE_FUNC + #define uECC_SQUARE_FUNC 1 +#endif + +#define uECC_CONCAT1(a, b) a##b +#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b) + +#define uECC_size_1 20 /* secp160r1 */ +#define uECC_size_2 24 /* secp192r1 */ +#define uECC_size_3 32 /* secp256r1 */ +#define uECC_size_4 32 /* secp256k1 */ +#define uECC_size_5 28 /* secp224r1 */ + +#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE) + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* uECC_RNG_Function type +The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if +'dest' was filled with random data, or 0 if the random data could not be generated. +The filled-in values should be either truly random, or from a cryptographically-secure PRNG. + +A correctly functioning RNG function must be set (using uECC_set_rng()) before calling +uECC_make_key() or uECC_sign(). + +Setting a correctly functioning RNG function improves the resistance to side-channel attacks +for uECC_shared_secret() and uECC_sign_deterministic(). + +A correct RNG function is set by default when building for Windows, Linux, or OS X. +If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, +you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined +RNG function; you must provide your own. +*/ +typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); + +/* uECC_set_rng() function. +Set the function that will be used to generate random bytes. The RNG function should +return 1 if the random data was generated, or 0 if the random data could not be generated. + +On platforms where there is no predefined RNG function (eg embedded platforms), this must +be called before uECC_make_key() or uECC_sign() are used. + +Inputs: + rng_function - The function that will be used to generate random bytes. +*/ +void uECC_set_rng(uECC_RNG_Function rng_function); + +/* uECC_make_key() function. +Create a public/private key pair. + +Outputs: + public_key - Will be filled in with the public key. + private_key - Will be filled in with the private key. + +Returns 1 if the key pair was generated successfully, 0 if an error occurred. +*/ +void uECC_make_key_start(const uint8_t private_key[uECC_BYTES]); +int uECC_make_key_continue(void); +void uECC_make_key_complete(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]); + +/* uECC_shared_secret() function. +Compute a shared secret given your secret key and someone else's public key. +Note: It is recommended that you hash the result of uECC_shared_secret() before using it for +symmetric encryption or HMAC. + +Inputs: + public_key - The public key of the remote party. + private_key - Your private key. + +Outputs: + secret - Will be filled in with the shared secret value. + +Returns 1 if the shared secret was generated successfully, 0 if an error occurred. +*/ +void uECC_shared_secret_start(const uint8_t public_key[uECC_BYTES*2], + const uint8_t private_key[uECC_BYTES]); +int uECC_shared_secret_continue(void); +void uECC_shared_secret_complete(uint8_t secret[uECC_BYTES]); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _MICRO_ECC_LL_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/CHANGELOG.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/CHANGELOG.md deleted file mode 100644 index bb4dad9a4a..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/CHANGELOG.md +++ /dev/null @@ -1,344 +0,0 @@ -# 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_NRF52/LICENSE b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/LICENSE deleted file mode 100644 index 60744edab2..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/LICENSE +++ /dev/null @@ -1,6 +0,0 @@ -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_NRF52/apache-2.0.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/apache-2.0.txt deleted file mode 100644 index 9327527edd..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/apache-2.0.txt +++ /dev/null @@ -1,13 +0,0 @@ -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_NRF52/module.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/module.json deleted file mode 100644 index b45b894f0e..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/module.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "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_NRF52/softdevice_nrf51822_licence_agreement.txt b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt deleted file mode 100644 index 8e447f4c64..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/softdevice_nrf51822_licence_agreement.txt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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_NRF52/source/btle/btle.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.cpp deleted file mode 100644 index cf7836a8ee..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* 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_NRF52/source/btle/btle.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.h deleted file mode 100644 index 4c35282d8a..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 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_NRF52/source/btle/btle_clock.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle_clock.h deleted file mode 100644 index bc4c1e29f4..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/btle_clock.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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_NRF52/source/btle/custom/custom_helper.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.cpp deleted file mode 100644 index 95be197637..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* 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_NRF52/source/btle/custom/custom_helper.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.h deleted file mode 100644 index e5cddc2bd5..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/btle/custom/custom_helper.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 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_NRF52/source/common/ansi_escape.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ansi_escape.h deleted file mode 100644 index 392dedb44f..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ansi_escape.h +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/common/assertion.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/assertion.h deleted file mode 100644 index 71bacb3e81..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/assertion.h +++ /dev/null @@ -1,197 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/common/binary.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/binary.h deleted file mode 100644 index 585787eb2f..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/binary.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/common/ble_error.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ble_error.h deleted file mode 100644 index 36deb33080..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/ble_error.h +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/common/common.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/common.h deleted file mode 100644 index 6002c6dfb7..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/common.h +++ /dev/null @@ -1,236 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/common/compiler.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/compiler.h deleted file mode 100644 index 5b04ac05d0..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/common/compiler.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************/ -/*! - @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_NRF52/source/nRF5xCrypto.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.cpp deleted file mode 100644 index 32419875a2..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* 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_NRF52/source/nRF5xCrypto.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.h deleted file mode 100644 index 35c56a875e..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xCrypto.h +++ /dev/null @@ -1,146 +0,0 @@ -/* 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_NRF52/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h deleted file mode 100644 index 19273e815c..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h +++ /dev/null @@ -1,346 +0,0 @@ -/* 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_NRF52/source/nRF5xGattServer.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.cpp deleted file mode 100644 index 8c93ac118c..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.cpp +++ /dev/null @@ -1,862 +0,0 @@ -/* 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_NRF52/source/nRF5xGattServer.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.h deleted file mode 100644 index 253c2d1446..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGattServer.h +++ /dev/null @@ -1,167 +0,0 @@ -/* 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_NRF52/source/nRF5xPalGattClient.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.cpp deleted file mode 100644 index 1778a102f1..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.cpp +++ /dev/null @@ -1,1681 +0,0 @@ -/* 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_NRF52/source/nRF5xPalGattClient.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.h deleted file mode 100644 index 6c298aa3e3..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalGattClient.h +++ /dev/null @@ -1,257 +0,0 @@ -/* 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_NRF52/source/nRF5xPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.h deleted file mode 100644 index 30ac7e20cc..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.h +++ /dev/null @@ -1,380 +0,0 @@ -/* 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_NRF52/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.cpp deleted file mode 100644 index e8e463a0c5..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* 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_NRF52/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.h deleted file mode 100644 index 088944faa6..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xn.h +++ /dev/null @@ -1,156 +0,0 @@ -/* 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_NRF52/source/projectconfig.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/projectconfig.h deleted file mode 100644 index 15959850c4..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/projectconfig.h +++ /dev/null @@ -1,136 +0,0 @@ -/* 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_NRF52/source/supress-warnings.cmake b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/supress-warnings.cmake deleted file mode 100644 index 60061399da..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/supress-warnings.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# 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_NRF5x/NRFCordioHCIDriver.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.cpp new file mode 100644 index 0000000000..9560518b9d --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.cpp @@ -0,0 +1,324 @@ +/* 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 +#include +#include + +// mbed Includes +#include "mbed_assert.h" +#include "rtos/rtos_idle.h" +#include "platform/mbed_power_mgmt.h" +#include "mbed_critical.h" + +// Cordio Includes +#include "ll_init_api.h" +#include "ll_defs.h" +#include "chci_drv.h" +#include "lhci_api.h" +#include "platform_api.h" +#include "platform_ble_api.h" +#include "wsf_assert.h" +#include "wsf_buf.h" +#include "wsf_timer.h" +#include "wsf_trace.h" + +// Nordic Includes +#include "nrf.h" + +#include "NRFCordioHCIDriver.h" +#include "NRFCordioHCITransportDriver.h" + +#ifdef DEBUG +#include +#include +#define DBG_WARN(...) printf(__VA_ARGS__) +#else +#define DBG_WARN(...) +#endif + +using namespace ble::vendor::nordic; +using namespace ble::vendor::cordio; + +/*! \brief Memory that should be reserved for the stack. */ +#define CORDIO_LL_MEMORY_FOOTPRINT 8192UL + +/*! \brief Typical implementation revision number (LlRtCfg_t::implRev). */ +#define LL_IMPL_REV 0x2303 + +// Note to implementer: this should be amended if the Cordio stack is updated + +// The Nordic-specific baseband configuration +// The BB_ config macros are set in the bb_api.h header file +const BbRtCfg_t NRFCordioHCIDriver::_bb_cfg = { + /*clkPpm*/ 20, + /*rfSetupDelayUsec*/ BB_RF_SETUP_DELAY_US, + /*maxScanPeriodMsec*/ BB_MAX_SCAN_PERIOD_MS, + /*schSetupDelayUsec*/ BB_SCH_SETUP_DELAY_US +}; + +static const uint16_t maxAdvReports = 16; +static const uint16_t numRxBufs = 8; +#if !defined(NRF52840_XXAA) +static const uint16_t advDataLen = 128; +static const uint16_t connDataLen = 256; +static const uint16_t numTxBufs = 8; +#else +static const uint16_t advDataLen = LL_MAX_ADV_DATA_LEN; +static const uint16_t connDataLen = 512; +static const uint16_t numTxBufs = 16; +#endif + + +/* +12 for message headroom, + 2 event header, +255 maximum parameter length. */ +static const uint16_t maxRptBufSize = 12 + 2 + 255; + +/* +12 for message headroom, +4 for header. */ +static const uint16_t aclBufSize = 12 + connDataLen + 4 + BB_DATA_PDU_TAILROOM; + +const LlRtCfg_t NRFCordioHCIDriver::_ll_cfg = { + /* Device */ + /*compId*/ LL_COMP_ID_ARM, + /*implRev*/ LL_IMPL_REV, + /*btVer*/ LL_VER_BT_CORE_SPEC_4_2, + 0, // padding + /* Advertiser */ + /*maxAdvSets*/ 0, /* Disable extended advertising. */ + /*maxAdvReports*/ 4, + /*maxExtAdvDataLen*/ advDataLen, + /*defExtAdvDataFrag*/ 64, + 0, // Aux delay + /* Scanner */ + /*maxScanReqRcvdEvt*/ 4, + /*maxExtScanDataLen*/ advDataLen, + /* Connection */ + /*maxConn*/ 4, + /*numTxBufs*/ numTxBufs, + /*numRxBufs*/ numRxBufs, + /*maxAclLen*/ connDataLen, + /*defTxPwrLvl*/ 0, + /*ceJitterUsec*/ 0, + /* DTM */ + /*dtmRxSyncMs*/ 10000, + /* PHY */ + /*phy2mSup*/ TRUE, + /*phyCodedSup*/ TRUE, + /*stableModIdxTxSup*/ TRUE, + /*stableModIdxRxSup*/ TRUE +}; + +extern "C" void TIMER0_IRQHandler(void); + +static void idle_hook(void) +{ + wsfTimerTicks_t nextExpiration; + bool_t timerRunning; + + nextExpiration = WsfTimerNextExpiration(&timerRunning); + if(timerRunning && nextExpiration > 0) + { + // Make sure we hae enough time to go to sleep + if( nextExpiration < 1 /* 10 ms per tick which is long enough to got to sleep */ ) + { + // Bail + return; + } + } + + // critical section to complete sleep with locked deepsleep + core_util_critical_section_enter(); + sleep_manager_lock_deep_sleep(); + sleep(); + sleep_manager_unlock_deep_sleep(); + core_util_critical_section_exit(); +} + +NRFCordioHCIDriver::NRFCordioHCIDriver(CordioHCITransportDriver& transport_driver) : cordio::CordioHCIDriver(transport_driver), _is_init(false), _stack_buffer(NULL) +{ + _stack_buffer = (uint8_t*)malloc(CORDIO_LL_MEMORY_FOOTPRINT); + MBED_ASSERT(_stack_buffer != NULL); +} + +NRFCordioHCIDriver::~NRFCordioHCIDriver() +{ + // Deativate all interrupts + NVIC_DisableIRQ(RADIO_IRQn); + NVIC_DisableIRQ(TIMER0_IRQn); + + // Switch off Radio peripheral + // TODO interop with 802.15.4 + NRF_RADIO->POWER = 0; + + // Stop timer + NRF_TIMER0->TASKS_STOP = 1; + NRF_TIMER0->TASKS_CLEAR = 1; + + NVIC_ClearPendingIRQ(RADIO_IRQn); + NVIC_ClearPendingIRQ(TIMER0_IRQn); + + MBED_ASSERT(_stack_buffer != NULL); + free(_stack_buffer); + _stack_buffer = NULL; + + // Restore RTOS idle thread + rtos_attach_idle_hook(NULL); + + MBED_ASSERT(_stack_buffer == NULL); +} + +ble::vendor::cordio::buf_pool_desc_t NRFCordioHCIDriver::get_buffer_pool_description() +{ + static union { + uint8_t buffer[ 32768 ]; + uint64_t align; + }; + static const wsfBufPoolDesc_t pool_desc[] = { + { 16, 16 + 8}, + { 32, 16 + 4 }, + { 64, 8 }, + { 128, 4 + maxAdvReports }, + { aclBufSize, numTxBufs + numRxBufs }, + { 272, 1 } + }; + + return buf_pool_desc_t(buffer, pool_desc); +} + +void NRFCordioHCIDriver::do_initialize() +{ + if(_is_init) { + return; + } + + _is_init = true; + + // Setup BB & LL config + LlInitRtCfg_t ll_init_cfg = + { + .pBbRtCfg = &_bb_cfg, + .wlSizeCfg = 4, + .rlSizeCfg = 4, + .plSizeCfg = 4, + .pLlRtCfg = &_ll_cfg, + .pFreeMem = _stack_buffer, + .freeMemAvail = CORDIO_LL_MEMORY_FOOTPRINT + }; + + // Override RTOS idle thread + rtos_attach_idle_hook(idle_hook); + + /* switch to more accurate 16 MHz crystal oscillator (system starts up using 16MHz RC oscillator) */ + NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; + NRF_CLOCK->TASKS_HFCLKSTART = 1; + while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) + { + } + + /* configure low-frequency clock */ + NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos); + NRF_CLOCK->EVENTS_LFCLKSTARTED = 0; + NRF_CLOCK->TASKS_LFCLKSTART = 1; + while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) + { + } + NRF_CLOCK->EVENTS_LFCLKSTARTED = 0; + + // Start RTC0 + NRF_RTC0->TASKS_STOP = 1; + NRF_RTC0->TASKS_CLEAR = 1; + NRF_RTC0->PRESCALER = 0; /* clear prescaler */ + NRF_RTC0->TASKS_START = 1; + + // Cycle radio peripheral power to guarantee known radio state + NRF_RADIO->POWER = 0; + NRF_RADIO->POWER = 1; + + // For some reason, the mbed target uses this (TIMER0_IRQHandler_v) vector name instead of the "standard" TIMER0_IRQHandler one + NVIC_SetVector(TIMER0_IRQn, (uint32_t)TIMER0_IRQHandler); + + // Extremely ugly + for(uint32_t irqn = 0; irqn < 32; irqn++) + { + uint8_t prio = NVIC_GetPriority((IRQn_Type)irqn); + if( prio < 2 ) { + NVIC_SetPriority((IRQn_Type)irqn, 2); + } + } + + // WARNING + // If a submodule does not have enough space to allocate its memory from buffer, it will still allocate its memory (and do a buffer overflow) and return 0 (as in 0 byte used) + // however that method will still continue which will lead to undefined behaviour + // So whenever a change of configuration is done, it's a good idea to set CORDIO_LL_MEMORY_FOOTPRINT to a high value and then reduce accordingly + uint32_t mem_used = LlInitControllerInit(&ll_init_cfg); + if( mem_used < CORDIO_LL_MEMORY_FOOTPRINT ) + { + // Sub-optimal, give warning + DBG_WARN("NRFCordioHCIDriver: CORDIO_LL_MEMORY_FOOTPRINT can be reduced to %lu instead of %lu", mem_used, CORDIO_LL_MEMORY_FOOTPRINT); + } + + // BD Addr + bdAddr_t bd_addr; + PlatformLoadBdAddress(bd_addr); + LlSetBdAddr((uint8_t *)&bd_addr); + LlMathSetSeed((uint32_t *)&bd_addr); + +//#ifdef DEBUG +// WsfTraceRegister(wsf_trace_handler); +//#endif + + // We're sharing the host stack's event queue +} + +void NRFCordioHCIDriver::do_terminate() +{ + +} + +ble::vendor::cordio::CordioHCIDriver& ble_cordio_get_hci_driver() { + static NRFCordioHCITransportDriver transport_driver; + + static NRFCordioHCIDriver hci_driver( + transport_driver + ); + + return hci_driver; +} + +// Do not handle any vendor specific command +extern "C" bool_t lhciCommonVsStdDecodeCmdPkt(LhciHdr_t *pHdr, uint8_t *pBuf) +{ + return false; +} + +// Nordic implementation +void PlatformLoadBdAddress(uint8_t *pDevAddr) +{ + unsigned int devAddrLen = 6; + + /* Load address from nRF configuration. */ + uint64_t devAddr = (((uint64_t)NRF_FICR->DEVICEID[0]) << 0) | + (((uint64_t)NRF_FICR->DEVICEID[1]) << 32); + + unsigned int i = 0; + while (i < devAddrLen) + { + pDevAddr[i] = devAddr >> (i * 8); + i++; + } + + pDevAddr[5] |= 0xC0; /* cf. "Static Address" (Vol C, Part 3, section 10.8.1) */ +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h new file mode 100644 index 0000000000..c7074dd645 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCIDriver.h @@ -0,0 +1,86 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-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 NRF_CORDIO_HCI_DRIVER_H_ +#define NRF_CORDIO_HCI_DRIVER_H_ + +#include "CordioHCIDriver.h" + +namespace ble { +namespace vendor { +namespace nordic { + + +/** + * Nordic port of CordioHCIDriver + */ +class NRFCordioHCIDriver : public cordio::CordioHCIDriver { +public: + /** + * Construct a new instance of an HCI driver. + * @param transport_driver The driver used to communicate with the chip. + */ + NRFCordioHCIDriver(cordio::CordioHCITransportDriver& transport_driver); + + /** + * Driver destructor + */ + virtual ~NRFCordioHCIDriver(); + + /** + * Return the set of memory pool which will be used by the Cordio stack + */ + virtual cordio::buf_pool_desc_t get_buffer_pool_description(); + + /** + * Start the reset sequence of the BLE module. + */ + //virtual void start_reset_sequence(); + + /** + * Handle HCI messages received during the reset sequence. + * + * @param msg The HCI message received. + * @note The driver should signal to the stack that the initialization + * sequence is done by calling the function: signal_reset_sequence_done. + */ + //virtual void handle_reset_sequence(uint8_t *msg); + +private: + /** + * Initialize the chip. + * The transport is up at that time. + */ + virtual void do_initialize(); + + /** + * Terminate the driver + */ + virtual void do_terminate(); + + // Cordio parameters + static const BbRtCfg_t _bb_cfg; /// << Baseband runtime configuration + static const LlRtCfg_t _ll_cfg; /// << Link layer runtime configuration; + + bool _is_init; + uint8_t* _stack_buffer; +}; + +} // namespace nordic +} // namespace vendor +} // namespace ble + +#endif /* NRF_CORDIO_HCI_DRIVER_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp new file mode 100644 index 0000000000..233b54b2c9 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.cpp @@ -0,0 +1,68 @@ +/* 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 + +#include "wsf_types.h" +#include "wsf_assert.h" +#include "wsf_cs.h" +#include "wsf_math.h" +#include "chci_api.h" +#include "chci_tr.h" +#include "chci_tr_serial.h" +#include "chci_drv.h" +#include "platform_nordic.h" +#include "hci_defs.h" +#include + +#include "NRFCordioHCITransportDriver.h" + +using namespace ble::vendor::nordic; +using namespace ble::vendor::cordio; + +NRFCordioHCITransportDriver::~NRFCordioHCITransportDriver() { } + +void NRFCordioHCITransportDriver::initialize() +{ + +} + +void NRFCordioHCITransportDriver::terminate() +{ + +} + +uint16_t NRFCordioHCITransportDriver::write(uint8_t type, uint16_t len, uint8_t *pData) +{ + chciTrSerialRxIncoming(&type, 1); + chciTrSerialRxIncoming(pData, len); + return len; +} + +extern "C" void chciDrvInit(void) +{ + // No-op +} + +// Callback from Cordio stack +extern "C" uint16_t chciDrvWrite(uint8_t prot, uint8_t type, uint16_t len, uint8_t *pData) +{ + uint8_t ctype = (type == CHCI_TR_TYPE_EVT) ? HCI_EVT_TYPE : HCI_ACL_TYPE; + CordioHCITransportDriver::on_data_received(&ctype, 1); + CordioHCITransportDriver::on_data_received(pData, len); + return len; +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h new file mode 100644 index 0000000000..382188527e --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/NRFCordioHCITransportDriver.h @@ -0,0 +1,66 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-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 NRF_CORDIO_HCI_TRANSPORT_DRIVER_H_ +#define NRF_CORDIO_HCI_TRANSPORT_DRIVER_H_ + +#include "CordioHCITransportDriver.h" + +namespace ble { +namespace vendor { +namespace nordic { + + +/** + * Nordic port of CordioHCITransportDriver + */ +class NRFCordioHCITransportDriver : public cordio::CordioHCITransportDriver { +public: + /** + * Driver destructor. + */ + virtual ~NRFCordioHCITransportDriver(); + + /** + * Inialization of the transport. + */ + virtual void initialize(); + + /** + * termination of the transport. + */ + virtual void terminate(); + + /** + * Write data in the transport channel. + * + * @param type The type of packet to transmit. It might be an HCI command + * packet, ACL packet or EVT packet. Depending on the type of transport + * it can prefix the packet itself. + * @param len Number of bytes to transmit. + * @param pData pointer to the data to transmit. + * + * @return The number of bytes which have been transmited. + */ + virtual uint16_t write(uint8_t type, uint16_t len, uint8_t *pData); +}; + + +} // namespace nordic +} // namespace vendor +} // namespace ble + +#endif /* NRF_CORDIO_HCI_TRANSPORT_DRIVER_H_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md new file mode 100644 index 0000000000..d70731400c --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/README.md @@ -0,0 +1,17 @@ +# Cordio Link Layer port for Nordic platforms + +To use this port amend your mbed_app.json file as following: +```json + "NRF52840_DK": { + "target.features_add": ["BLE"] + }, + "NRF52_DK": { + "target.features_add": ["BLE"] + } +``` + +Resources used: +* RADIO +* TIMER0 +* PPI channels 14 and 15 +* HF clock is enabled \ No newline at end of file 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_NRF5x/cordio_stack/libcordio_stack_nordic.a new file mode 100644 index 0000000000000000000000000000000000000000..21e4f37621d9803a0c426f005fe67e013cb8b498 GIT binary patch literal 56836 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 z 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 literal 0 HcmV?d00001 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_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h new file mode 100644 index 0000000000..4a53dea592 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/bb_drv_nordic.h @@ -0,0 +1,54 @@ +/*************************************************************************************************/ +/*! + * \brief Nordic baseband driver header. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_DRV_NORDIC_H +#define BB_DRV_NORDIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bb_api.h" + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! \brief IRQ callback datatypes. */ +typedef void (*bbDrvIrqCback_t)(void); + +/*************************************************************************************************/ +/*! + * \brief Called to register a protocol's Radio and Timer IRQ callback functions. + * + * \param protId Protocol ID. + * \param timerCback Timer IRQ callback. + * \param radioCback Timer IRQ callback. + * + * \return None. + */ +/*************************************************************************************************/ +void BbDrvRegisterProtIrq(uint8_t protId, bbDrvIrqCback_t timerCback, bbDrvIrqCback_t radioCback); + +#ifdef __cplusplus +}; +#endif + +#endif /* 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_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h new file mode 100644 index 0000000000..652f303f69 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_btn.h @@ -0,0 +1,74 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Private platform definitions. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef PLATFORM_BTN_H +#define PLATFORM_BTN_H + +#include "platform_nordic.h" +#include "wsf_msg.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +#if (BUTTONS_NUMBER >= 1) +#define BUTTON_0_BITMASK (1 << BSP_BUTTON_0) +#endif +#if (BUTTONS_NUMBER >= 2) +#define BUTTON_1_BITMASK (1 << BSP_BUTTON_1) +#endif +#if (BUTTONS_NUMBER >= 3) +#define BUTTON_2_BITMASK (1 << BSP_BUTTON_2) +#endif +#if (BUTTONS_NUMBER >= 4) +#define BUTTON_3_BITMASK (1 << BSP_BUTTON_3) +#endif + +#define BUTTON_ACTIVE_STATE 0 + +/************************************************************************************************** + Types +**************************************************************************************************/ + +/*! \brief Button configuration structure. */ +typedef struct +{ + uint8_t pinNo; /*!< Pin to be used as a button. */ + uint8_t activeState; /*!< APP_BUTTON_ACTIVE_HIGH or APP_BUTTON_ACTIVE_LOW. */ + nrf_gpio_pin_pull_t pullCfg; /*!< Pull-up or -down configuration. */ +} platformButtonCfg_t; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern platformButtonCfg_t platformButtons[]; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +void PlatformInitBtns(platformButtonCfg_t *pButtons, uint8_t buttonCount); +uint32_t PlatformReadBtns(void); +void PlatformRegisterBtnsHandler(wsfHandlerId_t handlerId, wsfEventMask_t eventMask); + +#endif /* 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_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h new file mode 100644 index 0000000000..31f3a492bf --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/include/platform_nordic.h @@ -0,0 +1,89 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Private platform definitions. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef PLATFORM_INT_H +#define PLATFORM_INT_H + +#include "platform_api.h" + +/* Nordic specific definitions. */ +#include +#include "boards.h" +#include "nrf.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +#if defined(BOARD_PCA10000) || defined(BOARD_PCA10031) + +#define LED_CPU_ACTIVE() nrf_gpio_pin_set (LED_RGB_RED); \ + nrf_gpio_pin_clear(LED_RGB_GREEN); \ + nrf_gpio_pin_set (LED_RGB_BLUE) +#define LED_CPU_SLEEP() nrf_gpio_pin_set (LED_RGB_RED); \ + nrf_gpio_pin_set (LED_RGB_GREEN); \ + nrf_gpio_pin_set (LED_RGB_BLUE) +#define LED_ERROR() nrf_gpio_pin_clear(LED_RGB_RED); \ + nrf_gpio_pin_set (LED_RGB_GREEN); \ + nrf_gpio_pin_set (LED_RGB_BLUE) +#define LED_CLEAR_ERROR() + +#elif defined(BOARD_PCA10001) + +#define LED_CPU_ACTIVE() nrf_gpio_pin_set (BSP_LED_0) +#define LED_CPU_SLEEP() nrf_gpio_pin_clear(BSP_LED_0) +#define LED_ERROR() nrf_gpio_pin_set (BSP_LED_1) +#define LED_CLEAR_ERROR() nrf_gpio_pin_clear(BSP_LED_1) + +#elif defined(BOARD_PCA10028) || defined(BOARD_PCA10040) || defined(BOARD_PCA10056) + +/* Inverted LED "on" logic */ +#define LED_CPU_ACTIVE() nrf_gpio_pin_clear(BSP_LED_1) /* edge of board */ +#define LED_CPU_SLEEP() nrf_gpio_pin_set (BSP_LED_1) /* edge of board */ +#define LED_ERROR() nrf_gpio_pin_clear(BSP_LED_3) /* edge of board */ +#define LED_CLEAR_ERROR() nrf_gpio_pin_set (BSP_LED_3) /* edge of board */ + +#else + +#warning "Board not specified" + +#define LED_CPU_ACTIVE() +#define LED_CPU_SLEEP() +#define LED_ERROR() +#define LED_CLEAR_ERROR() + +#endif + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +extern uint8_t *SystemHeapStart; +extern uint32_t SystemHeapSize; + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +void platformTimeInit(void); + +#endif /* PLATFORM_INT_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_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h new file mode 100644 index 0000000000..e82c5011c0 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/cordio_stack/platform/nordic/sources/bb/ble/bb_ble_int.h @@ -0,0 +1,48 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Baseband driver internal interface file. + * + * Copyright (c) 2009-2018 ARM Ltd., all rights reserved. + * SPDX-License-Identifier: LicenseRef-PBL + * + * This file and the related binary are licensed under the + * Permissive Binary License, Version 1.0 (the "License"); + * you may not use these files except in compliance with the License. + * + * You may obtain a copy of the License here: + * LICENSE-permissive-binary-license-1.0.txt and at + * https://www.mbed.com/licenses/PBL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*************************************************************************************************/ + +#ifndef BB_BLE_DRV_INT_H +#define BB_BLE_DRV_INT_H + +#include "wsf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ + +/* Inline encryption */ +void BbBleDrvInlineEncryptTxEnable(bool_t enable); +void BbBleDrvInlineEncryptSetPacketCount(uint64_t count); +void BbBleDrvInlineEncryptDecryptSuppressMic(bool_t enable); +void BbBleDrvInlineEncryptDecryptSetKey(uint8_t * key); +void BbBleDrvInlineEncryptDecryptSetIv(uint8_t * iv); +void BbBleDrvInlineEncryptDecryptSetDirection(uint8_t dir); + +#ifdef __cplusplus +}; +#endif + +#endif /* BB_BLE_DRV_INT_H */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json new file mode 100644 index 0000000000..1dbbdbb711 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/mbed_lib.json @@ -0,0 +1,6 @@ +{ + "name": "cordio-nordic-ll", + "macros": [ + "uECC_ASM=2", "INIT_BROADCASTER", "INIT_OBSERVER", "INIT_CENTRAL", "INIT_PERIPHERAL", "INIT_ENCRYPTED", "LHCI_ENABLE_VS=0", "BB_CLK_RATE_HZ=32768" + ] +} diff --git a/targets/targets.json b/targets/targets.json index 9feeda3205..4e4cb58d3f 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -6515,8 +6515,9 @@ "NRF5x", "NRF52", "SDK_14_2", - "SOFTDEVICE_COMMON", - "SOFTDEVICE_S132_FULL" + "CORDIO", + "CORDIO_LL", + "SOFTDEVICE_NONE" ], "config": { "lf_clock_src": { @@ -6629,8 +6630,9 @@ "NRF5x", "NRF52", "SDK_14_2", - "SOFTDEVICE_COMMON", - "SOFTDEVICE_S140_FULL" + "CORDIO", + "CORDIO_LL", + "SOFTDEVICE_NONE" ], "config": { "lf_clock_src": {