diff --git a/Kconfig b/Kconfig index 356b986c..d3fa2516 100644 --- a/Kconfig +++ b/Kconfig @@ -8,3 +8,21 @@ rsource "drivers/Kconfig" config ALIRO_PRINT_READER_GROUP_ID bool "Print reader group ID that should be provisioned into the User Device" + +config ALIRO_BLE_TP + bool "Aliro BLE transport" + help + Enable the Aliro BLE transport protocol (TP). This is the transport layer + used by Reader to communicate with the User Device. It is used to send and + receive packets over BLE. + +if ALIRO_BLE_TP + +config ALIRO_BLE_TP_MAX_SESSIONS + int "Maximum number of BLE sessions" + default BT_MAX_CONN + help + The maximum number of BLE sessions that can be established. + +rsource "lib/aliro/Kconfig.ble.defconfig" +endif # ALIRO_BLE_TP diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 38d475f7..607e2a3f 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,29 +9,33 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(door-lock-app) -FILE(GLOB app_sources src/*.cpp) +file(GLOB app_sources CONFIGURE_DEPENDS src/*.cpp) -add_subdirectory(src/nfc_transport_impl) +add_subdirectory(src/platform) -target_sources(app PRIVATE - ${app_sources} -) +target_sources(app PRIVATE ${app_sources}) -set(ALIRO_LIB_DIR ${ZEPHYR_NCS_DOOR_LOCK_APP_MODULE_DIR}/lib/aliro) +set(PUBLIC_API ${ZEPHYR_NCS_ALIRO_MODULE_DIR}) if(CONFIG_SOC_SERIES_NRF52X) - set(ALIRO_LIB_BIN_PATH ${ALIRO_LIB_DIR}/bin/cortex-m4) + set(ALIRO_LIB_PATH ${ZEPHYR_NCS_ALIRO_MODULE_DIR}/applications/doorlock/lib/aliro/bin/cortex-m4) elseif(CONFIG_SOC_SERIES_NRF54LX OR CONFIG_SOC_SERIES_NRF53X) - set(ALIRO_LIB_BIN_PATH ${ALIRO_LIB_DIR}/bin/cortex-m33) + set(ALIRO_LIB_PATH ${ZEPHYR_NCS_ALIRO_MODULE_DIR}/applications/doorlock/lib/aliro/bin/cortex-m33) endif() add_library(aliro_stack STATIC IMPORTED GLOBAL) -set_target_properties(aliro_stack PROPERTIES IMPORTED_LOCATION ${ALIRO_LIB_BIN_PATH}/libaliro.a) +if(CONFIG_ALIRO_BLE_TP) + set_target_properties(aliro_stack PROPERTIES IMPORTED_LOCATION ${ALIRO_LIB_PATH}/libaliro_ble.a) +else(CONFIG_ALIRO_BLE_TP) + set_target_properties(aliro_stack PROPERTIES IMPORTED_LOCATION ${ALIRO_LIB_PATH}/libaliro.a) +endif(CONFIG_ALIRO_BLE_TP) target_link_libraries(app PRIVATE aliro_stack) target_link_libraries(aliro_stack INTERFACE zephyr_interface) -zephyr_include_directories(${ALIRO_LIB_DIR}/include) -zephyr_include_directories(${ALIRO_LIB_DIR}/interfaces) -zephyr_include_directories(${ALIRO_LIB_DIR}/interfaces/crypto/backend_crypto_psa) +zephyr_include_directories( + ${PUBLIC_API}/include + ${PUBLIC_API}/interfaces + ${PUBLIC_API}/interfaces/crypto/backend_crypto_psa +) diff --git a/app/Kconfig b/app/Kconfig index 726bc083..92c309d3 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -4,7 +4,7 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # -rsource "src/nfc_transport_impl/Kconfig" +rsource "src/platform/Kconfig" rsource "../lib/aliro/Kconfig.defconfig" menu "Zephyr" diff --git a/app/Kconfig.sysbuild b/app/Kconfig.sysbuild new file mode 100644 index 00000000..42389cdd --- /dev/null +++ b/app/Kconfig.sysbuild @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +source "share/sysbuild/Kconfig" + +config NRF_DEFAULT_IPC_RADIO + default y + +config NETCORE_IPC_RADIO_BT_HCI_IPC + default y diff --git a/app/VERSION b/app/VERSION index 445af309..1457d6ad 100644 --- a/app/VERSION +++ b/app/VERSION @@ -1,5 +1,5 @@ VERSION_MAJOR = 0 -VERSION_MINOR = 2 +VERSION_MINOR = 1 PATCHLEVEL = 0 VERSION_TWEAK = 0 EXTRAVERSION = diff --git a/app/boards/nrf52840dk_nrf52840.overlay b/app/boards/nrf52840dk_nrf52840.overlay index 6b0a0ade..079be37b 100644 --- a/app/boards/nrf52840dk_nrf52840.overlay +++ b/app/boards/nrf52840dk_nrf52840.overlay @@ -34,8 +34,9 @@ nucleo_nfc@0 { compatible = "x-nucleo-nfc"; reg = <0>; - spi-max-frequency = <4000000>; + spi-max-frequency = ; irq-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 10 (GPIO_ACTIVE_LOW | GPIO_PULL_DOWN)>; }; }; @@ -57,3 +58,11 @@ status = "okay"; }; }; + +/ { + access_decision_indicator: access_decision_indicator{ + status = "okay"; + compatible = "access-decision-indicator"; + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/app/boards/nrf5340dk_nrf5340_cpuapp.conf b/app/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000..7f82d794 --- /dev/null +++ b/app/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Enable BLE Transport Protocol +CONFIG_ALIRO_BLE_TP=y diff --git a/app/boards/nrf5340dk_nrf5340_cpuapp.overlay b/app/boards/nrf5340dk_nrf5340_cpuapp.overlay index ee77d646..152011af 100644 --- a/app/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/app/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -24,7 +24,6 @@ }; - &spi1 { compatible = "nordic,nrf-spim"; status = "okay"; @@ -36,7 +35,16 @@ nucleo_nfc@0 { compatible = "x-nucleo-nfc"; reg = <0>; - spi-max-frequency = <4000000>; + spi-max-frequency = ; irq-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 10 (GPIO_ACTIVE_LOW | GPIO_PULL_DOWN)>; + }; +}; + +/ { + access_decision_indicator: access_decision_indicator{ + status = "okay"; + compatible = "access-decision-indicator"; + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; }; }; diff --git a/app/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/app/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index 207047c1..f07b22f0 100644 --- a/app/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/app/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -57,6 +57,12 @@ compatible = "nfc-power-control"; gpios = <&gpio2 6 ( GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN )>; }; + + access_decision_indicator: access_decision_indicator{ + status = "okay"; + compatible = "access-decision-indicator"; + gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; + }; }; &gpio0 { diff --git a/app/prj.conf b/app/prj.conf index bdb19c50..72f4727d 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -17,6 +17,7 @@ CONFIG_ASSERT=y CONFIG_CONSOLE=y CONFIG_LOG=y CONFIG_NCS_ALIRO_RFAL_LOG_LEVEL_DBG=y +CONFIG_DEBUG_STATE_MACHINE=y CONFIG_USE_SEGGER_RTT=n CONFIG_LOG_BACKEND_RTT=n CONFIG_LOG_BACKEND_SHOW_COLOR=n @@ -27,14 +28,20 @@ CONFIG_SHELL_HISTORY=n CONFIG_SHELL_WILDCARD=n # Increase shell buffer sizes -CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=512 -CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE=128 +CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=2048 +CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE=1024 # Adjust logs queue size -CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE=768 +CONFIG_SHELL_BACKEND_SERIAL_LOG_MESSAGE_QUEUE_SIZE=2048 # Print reader key that can be provisioned to the User Device CONFIG_ALIRO_PRINT_READER_GROUP_ID=y # RFAL worker stack size (TODO: optimize) CONFIG_RFAL_WORKER_THREAD_STACK_SIZE=8192 + +CONFIG_ACCESS_DECISION_INDICATOR=y + +# Workaournd for Murata issue: +# https://github.com/csa-access-control/aliro-actuator/issues/114 +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n diff --git a/app/sample.yaml b/app/sample.yaml index bf78be34..955ad24b 100644 --- a/app/sample.yaml +++ b/app/sample.yaml @@ -11,3 +11,6 @@ common: integration_platforms: *platforms tests: app.nfc_door_lock: {} + app.nfc_door_lock_src_no: + extra_args: + - CONFIG_NCS_ALIRO_SRC=n diff --git a/app/src/main.cpp b/app/src/main.cpp index 6a199b14..839e33b9 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -11,32 +11,58 @@ #include #include +#ifdef CONFIG_ACCESS_DECISION_INDICATOR +#include "access_decision_indicator.h" +#endif // CONFIG_ACCESS_DECISION_INDICATOR + #include +#include LOG_MODULE_REGISTER(door_lock_app, CONFIG_NCS_DOOR_LOCK_APP_LOG_LEVEL); +using namespace Aliro; +using namespace Aliro::Access; + int main() { + AliroError ec{}; LOG_INF("Starting nRF Door Lock Reference Application for the nRF Connect SDK"); - AliroError ec = Aliro::AliroStack::Instance().Init( +#ifdef CONFIG_ACCESS_DECISION_INDICATOR + VerifyOrReturnValue(Indicator::InitAccessDecisionIndicator() == ALIRO_NO_ERROR, EXIT_FAILURE, + LOG_ERR("Failed to initialize access decision indicator")); +#endif // CONFIG_ACCESS_DECISION_INDICATOR + + const AliroConfig config{ +#ifdef CONFIG_ALIRO_BLE_TP + .mMaxBleSessions = CONFIG_ALIRO_BLE_TP_MAX_SESSIONS, +#endif // CONFIG_ALIRO_BLE_TP + }; + + ec = AliroStack::Instance().Init( { .mOnAccessAttempt = - [](Aliro::Access::Status status) { - if (status == Aliro::Access::Status::Denied) { + [](Status status) { + if (status == Status::Denied) { LOG_INF("ACCESS DENIED"); } else { LOG_INF("ACCESS GRANTED"); +#ifdef CONFIG_ACCESS_DECISION_INDICATOR + Indicator::SignalAccessGranted(); +#endif // CONFIG_ACCESS_DECISION_INDICATOR } }, - .mOnError = [](AliroError error) { LOG_ERR("Aliro error: %s", error.ToString()); } }); + .mOnError = [](AliroError error) { LOG_ERR("Aliro error: %s", error.ToString()); } }, + config); VerifyOrDie(ec == ALIRO_NO_ERROR, "Aliro stack initialization failed"); - ec = Aliro::AliroStack::Instance().Start(); + ec = AliroStack::Instance().Start(); VerifyOrDie(ec == ALIRO_NO_ERROR, "Aliro stack start failed"); - Aliro::RegisterShellCommands(); + RegisterShellCommands(); + + LOG_INF("Application started"); - return 0; + return EXIT_SUCCESS; } diff --git a/app/src/platform/CMakeLists.txt b/app/src/platform/CMakeLists.txt new file mode 100644 index 00000000..50cee9ea --- /dev/null +++ b/app/src/platform/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +add_subdirectory(nfc_transport_impl) +add_subdirectory(logger) + +add_subdirectory_ifdef(CONFIG_ALIRO_BLE_TP ble) +add_subdirectory_ifdef(CONFIG_ALIRO_BLE_TP uwb_impl) +add_subdirectory_ifdef(CONFIG_ACCESS_DECISION_INDICATOR access_decision_indicator) diff --git a/app/src/platform/Kconfig b/app/src/platform/Kconfig new file mode 100644 index 00000000..4b0ec5f2 --- /dev/null +++ b/app/src/platform/Kconfig @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +rsource "access_decision_indicator/Kconfig" +rsource "nfc_transport_impl/Kconfig" + +if ALIRO_BLE_TP +rsource "uwb_impl/Kconfig" +endif # ALIRO_BLE_TP diff --git a/app/src/platform/access_decision_indicator/CMakeLists.txt b/app/src/platform/access_decision_indicator/CMakeLists.txt new file mode 100644 index 00000000..06eb1d4c --- /dev/null +++ b/app/src/platform/access_decision_indicator/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +file(GLOB impl_src CONFIGURE_DEPENDS *.cpp) + +zephyr_library_sources(${impl_src}) diff --git a/app/src/platform/access_decision_indicator/Kconfig b/app/src/platform/access_decision_indicator/Kconfig new file mode 100644 index 00000000..c8837c3d --- /dev/null +++ b/app/src/platform/access_decision_indicator/Kconfig @@ -0,0 +1,17 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config ACCESS_DECISION_INDICATOR + bool "Enable access decision indicator" + +config RESET_ACCESS_DECISION_INDICATOR_STATE_DELAY_MS + int "Access decision indicator reset state delay (ms)" + depends on ACCESS_DECISION_INDICATOR + default 1000 + help + Specifies how long (in milliseconds) the access indicator (e.g. LED) remains active before automatically + resetting to its default state. This is useful to provide a visual indication of the access decision made + by a Aliro Access Manager (e.g. LED indication). diff --git a/app/src/platform/access_decision_indicator/access_decision_indicator.cpp b/app/src/platform/access_decision_indicator/access_decision_indicator.cpp new file mode 100644 index 00000000..f3e4fd67 --- /dev/null +++ b/app/src/platform/access_decision_indicator/access_decision_indicator.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "access_decision_indicator.h" + +#include "aliro/utils.h" + +#include +#include + +namespace { + +constexpr int kDelayMs{ CONFIG_RESET_ACCESS_DECISION_INDICATOR_STATE_DELAY_MS }; +constexpr int kLedOn{ 1 }; +constexpr int kLedOff{ 0 }; +constexpr gpio_dt_spec kAccessGrantedLed = GPIO_DT_SPEC_GET(DT_NODELABEL(access_decision_indicator), gpios); + +static K_WORK_DELAYABLE_DEFINE(ResetIndicatorStateWork, + []([[maybe_unused]] k_work *) { (void)gpio_pin_set_dt(&kAccessGrantedLed, kLedOff); }); + +} // namespace + +namespace Aliro::Access::Indicator { + +AliroError InitAccessDecisionIndicator() +{ + VerifyOrReturnStatus(gpio_is_ready_dt(&kAccessGrantedLed), ALIRO_ERROR_INTERNAL); + VerifyOrReturnStatus(gpio_pin_configure_dt(&kAccessGrantedLed, GPIO_OUTPUT_INACTIVE) == 0, + ALIRO_ERROR_INTERNAL); + + return ALIRO_NO_ERROR; +} + +void SignalAccessGranted() +{ + (void)gpio_pin_set_dt(&kAccessGrantedLed, kLedOn); + (void)k_work_schedule(&ResetIndicatorStateWork, K_MSEC(kDelayMs)); +} + +} // namespace Aliro::Access::Indicator diff --git a/app/src/platform/access_decision_indicator/access_decision_indicator.h b/app/src/platform/access_decision_indicator/access_decision_indicator.h new file mode 100644 index 00000000..c1d506b2 --- /dev/null +++ b/app/src/platform/access_decision_indicator/access_decision_indicator.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include + +namespace Aliro::Access::Indicator { + +/** + * @brief Initializes a access decision indicator (e.g LED). + * This function sets up the access decision indicator to be used + * when an access decision is made. + * + * @return ALIRO_NO_ERROR on success, or an error code on failure. + */ +AliroError InitAccessDecisionIndicator(); + +/** + * @brief Signals that access has been granted. + * This function activates the access decision indicator (e.g LED) + * to indicate that access has been granted. + * It also schedules a work to reset the indicator state after a delay. + */ +void SignalAccessGranted(); + +} // namespace Aliro::Access::Indicator diff --git a/app/src/platform/ble/CMakeLists.txt b/app/src/platform/ble/CMakeLists.txt new file mode 100644 index 00000000..c79a14d7 --- /dev/null +++ b/app/src/platform/ble/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +file(GLOB ble_src CONFIGURE_DEPENDS *.cpp) + +zephyr_library_sources(${ble_src}) diff --git a/app/src/platform/ble/l2cap_server_net_buf_pool.cpp b/app/src/platform/ble/l2cap_server_net_buf_pool.cpp new file mode 100644 index 00000000..d8859aed --- /dev/null +++ b/app/src/platform/ble/l2cap_server_net_buf_pool.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "transport/ble/l2cap_server_net_buf_pool.h" + +#include +#include +#include + +namespace { + +NET_BUF_POOL_DEFINE(sNetBufPool, CONFIG_ALIRO_BLE_TP_MAX_SESSIONS, BT_L2CAP_SDU_BUF_SIZE(BT_L2CAP_SDU_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, nullptr); + +} // namespace + +namespace Aliro { + +net_buf_pool *sL2CapServerNetBufPool{ &sNetBufPool }; + +} // namespace Aliro diff --git a/app/src/platform/logger/CMakeLists.txt b/app/src/platform/logger/CMakeLists.txt new file mode 100644 index 00000000..825f1596 --- /dev/null +++ b/app/src/platform/logger/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +file(GLOB logger_src CONFIGURE_DEPENDS *.cpp) + +zephyr_library_sources(${logger_src}) diff --git a/app/src/platform/logger/platform_log.cpp b/app/src/platform/logger/platform_log.cpp new file mode 100644 index 00000000..2e011adf --- /dev/null +++ b/app/src/platform/logger/platform_log.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "logger/platform_log.h" + +#include + +#include + +LOG_MODULE_REGISTER(platform, CONFIG_NCS_DOOR_LOCK_APP_LOG_LEVEL); + +void _AliroPlatformLogHexdump(uint8_t platformLogLevel, const void *data, size_t size, const char *str) +{ + switch (platformLogLevel) { + case LOG_LEVEL_ERR: + LOG_HEXDUMP_ERR(data, size, str); + break; + case LOG_LEVEL_WRN: + LOG_HEXDUMP_WRN(data, size, str); + break; + case LOG_LEVEL_INF: + LOG_HEXDUMP_INF(data, size, str); + break; + case LOG_LEVEL_DBG: + LOG_HEXDUMP_DBG(data, size, str); + break; + case LOG_LEVEL_NONE: + default: + break; + } +} + +void _AliroPlatformLog(uint8_t platformLogLevel, const char *logFormat, ...) +{ +#if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) + + if (platformLogLevel > CONFIG_NCS_ALIRO_LOG_LEVEL_VALUE) { + return; + } + + va_list paramList; + va_start(paramList, logFormat); + log_generic(platformLogLevel, logFormat, paramList); + va_end(paramList); + +#else // defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) + + ARG_UNUSED(platformLogLevel); + ARG_UNUSED(logFormat); + +#endif // defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) +} diff --git a/app/src/platform/nfc_transport_impl/CMakeLists.txt b/app/src/platform/nfc_transport_impl/CMakeLists.txt new file mode 100644 index 00000000..06eb1d4c --- /dev/null +++ b/app/src/platform/nfc_transport_impl/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +file(GLOB impl_src CONFIGURE_DEPENDS *.cpp) + +zephyr_library_sources(${impl_src}) diff --git a/app/src/platform/nfc_transport_impl/Kconfig b/app/src/platform/nfc_transport_impl/Kconfig new file mode 100644 index 00000000..ba2a5eaf --- /dev/null +++ b/app/src/platform/nfc_transport_impl/Kconfig @@ -0,0 +1,26 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +rsource "Kconfig.rfal.defconfig" + +config RFAL_RX_TIMEOUT_MS + int "RFAL RX timeout in ms" + default 500 + +config RFAL_IDLE_TIMEOUT_MS + int "RFAL idle timeout in ms" + default 500 + +# Prompt-less option only for internal tuning of the RFAL worker thread. Do not change it. +config RFAL_NFC_WORKER_TIMEOUT_MS + int + default 30 + +module = NCS_ALIRO_RFAL +module-str = ALIRO_RFAL +module-dep = LOG +module-help = Enables Aliro NFC RFAL log messages. +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" diff --git a/app/src/platform/nfc_transport_impl/Kconfig.rfal.defconfig b/app/src/platform/nfc_transport_impl/Kconfig.rfal.defconfig new file mode 100644 index 00000000..724a02cc --- /dev/null +++ b/app/src/platform/nfc_transport_impl/Kconfig.rfal.defconfig @@ -0,0 +1,23 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config NFC_DRIVER_STM + default y + +config RFAL_FEATURE_NFCA + default y + +config RFAL_FEATURE_WAKEUP_MODE + default y + +config RFAL_FEATURE_T4T + default y + +config RFAL_FEATURE_ISO_DEP + default y + +config RFAL_FEATURE_ISO_DEP_POLL + default y diff --git a/app/src/platform/nfc_transport_impl/isodep_config.h b/app/src/platform/nfc_transport_impl/isodep_config.h new file mode 100644 index 00000000..11188c0f --- /dev/null +++ b/app/src/platform/nfc_transport_impl/isodep_config.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +/* An alias for a name of the class that implements the IsoDep interface. */ +#define IsoDepImpl NfcTransportRfal diff --git a/app/src/platform/nfc_transport_impl/isodep_impl.h b/app/src/platform/nfc_transport_impl/isodep_impl.h new file mode 100644 index 00000000..070867ce --- /dev/null +++ b/app/src/platform/nfc_transport_impl/isodep_impl.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "nfc_transport_rfal.h" diff --git a/app/src/platform/nfc_transport_impl/nfc_driver_config.h b/app/src/platform/nfc_transport_impl/nfc_driver_config.h new file mode 100644 index 00000000..c4075d4c --- /dev/null +++ b/app/src/platform/nfc_transport_impl/nfc_driver_config.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +/* An alias for a name of the class that implements the NfcDriver interface. */ +#define NfcDriverImpl NfcTransportRfal diff --git a/app/src/platform/nfc_transport_impl/nfc_driver_impl.h b/app/src/platform/nfc_transport_impl/nfc_driver_impl.h new file mode 100644 index 00000000..070867ce --- /dev/null +++ b/app/src/platform/nfc_transport_impl/nfc_driver_impl.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "nfc_transport_rfal.h" diff --git a/app/src/platform/nfc_transport_impl/nfc_transport_rfal.cpp b/app/src/platform/nfc_transport_impl/nfc_transport_rfal.cpp new file mode 100644 index 00000000..5625d392 --- /dev/null +++ b/app/src/platform/nfc_transport_impl/nfc_transport_rfal.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "nfc_transport_rfal.h" +#include "ncs_pal_semaphore.h" +#include +#include + +#include "aliro/utils.h" +#include "ncs_pal_nfc_worker.h" + +#include + +LOG_MODULE_REGISTER(nfc_st_rfal_impl, CONFIG_NCS_ALIRO_RFAL_LOG_LEVEL); + +namespace Aliro { + +K_THREAD_STACK_DEFINE(mStack, CONFIG_RFAL_WORKER_THREAD_STACK_SIZE); + +[[noreturn]] void NfcTransportRfal::Run() +{ + while (true) { + if (mRecoverPolling && !mSendInProgress) { + mRecoverPolling = false; + RecoverPolling(); + } + rfalNfcWorker(); + ncs_pal_take_semaphore(K_MSEC(CONFIG_RFAL_NFC_WORKER_TIMEOUT_MS)); + } +} + +void NfcTransportRfal::RfalNotifyCallback(rfalNfcState state) +{ + switch (state) { + case RFAL_NFC_STATE_WAKEUP_MODE: + LOG_DBG("RFAL: Wake Up mode state"); + break; + case RFAL_NFC_STATE_POLL_TECHDETECT: + LOG_DBG("RFAL: Poll technology detect state"); + if (mNfcConfig.wakeupEnabled) { + LOG_DBG("RFAL: Wake Up mode terminated. Polling for devices."); + } + break; + case RFAL_NFC_STATE_POLL_SELECT: + LOG_DBG("RFAL: Poll select state"); + // Check if in case of multiple devices, selection is already attempted + if (!mMultiSel) { + mMultiSel = true; + // Multiple devices were found, activate first of them + uint8_t devCnt; + rfalNfcDevice *dev; + (void)rfalNfcGetDevicesFound(&dev, &devCnt); + (void)rfalNfcSelect(0); + LOG_DBG("RFAL: Multiple Tags detected: %d", devCnt); + } else { + (void)rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY); + } + break; + case RFAL_NFC_STATE_START_DISCOVERY: + LOG_DBG("RFAL: Start discovery state"); + mMultiSel = false; + mSendInProgress = false; + break; + case RFAL_NFC_STATE_DATAEXCHANGE: + LOG_DBG("RFAL: Data exchange state"); + break; + case RFAL_NFC_STATE_DATAEXCHANGE_DONE: + mSendInProgress = false; + CaptureRxData(); + break; + case RFAL_NFC_STATE_DEACTIVATION: + LOG_DBG("RFAL: Deactivation State"); + mSendInProgress = false; + break; + case RFAL_NFC_STATE_ACTIVATED: + LOG_DBG("RFAL: Activated state"); + SelectTag(); + break; + default: + break; + } +} + +ReturnCode NfcTransportRfal::RfalNfcInit() +{ + ReturnCode err = rfalNfcInitialize(); + VerifyOrExit(err == RFAL_ERR_NONE); + + // Set default discovery parameters. + rfalNfcDefaultDiscParams(&mNfcConfig); + // Set wake-up configuration. + rfalNfcWakeupConfig(&mNfcConfig); + // Set only NFC-A technology Flag. + mNfcConfig.techs2Find |= RFAL_NFC_POLL_TECH_A; + + mNfcConfig.notifyCb = [](rfalNfcState state) { Instance().RfalNotifyCallback(state); }; +exit: + return err; +} + +void NfcTransportRfal::SelectTag() const +{ + rfalNfcDevice *nfcDevice; + rfalNfcGetActiveDevice(&nfcDevice); + VerifyOrReturn(nfcDevice); + + LOG_INF("RFAL: Active device type = %d", nfcDevice->type); + + if (nfcDevice->type == RFAL_NFC_LISTEN_TYPE_NFCA) { + if (nfcDevice->dev.nfca.type == RFAL_NFCA_T4T) { + LOG_HEXDUMP_DBG(nfcDevice->nfcid, nfcDevice->nfcidLen, + "RFAL: NFCA Passive ISO-DEP device found. UID: "); + VerifyAndCall(this->NfcDriver::mCallbacks.mOnTagDetected); + } else { + LOG_HEXDUMP_DBG(nfcDevice->nfcid, nfcDevice->nfcidLen, + "RFAL: Usupported NFC card found. UID: %s"); + } + } +} + +void NfcTransportRfal::CaptureRxData() +{ + ReturnCode status = rfalNfcDataExchangeGetStatus(); + if (status == RFAL_ERR_BUSY) { + LOG_ERR("RFAL: Data transaction has not been completed [status: %d]", status); + VerifyAndCall(this->NfcDriver::mCallbacks.mOnError, ALIRO_INVALID_STATE); + return; + } + + uint16_t currentDataLen = *mRcvLen; + memset(mRxBuffer.data(), 0, mRxBuffer.size()); + + VerifyOrReturn(mRxBuffer.size() >= currentDataLen); + memcpy(mRxBuffer.data(), mRxData, currentDataLen); + + LOG_HEXDUMP_DBG(mRxBuffer.data(), currentDataLen, "RFAL: RX data:"); + + VerifyAndCall(NfcDriver::mCallbacks.mOnDataReceived, { .mData = mRxBuffer.data(), .mLength = currentDataLen }, + 0); +} + +void NfcTransportRfal::RecoverPolling() const +{ + if (rfalNfcIsDevActivated(rfalNfcGetState())) { + ReturnCode err = rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_SLEEP); + VerifyOrReturn(err == RFAL_ERR_NONE, LOG_ERR("RFAL: Deactivation failed, return code: %d", err)); + } +} + +/* +****************************************************************************** +* IsoDep interface implementation +****************************************************************************** +*/ +AliroError NfcTransportRfal::_Init(IsoDep::Callbacks callbacks) +{ + IsoDep::mCallbacks = callbacks; + return ALIRO_NO_ERROR; +} + +AliroError NfcTransportRfal::_PrepareData([[maybe_unused]] Data data) const +{ + // ISO-DEP layer is implemented internally in the RFAL, no need for special data handling + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +AliroError NfcTransportRfal::_PrepareRats() const +{ + // RATS is sent by the driver internally as an activation procedure, so we can presume the tag is fully selected + // a this point + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +AliroError NfcTransportRfal::_HandleReceivedData([[maybe_unused]] Data data, [[maybe_unused]] int transferError) const +{ + // No specific processing needed, all ISO-DEP specific data handling happens in driver's internals + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +AliroError NfcTransportRfal::_ReportTimeout() const +{ + // No special handling needed with RFAL + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +/* Implementation of the generic IsoDep instance getter. */ +IsoDep &IsoDepInstance() +{ + return NfcTransportRfal::Instance(); +} +/* +****************************************************************************** +****************************************************************************** +*/ + +/* +****************************************************************************** +* NfcDriver interface implementation +****************************************************************************** +*/ +AliroError NfcTransportRfal::_Init(NfcDriver::Callbacks callbacks) +{ + NfcDriver::mCallbacks = callbacks; + + int err = rfal_ncs_pal_init(); + VerifyOrReturnStatus(err == 0, ALIRO_ERROR_INTERNAL, LOG_ERR("RFAL: NFC PAL init failed %d", err)); + + const k_tid_t thread = ncs_pal_nfc_worker_start([](void *, void *, void *) { Instance().Run(); }); + + VerifyOrReturnStatus(thread, ALIRO_INVALID_STATE, LOG_ERR("RFAL: Cannot spawn the NFC driver thread")); + VerifyOrReturnStatus(RfalNfcInit() == RFAL_ERR_NONE, ALIRO_ERROR_INTERNAL, + LOG_ERR("RFAL: NFC initialization failed")); + + return ALIRO_NO_ERROR; +} + +AliroError NfcTransportRfal::_Send(Data data, [[maybe_unused]] uint32_t maximumFrameDelayTime) +{ + LOG_HEXDUMP_DBG(data.mData, data.mLength, "RFAL: TX data:"); + mSendInProgress = true; + + // use RFAL_FWT_NONE as FWT because the driver with ISO-DEP enabled will ignore it anyway + ReturnCode err = rfalNfcDataExchangeStart(data.mData, data.mLength, &mRxData, &mRcvLen, RFAL_FWT_NONE); + VerifyOrReturnStatus(err == RFAL_ERR_NONE, ALIRO_ERROR_INTERNAL, + LOG_ERR("RFAL: Data exchange failed, return code: %d", err); + mSendInProgress = false); + + return ALIRO_NO_ERROR; +} + +AliroError NfcTransportRfal::_NfcOn() const +{ + // The RF field is turned right after the STR25 boots + // The only thing that must be done is to activate the reader + // by starting tag discovery procedure. + ReturnCode err = rfalNfcDiscover(&mNfcConfig); + VerifyOrReturnStatus(err == RFAL_ERR_NONE, ALIRO_ERROR_INTERNAL, + LOG_ERR("RFAL: NFC discovery failed, return code: %d", err)); + + return ALIRO_NO_ERROR; +} + +AliroError NfcTransportRfal::_NfcOff() const +{ + // RFAL handles this internally and knows when the field can be off + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +AliroError NfcTransportRfal::_RestartPolling() +{ + mRecoverPolling = true; + + return ALIRO_NO_ERROR; +} + +/* Implementation of the generic NfcDriver instance getter. */ +NfcDriver &NfcDriverInstance() +{ + return NfcTransportRfal::Instance(); +} +/* +****************************************************************************** +****************************************************************************** +*/ + +} // namespace Aliro diff --git a/app/src/platform/nfc_transport_impl/nfc_transport_rfal.h b/app/src/platform/nfc_transport_impl/nfc_transport_rfal.h new file mode 100644 index 00000000..d803fe92 --- /dev/null +++ b/app/src/platform/nfc_transport_impl/nfc_transport_rfal.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "transport/nfc/driver/interface/aliro_nfc_driver.h" +#include "transport/nfc/isodep/interface/aliro_isodep.h" + +extern "C" { +#include +#include +#include +} + +#include + +#include + +namespace Aliro { + +class NfcTransportRfal : public IsoDep, public NfcDriver { +private: + friend class IsoDep; + friend IsoDep &IsoDepInstance(); + friend class NfcDriver; + friend NfcDriver &NfcDriverInstance(); + + // IsoDep interface + AliroError _Init(IsoDep::Callbacks callbacks); + AliroError _PrepareData(Data data) const; + AliroError _PrepareRats() const; + AliroError _HandleReceivedData(Data data, int transferError) const; + AliroError _ReportTimeout() const; + + // NfcDriver interface + AliroError _Init(NfcDriver::Callbacks callbacks); + AliroError _Send(Data data, uint32_t maximumFrameDelayTime); + AliroError _NfcOn() const; + AliroError _NfcOff() const; + AliroError _RestartPolling(); + + static NfcTransportRfal &Instance() + { + static NfcTransportRfal sInstance; + return sInstance; + } + + ReturnCode RfalNfcInit(); + [[noreturn]] void Run(); + void RfalNotifyCallback(rfalNfcState state); + void CaptureRxData(); + void SelectTag() const; + void RecoverPolling() const; + + rfalNfcDiscoverParam mNfcConfig{}; + k_thread mThread{}; + bool mMultiSel{ false }; + + std::array mRxBuffer{}; + uint8_t *mRxData{}; + uint16_t *mRcvLen{}; + + bool mRecoverPolling{ false }; + bool mSendInProgress{ false }; + + static constexpr uint32_t sIdleTimerTimeoutMs{ CONFIG_RFAL_IDLE_TIMEOUT_MS }; +}; + +} // namespace Aliro diff --git a/app/src/platform/uwb_impl/CMakeLists.txt b/app/src/platform/uwb_impl/CMakeLists.txt new file mode 100644 index 00000000..ac580ce1 --- /dev/null +++ b/app/src/platform/uwb_impl/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +if(CONFIG_QM35_UWB_ALIRO_ZEPHYR) + add_subdirectory(uwb_qm35_impl) +else() + add_subdirectory(uwb_dummy_impl) +endif() diff --git a/app/src/platform/uwb_impl/Kconfig b/app/src/platform/uwb_impl/Kconfig new file mode 100644 index 00000000..36c321d7 --- /dev/null +++ b/app/src/platform/uwb_impl/Kconfig @@ -0,0 +1,9 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +if QM35_UWB_ALIRO_ZEPHYR +rsource "uwb_qm35_impl/Kconfig" +endif # QM35_UWB_ALIRO_ZEPHYR diff --git a/app/src/platform/uwb_impl/uwb_dummy_impl/CMakeLists.txt b/app/src/platform/uwb_impl/uwb_dummy_impl/CMakeLists.txt new file mode 100644 index 00000000..ffdeb472 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_dummy_impl/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) diff --git a/app/src/platform/uwb_impl/uwb_dummy_impl/uwb_impl.h b/app/src/platform/uwb_impl/uwb_dummy_impl/uwb_impl.h new file mode 100644 index 00000000..867ea069 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_dummy_impl/uwb_impl.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "aliro/errors.h" +#include "uwb/uwb.h" + +#include + +namespace Aliro::Uwb { + +/** + * @class UltraWideBandImpl + * @brief Dummy implementation of the UltraWideBand interface. + * + * This class provides the dummy implementation of the UltraWideBand interface, handling UWB operations + * such as initialization, ranging session management, and BLE message handling. + */ +class UltraWideBandImpl : public UltraWideBand { +public: + /** + * @brief Gets the instance of the UltraWideBand implementation. + * + * @return The instance of the UltraWideBand implementation. + */ + static UltraWideBandImpl &Instance() + { + static UltraWideBandImpl sInstance; + return sInstance; + } + + AliroError _Init([[maybe_unused]] const Callbacks &) const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + AliroError _Deinit() const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + void + _BleTimeSync() const { /* No operation for dummy implementation; override in derived classes if needed. */ }; + + AliroError _HandleBleMessage([[maybe_unused]] const uint8_t *, [[maybe_unused]] size_t) const + { + return ALIRO_ERROR_NOT_IMPLEMENTED; + } + + AliroError _ConfigureRangingSession([[maybe_unused]] SessionIdentifier, [[maybe_unused]] const uint8_t *, + [[maybe_unused]] size_t, [[maybe_unused]] const void *) const + { + return ALIRO_ERROR_NOT_IMPLEMENTED; + } + + AliroError _InitiateRangingSession() const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + + AliroError _TerminateRangingSession() const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + AliroError _SuspendRangingSession() const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + AliroError _ResumeRangingSession() const { return ALIRO_ERROR_NOT_IMPLEMENTED; } + + // Delete copy and move constructors and assignment operators. + UltraWideBandImpl(const UltraWideBandImpl &) = delete; + UltraWideBandImpl &operator=(const UltraWideBandImpl &) = delete; + UltraWideBandImpl(UltraWideBandImpl &&) = delete; + UltraWideBandImpl &operator=(UltraWideBandImpl &&) = delete; + +private: + UltraWideBandImpl() = default; + ~UltraWideBandImpl() = default; +}; + +} // namespace Aliro::Uwb diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/CMakeLists.txt b/app/src/platform/uwb_impl/uwb_qm35_impl/CMakeLists.txt new file mode 100644 index 00000000..d7075515 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_include_directories(.) + +file(GLOB uwb_src CONFIGURE_DEPENDS *.cpp) + +zephyr_library_sources(${uwb_src}) diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig b/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig new file mode 100644 index 00000000..205f9c7d --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig @@ -0,0 +1,69 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +rsource "Kconfig.defconfig" + +config ALIRO_UWB_MIN_RAN_MULTIPLIER + int "Minimum RAN multiplier for UWB ranging blocks" + default 1 + range 1 255 + help + The RAN multiplier allows to define the time between 2 ranging blocks. + The time range is between 96 ms (RAN multiplier is 1) and 24480 ms + (RAN multiplier is 255). + +choice ALIRO_UWB_PREFERRED_HOPPING_CONFIG + prompt "Preferred hopping configuration" + default ALIRO_UWB_HOPPING_CONTINUOUS + help + Select the preferred hopping configuration for UWB. + +config ALIRO_UWB_HOPPING_AES + bool "AES based hopping sequence" + +config ALIRO_UWB_HOPPING_DEFAULT + bool "Default hopping sequence" + +config ALIRO_UWB_HOPPING_ADAPTIVE + bool "Adaptive hopping mode" + +config ALIRO_UWB_HOPPING_CONTINUOUS + bool "Continuous hopping mode" + +config ALIRO_UWB_HOPPING_NONE + bool "No hopping" + +endchoice + +config ALIRO_UWB_PREFERRED_HOPPING_CONFIG_VALUE + hex + default 0x01 if ALIRO_UWB_HOPPING_AES + default 0x02 if ALIRO_UWB_HOPPING_DEFAULT + default 0x04 if ALIRO_UWB_HOPPING_ADAPTIVE + default 0x08 if ALIRO_UWB_HOPPING_CONTINUOUS + default 0x10 if ALIRO_UWB_HOPPING_NONE + +config ALIRO_UWB_MAC_MODE_OFFSET + int "Offset between ranging blocks in MAC mode" + default 0 + range 0 63 + help + Offset between the 2 ranging blocks. + +config ALIRO_UWB_MAC_MODE_RANGING_ROUNDS + int "Number of ranging rounds per ranging block" + default 0 + range 0 1 + help + Number of ranging rounds used in a ranging block. + Values: + - 0: 1 ranging round + - 1: 2 ranging round + +config ALIRO_UWB_SESSION_LOGGING + bool "Enable UWB session state logging" + help + Enable logging for UWB session states and reason codes. diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig.defconfig b/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig.defconfig new file mode 100644 index 00000000..0cffff07 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/Kconfig.defconfig @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config UART_NRFX_UARTE_LEGACY_SHIM + bool + default n + +config QOSAL_MAX_MUTEX + int + default 8 diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/calibration/qm35825_calib.h b/app/src/platform/uwb_impl/uwb_qm35_impl/calibration/qm35825_calib.h new file mode 100644 index 00000000..cf0430f4 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/calibration/qm35825_calib.h @@ -0,0 +1,286 @@ +/* + * Header file for chip calibration. + * + * SPDX-FileCopyrightText: Copyright (c) 2025 Qorvo, Inc. + * SPDX-License-Identifier: LicenseRef-QORVO-2 + */ + +#pragma once + +#include + +/* Modified calibration based on jolie_quad_GSavg_27032025.json. */ +static const uint8_t util_calib_qm35825_ant_pair_0_ant_path[] = { 0x03, 0x01 }; +static const uint8_t util_calib_qm35825_ant_pair_1_ant_path[] = { 0x02, 0x01 }; +static const uint8_t util_calib_qm35825_ant_set0_tx_ant_paths[] = { 0x00, + 0xFF }; +static const uint8_t util_calib_qm35825_ant_set3_tx_ant_paths[] = { 0x00, + 0xFF }; +static const uint8_t util_calib_qm35825_ant_set0_rx_ants[] = { 0x00, 0x01, + 0x00 }; +static const uint8_t util_calib_qm35825_ant_set3_rx_ants[] = { 0x02, 0xFF, + 0xFF }; + +static const uint16_t util_calib_qm35825_pdoa_lut0_ch5[][2] = { + { 0xEBBC, 0xF370 }, /* original: -2.533321, -1.570796 */ + { 0xEBFB, 0xF446 }, /* original: -2.502671, -1.466077 */ + { 0xEC95, 0xF51C }, /* original: -2.427698, -1.361357 */ + { 0xED66, 0xF5F3 }, /* original: -2.325576, -1.256637 */ + { 0xEE3F, 0xF6C9 }, /* original: -2.219499, -1.151917 */ + { 0xEF0D, 0xF7A0 }, /* original: -2.118834, -1.047198 */ + { 0xEFEF, 0xF876 }, /* original: -2.008664, -0.942478 */ + { 0xF0F5, 0xF94D }, /* original: -1.880509, -0.837758 */ + { 0xF22D, 0xFA23 }, /* original: -1.728161, -0.733038 */ + { 0xF3A2, 0xFAFA }, /* original: -1.545929, -0.628319 */ + { 0xF541, 0xFBD0 }, /* original: -1.343469, -0.523599 */ + { 0xF701, 0xFCA7 }, /* original: -1.124806, -0.418879 */ + { 0xF8E9, 0xFD7D }, /* original: -0.886351, -0.314159 */ + { 0xFB09, 0xFE54 }, /* original: -0.621014, -0.209440 */ + { 0xFD66, 0xFF2A }, /* original: -0.325595, -0.104720 */ + { 0xFFEE, 0x0000 }, /* original: -0.008833, 0.000000 */ + { 0x0294, 0x00D6 }, /* original: 0.322504, 0.104720 */ + { 0x0529, 0x01AC }, /* original: 0.645128, 0.209440 */ + { 0x0791, 0x0283 }, /* original: 0.946167, 0.314159 */ + { 0x09BE, 0x0359 }, /* original: 1.217986, 0.418879 */ + { 0x0B99, 0x0430 }, /* original: 1.450172, 0.523599 */ + { 0x0D1F, 0x0506 }, /* original: 1.640173, 0.628319 */ + { 0x0E84, 0x05DD }, /* original: 1.814894, 0.733038 */ + { 0x100C, 0x06B3 }, /* original: 2.006023, 0.837758 */ + { 0x11E4, 0x078A }, /* original: 2.236502, 0.942478 */ + { 0x13E9, 0x0860 }, /* original: 2.489156, 1.047198 */ + { 0x159C, 0x0937 }, /* original: 2.701204, 1.151917 */ + { 0x16D1, 0x0A0D }, /* original: 2.852178, 1.256637 */ + { 0x1798, 0x0AE4 }, /* original: 2.949266, 1.361357 */ + { 0x181E, 0x0BBA }, /* original: 3.014801, 1.466077 */ + { 0x18B3, 0x0C90 }, /* original: 3.087452, 1.570796 */ +}; + +static const uint16_t util_calib_qm35825_pdoa_lut1_ch9[][2] = { + { 0xE276, 0xF370 }, /* original: -3.692644, -1.570796 */ + { 0xE552, 0xF446 }, /* original: -3.334963, -1.466077 */ + { 0xE7A9, 0xF51C }, /* original: -3.042653, -1.361357 */ + { 0xE99B, 0xF5F3 }, /* original: -2.799788, -1.256637 */ + { 0xEB8F, 0xF6C9 }, /* original: -2.555214, -1.151917 */ + { 0xEDD8, 0xF7A0 }, /* original: -2.269609, -1.047198 */ + { 0xF040, 0xF876 }, /* original: -1.968854, -0.942478 */ + { 0xF26B, 0xF94D }, /* original: -1.698059, -0.837758 */ + { 0xF3F7, 0xFA23 }, /* original: -1.504771, -0.733038 */ + { 0xF4E2, 0xFAFA }, /* original: -1.389977, -0.628319 */ + { 0xF596, 0xFBD0 }, /* original: -1.302234, -0.523599 */ + { 0xF6D7, 0xFCA7 }, /* original: -1.145199, -0.418879 */ + { 0xF8BD, 0xFD7D }, /* original: -0.907927, -0.314159 */ + { 0xFB11, 0xFE54 }, /* original: -0.616846, -0.209440 */ + { 0xFD93, 0xFF2A }, /* original: -0.303409, -0.104720 */ + { 0xFFEC, 0x0000 }, /* original: -0.009988, 0.000000 */ + { 0x01F6, 0x00D6 }, /* original: 0.245181, 0.104720 */ + { 0x03A1, 0x01AC }, /* original: 0.453615, 0.209440 */ + { 0x0518, 0x0283 }, /* original: 0.637080, 0.314159 */ + { 0x068D, 0x0359 }, /* original: 0.819239, 0.418879 */ + { 0x0836, 0x0430 }, /* original: 1.026568, 0.523599 */ + { 0x0A43, 0x0506 }, /* original: 1.282985, 0.628319 */ + { 0x0C8A, 0x05DD }, /* original: 1.567616, 0.733038 */ + { 0x0EA8, 0x06B3 }, /* original: 1.832378, 0.837758 */ + { 0x107F, 0x078A }, /* original: 2.062391, 0.942478 */ + { 0x1215, 0x0860 }, /* original: 2.260298, 1.047198 */ + { 0x137E, 0x0937 }, /* original: 2.436810, 1.151917 */ + { 0x14D6, 0x0A0D }, /* original: 2.604729, 1.256637 */ + { 0x1623, 0x0AE4 }, /* original: 2.767291, 1.361357 */ + { 0x173E, 0x0BBA }, /* original: 2.905700, 1.466077 */ + { 0x17F9, 0x0C90 }, /* original: 2.996765, 1.570796 */ +}; + +static const uint16_t util_calib_qm35825_pdoa_lut2_ch5[][2] = { + { 0xE9A9, 0xF370 }, /* original: -2.792527, -1.570796 */ + { 0xEB2C, 0xF446 }, /* original: -2.603787, -1.466077 */ + { 0xEBA9, 0xF51C }, /* original: -2.542772, -1.361357 */ + { 0xEBE6, 0xF5F3 }, /* original: -2.512901, -1.256637 */ + { 0xEC73, 0xF6C9 }, /* original: -2.443996, -1.151917 */ + { 0xED40, 0xF7A0 }, /* original: -2.343959, -1.047198 */ + { 0xEE2F, 0xF876 }, /* original: -2.227345, -0.942478 */ + { 0xEF79, 0xF94D }, /* original: -2.066077, -0.837758 */ + { 0xF18A, 0xFA23 }, /* original: -1.807950, -0.733038 */ + { 0xF3AE, 0xFAFA }, /* original: -1.540392, -0.628319 */ + { 0xF549, 0xFBD0 }, /* original: -1.339376, -0.523599 */ + { 0xF715, 0xFCA7 }, /* original: -1.114900, -0.418879 */ + { 0xF8A6, 0xFD7D }, /* original: -0.919253, -0.314159 */ + { 0xFAE7, 0xFE54 }, /* original: -0.637496, -0.209440 */ + { 0xFDBD, 0xFF2A }, /* original: -0.282860, -0.104720 */ + { 0xFFF8, 0x0000 }, /* original: -0.003959, 0.000000 */ + { 0x02B5, 0x00D6 }, /* original: 0.338599, 0.104720 */ + { 0x0598, 0x01AC }, /* original: 0.699250, 0.209440 */ + { 0x07DF, 0x0283 }, /* original: 0.984358, 0.314159 */ + { 0x0A49, 0x0359 }, /* original: 1.285751, 0.418879 */ + { 0x0CA8, 0x0430 }, /* original: 1.582377, 0.523599 */ + { 0x0E60, 0x0506 }, /* original: 1.796904, 0.628319 */ + { 0x0FFC, 0x05DD }, /* original: 1.998268, 0.733038 */ + { 0x1162, 0x06B3 }, /* original: 2.173067, 0.837758 */ + { 0x1251, 0x078A }, /* original: 2.289824, 0.942478 */ + { 0x12D9, 0x0860 }, /* original: 2.356255, 1.047198 */ + { 0x135E, 0x0937 }, /* original: 2.421218, 1.151917 */ + { 0x13E1, 0x0A0D }, /* original: 2.484917, 1.256637 */ + { 0x1429, 0x0AE4 }, /* original: 2.520422, 1.361357 */ + { 0x14CC, 0x0BBA }, /* original: 2.599798, 1.466077 */ + { 0x1657, 0x0C90 }, /* original: 2.792527, 1.570796 */ +}; + +static const uint16_t util_calib_qm35825_pdoa_lut3_ch9[][2] = { + { 0xE844, 0xF370 }, /* original: -2.967060, -1.570796 */ + { 0xE91A, 0xF446 }, /* original: -2.862340, -1.466077 */ + { 0xEA42, 0xF51C }, /* original: -2.717778, -1.361357 */ + { 0xEB40, 0xF5F3 }, /* original: -2.593895, -1.256637 */ + { 0xEBAA, 0xF6C9 }, /* original: -2.542119, -1.151917 */ + { 0xEC4A, 0xF7A0 }, /* original: -2.464203, -1.047198 */ + { 0xEE05, 0xF876 }, /* original: -2.247908, -0.942478 */ + { 0xF181, 0xF94D }, /* original: -1.812106, -0.837758 */ + { 0xF571, 0xFA23 }, /* original: -1.320167, -0.733038 */ + { 0xF721, 0xFAFA }, /* original: -1.109353, -0.628319 */ + { 0xF79D, 0xFBD0 }, /* original: -1.048388, -0.523599 */ + { 0xF8BF, 0xFCA7 }, /* original: -0.906986, -0.418879 */ + { 0xFA51, 0xFD7D }, /* original: -0.710901, -0.314159 */ + { 0xFBCE, 0xFE54 }, /* original: -0.524584, -0.209440 */ + { 0xFDB2, 0xFF2A }, /* original: -0.288408, -0.104720 */ + { 0xFFD6, 0x0000 }, /* original: -0.020595, 0.000000 */ + { 0x029D, 0x00D6 }, /* original: 0.326923, 0.104720 */ + { 0x053A, 0x01AC }, /* original: 0.653783, 0.209440 */ + { 0x07DA, 0x0283 }, /* original: 0.981670, 0.314159 */ + { 0x0A61, 0x0359 }, /* original: 1.297462, 0.418879 */ + { 0x0CAF, 0x0430 }, /* original: 1.585514, 0.523599 */ + { 0x0F38, 0x0506 }, /* original: 1.902817, 0.628319 */ + { 0x1176, 0x05DD }, /* original: 2.182937, 0.733038 */ + { 0x1377, 0x06B3 }, /* original: 2.433119, 0.837758 */ + { 0x151E, 0x078A }, /* original: 2.640119, 0.942478 */ + { 0x1661, 0x0860 }, /* original: 2.797588, 1.047198 */ + { 0x1768, 0x0937 }, /* original: 2.925985, 1.151917 */ + { 0x183E, 0x0A0D }, /* original: 3.030629, 1.256637 */ + { 0x18C9, 0x0AE4 }, /* original: 3.098309, 1.361357 */ + { 0x1922, 0x0BBA }, /* original: 3.142011, 1.466077 */ + { 0x196E, 0x0C90 }, /* original: 3.178911, 1.570796 */ +}; + +static const struct cherry_calib_key util_partial_calib_qm35825_keys[] = { + /* PDOA LUT Configuration. */ + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut0.data", + util_calib_qm35825_pdoa_lut0_ch5), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut1.data", + util_calib_qm35825_pdoa_lut1_ch9), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut2.data", + util_calib_qm35825_pdoa_lut2_ch5), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut3.data", + util_calib_qm35825_pdoa_lut3_ch9), + CHERRY_CALIB_UINT8("ant_pair0.ch5.pdoa.lut_id", 0x0), + CHERRY_CALIB_UINT8("ant_pair0.ch9.pdoa.lut_id", 0x1), + CHERRY_CALIB_UINT8("ant_pair1.ch5.pdoa.lut_id", 0X2), + CHERRY_CALIB_UINT8("ant_pair1.ch9.pdoa.lut_id", 0x3), + CHERRY_CALIB_UINT8("ant_set0.tx_power_control", 0x01), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set3.tx_ant_paths", + util_calib_qm35825_ant_set3_tx_ant_paths), + CHERRY_CALIB_UINT8("ant_set3.nb_rx_ants", 1), + CHERRY_CALIB_BOOL("ant_set3.rx_ants_are_pairs", false), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set3.rx_ants", + util_calib_qm35825_ant_set3_rx_ants), + CHERRY_CALIB_UINT8("ant_set3.tx_power_control", 0x01), +}; + +static const struct cherry_calib_key util_calib_qm35825_keys[] = { + /* Global Calibration. */ + CHERRY_CALIB_UINT8("xtal_trim", 0x32), + + /* PDOA LUT Configuration. */ + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut0.data", + util_calib_qm35825_pdoa_lut0_ch5), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut1.data", + util_calib_qm35825_pdoa_lut1_ch9), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut2.data", + util_calib_qm35825_pdoa_lut2_ch5), + CHERRY_CALIB_NUMBER_ARRAY_2D("pdoa_lut3.data", + util_calib_qm35825_pdoa_lut3_ch9), + + /* ANT0 = TX_ANT1 */ + CHERRY_CALIB_UINT32("ant0.ch5.ref_frame0.tx_power_index", 0X51515151), + CHERRY_CALIB_UINT32("ant0.ch9.ref_frame0.tx_power_index", 0x4d4d4d4d), + CHERRY_CALIB_UINT32("ant0.ch5.ant_delay", 16387), + CHERRY_CALIB_UINT32("ant0.ch9.ant_delay", 16394), + CHERRY_CALIB_UINT8("ant0.transceiver", 0), + CHERRY_CALIB_UINT8("ant0.port", 1), + CHERRY_CALIB_INT8("ant0.ch5.pa_gain_offset", 0x5), + CHERRY_CALIB_INT8("ant0.ch9.pa_gain_offset", 0x8), + /* ANT1 = RXB_ANT2 */ + CHERRY_CALIB_UINT8("ant1.transceiver", 2), + CHERRY_CALIB_UINT8("ant1.port", 2), + CHERRY_CALIB_UINT8("ant1.lna", 1), + CHERRY_CALIB_UINT32("ant1.ch5.ant_delay", 16403), + CHERRY_CALIB_UINT32("ant1.ch9.ant_delay", 16407), + + /* ANT2 = RXA_ANT3 */ + CHERRY_CALIB_UINT8("ant2.transceiver", 1), + CHERRY_CALIB_UINT8("ant2.port", 3), + CHERRY_CALIB_UINT8("ant2.lna", 1), + CHERRY_CALIB_UINT32("ant2.ch5.ant_delay", 16392), + CHERRY_CALIB_UINT32("ant2.ch9.ant_delay", 16393), + + /* ANT3 = RXA_ANT4 */ + CHERRY_CALIB_UINT8("ant3.transceiver", 1), + CHERRY_CALIB_UINT8("ant3.port", 4), + CHERRY_CALIB_UINT8("ant3.lna", 1), + CHERRY_CALIB_UINT32("ant3.ch5.ant_delay", 16396), + CHERRY_CALIB_UINT32("ant3.ch9.ant_delay", 16395), + + /* ANT4 */ + CHERRY_CALIB_UINT8("ant4.transceiver", 0), + CHERRY_CALIB_UINT8("ant4.port", 2), + CHERRY_CALIB_INT8("ant4.ch5.pa_gain_offset", 0x7), + CHERRY_CALIB_UINT32("ant4.ch5.ref_frame0.tx_power_index", 0x4a4a4a4a), + CHERRY_CALIB_INT8("ant4.ch9.pa_gain_offset", 0x8), + CHERRY_CALIB_UINT32("ant4.ch9.ref_frame0.tx_power_index", 0x4a4a4a4a), + CHERRY_CALIB_UINT32("ant4.ch5.ant_delay", 16403), + CHERRY_CALIB_UINT32("ant4.ch9.ant_delay", 16407), + + /* Ant Pair 0 to measure Azimuth between ant1 and ant3 */ + CHERRY_CALIB_UINT8("ant_pair0.axis", 0), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_pair0.ant_paths", + util_calib_qm35825_ant_pair_0_ant_path), + CHERRY_CALIB_INT16("ant_pair0.ch5.pdoa.offset", 3893), + CHERRY_CALIB_INT16("ant_pair0.ch9.pdoa.offset", 1669), + CHERRY_CALIB_UINT8("ant_pair0.ch5.pdoa.lut_id", 0x0), + CHERRY_CALIB_UINT8("ant_pair0.ch9.pdoa.lut_id", 0x1), + + /* Ant Pair 1 to measure Elevation between ant1 and ant2 */ + CHERRY_CALIB_UINT8("ant_pair1.axis", 1), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_pair1.ant_paths", + util_calib_qm35825_ant_pair_1_ant_path), + CHERRY_CALIB_INT16("ant_pair1.ch5.pdoa.offset", 4476), + CHERRY_CALIB_INT16("ant_pair1.ch9.pdoa.offset", 1716), + CHERRY_CALIB_UINT8("ant_pair1.ch5.pdoa.lut_id", 0X2), + CHERRY_CALIB_UINT8("ant_pair1.ch9.pdoa.lut_id", 0x3), + + /* Ant Set0: all excepted radar. */ + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set0.tx_ant_paths", + util_calib_qm35825_ant_set0_tx_ant_paths), + CHERRY_CALIB_UINT8("ant_set0.nb_rx_ants", 2), + CHERRY_CALIB_BOOL("ant_set0.rx_ants_are_pairs", true), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set0.rx_ants", + util_calib_qm35825_ant_set0_rx_ants), + CHERRY_CALIB_UINT8("ant_set0.tx_power_control", 0x01), + + /* Ant Set3 : for radar. */ + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set3.tx_ant_paths", + util_calib_qm35825_ant_set3_tx_ant_paths), + CHERRY_CALIB_UINT8("ant_set3.nb_rx_ants", 1), + CHERRY_CALIB_BOOL("ant_set3.rx_ants_are_pairs", false), + CHERRY_CALIB_NUMBER_ARRAY_1D("ant_set3.rx_ants", + util_calib_qm35825_ant_set3_rx_ants), + CHERRY_CALIB_UINT8("ant_set3.tx_power_control", 0x01), + CHERRY_CALIB_BOOL("legacy_android_ccc", 0), +}; + +static const struct cherry_calib util_calib_qm35825 = { + .n_keys = sizeof(util_calib_qm35825_keys) / + sizeof(util_calib_qm35825_keys[0]), + .keys = util_calib_qm35825_keys, +}; + +static const struct cherry_calib util_partial_calib_qm35825 = { + .n_keys = sizeof(util_partial_calib_qm35825_keys) / + sizeof(util_partial_calib_qm35825_keys[0]), + .keys = util_partial_calib_qm35825_keys, +}; diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.cpp b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.cpp new file mode 100644 index 00000000..026739ed --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "uwb_impl.h" +#include "uwb_message.h" + +#include "aliro/utils.h" + +// UWB API +#include +#include + +// Calibration data +#include "calibration/qm35825_calib.h" + +#include +#include + +LOG_MODULE_REGISTER(uwb, CONFIG_NCS_DOOR_LOCK_APP_LOG_LEVEL); + +namespace { + +K_EVENT_DEFINE(sUwbEvents); + +constexpr uint32_t kUwbWaitCapabilitiesTimeoutMs{ 1000 }; + +/** + * @brief Helper enum class for UWB events. + */ +enum class UwbEvents : uint32_t { + Timeout = 0x00, + Error = 0x01, + DeviceCaps = 0x02, +}; + +/** + * @brief Converts aliro_uwb_err to AliroError. + * + * @param uwbErr The UWB error code to convert. + * + * @return The corresponding AliroError. + */ +constexpr AliroError ConvertUwbError(aliro_uwb_err uwbErr) +{ + switch (uwbErr) { + case ALIRO_UWB_ERR_NONE: + return ALIRO_NO_ERROR; + case ALIRO_UWB_ERR_INVALID_PARAMETER: + case ALIRO_UWB_ERR_MSG_MALFORMED: + return ALIRO_INVALID_ARGUMENT; + case ALIRO_UWB_ERR_UWBS_TIMEOUT: + return ALIRO_TIMEOUT; + case ALIRO_UWB_ERR_INTERNAL: + case ALIRO_UWB_ERR_SESSION_INIT: + return ALIRO_ERROR_INTERNAL; + case ALIRO_UWB_ERR_SESSION_ACTIVE: + case ALIRO_UWB_ERR_SESSION_CONFIG: + case ALIRO_UWB_ERR_MESSAGE_STATE: + case ALIRO_UWB_ERR_INVALID_STATE: + return ALIRO_INVALID_STATE; + default: + return ALIRO_ERROR_INTERNAL; + } +} + +#ifdef CONFIG_ALIRO_UWB_SESSION_LOGGING + +/** + * @brief Converts Cherry CCC session state to readable string. + * + * @param state The Cherry CCC session state value. + * + * @return String representation of the session state. + */ +constexpr const char *CherryCccSessionStateToString(enum cherry_ccc_session_state state) +{ + switch (state) { + case CHERRY_CCC_SESSION_STATE_INIT: + return "INIT"; + case CHERRY_CCC_SESSION_STATE_DEINIT: + return "DEINIT"; + case CHERRY_CCC_SESSION_STATE_ACTIVE: + return "ACTIVE"; + case CHERRY_CCC_SESSION_STATE_IDLE: + return "IDLE"; + default: + return "UNKNOWN"; + } +} + +/** + * @brief Converts Cherry CCC session reason code to readable string. + * + * @param reasonCode The Cherry CCC session reason code value. + * + * @return String representation of the reason code. + */ +constexpr const char *CherryCccReasonCodeToString(enum cherry_ccc_state_change_reason reasonCode) +{ + switch (reasonCode) { + case CHERRY_CCC_STATE_CHANGE_REASON_MGMT_CMD: + return "MGMT_CMD"; + case CHERRY_CCC_STATE_CHANGE_REASON_UNKNOWN: + return "UNKNOWN_REASON"; + case CHERRY_CCC_STATE_CHANGE_REASON_FORCE_STOPPED: + return "FORCE_STOPPED"; + default: + return "UNKNOWN"; + } +} + +#endif // CONFIG_ALIRO_UWB_SESSION_LOGGING + +} // namespace + +namespace Aliro::Uwb { + +void UwbCoreCallback(cherry_core_event *event, void *userData) +{ + VerifyOrExit(event && userData, LOG_ERR("Invalid event or user data.")); + + { + auto *uwbImpl = static_cast(userData); + + if (event->type == CHERRY_CORE_EVENT_TYPE_ERROR) { + k_event_set(&sUwbEvents, ToUnderlying(UwbEvents::Error)); + } else if (event->type == CHERRY_CORE_EVENT_TYPE_DEVICE_CAPS) { + auto *caps = event->data.device_caps; + if (caps->status_err == CHERRY_ERR_NONE && caps->ccc_capabilities) { + uwbImpl->mCoreEvent = event; + k_event_set(&sUwbEvents, ToUnderlying(UwbEvents::DeviceCaps)); + return; + } + } + } + +exit: + // Free allocated event. + cherry_core_event_free(event); +} + +void SessionHandlerCallback(aliro_uwb_session_event *event, void *user_data) +{ + auto sessionData = event->data; + switch (event->type) { + case ALIRO_UWB_SESSION_EVENT_TYPE_SESSION_STATUS: +#ifdef CONFIG_ALIRO_UWB_SESSION_LOGGING + + LOG_INF("Session status changed: %s (%d), reason: %s (%d)", + CherryCccSessionStateToString(sessionData.status->session_state), + sessionData.status->session_state, CherryCccReasonCodeToString(sessionData.status->reason_code), + sessionData.status->reason_code); + +#else // CONFIG_ALIRO_UWB_SESSION_LOGGING + + LOG_INF("Session status changed: %d, reason: %d", sessionData.status->session_state, + sessionData.status->reason_code); + +#endif // CONFIG_ALIRO_UWB_SESSION_LOGGING + break; + case ALIRO_UWB_SESSION_EVENT_TYPE_SESSION_ERROR: + LOG_INF("Session error: 0x%x", sessionData.error->status_err); + break; + case ALIRO_UWB_SESSION_EVENT_TYPE_SESSION_CONTROLLER_REPORT: { + const cherry_ccc_controller_session_report *results = sessionData.controller_report; + LOG_INF("Controller report %d measurements", results->n_measurements); + break; + } + case ALIRO_UWB_SESSION_EVENT_TYPE_SESSION_CONTROLEE_REPORT: { + const cherry_ccc_session_controlee_measurements *currentMeasurement = + sessionData.controlee_report->measurements; + while (currentMeasurement) { + if (!currentMeasurement->frame_status) { + LOG_INF("Controlee report distance %d [cm]", currentMeasurement->distance_cm); + } else { + LOG_INF("Controlee report error status: 0x%x on slot id: %d", + currentMeasurement->frame_status, currentMeasurement->slot_index); + } + currentMeasurement = currentMeasurement->next; + } + break; + } + default: + break; + } + + // Free the consumed event. + aliro_uwb_session_event_free(event); +} + +void TransmitBleMessage(aliro_uwb_message *message, aliro_uwb_session *sessionCtx, void *userData, bool timeout) +{ + auto *uwbImpl = static_cast(userData); + + uwbImpl->mCallbacks.mTransmitBleMessage(uwbImpl->mAliroSessionUserData, message->data, message->len); + + // Free the consumed message. + aliro_uwb_session_message_free(message); +} + +AliroError UltraWideBandImpl::_Init(const Callbacks &callbacks) +{ + cherry_err cErr{}; + uint32_t event{}; + + mCallbacks = callbacks; + + LOG_INF("Initializing UWB device..."); + + mCtx = cherry_create("qm35", &UwbCoreCallback, this); + VerifyOrReturnStatus(mCtx, ALIRO_UWB_INIT_FAILED, LOG_ERR("Failed to create Cherry context")); + + // Use full calibration data for the QM35825 device. + // This needs to be done only once during initialization, or after a power cycle. + const auto calibData = &util_calib_qm35825; + int err = cherry_set_calib(mCtx, calibData); + VerifyOrExit(err == CHERRY_ERR_NONE, LOG_ERR("Failed to set calibration data: %d", err)); + + // Initialize Cherry device capabilities. + cErr = cherry_get_device_capabilities(mCtx); + VerifyOrExit(cErr == CHERRY_ERR_NONE, LOG_ERR("Failed to get device capabilities: %s", cherry_err_str(cErr))); + + // Wait for device capabilities or error to be received. + event = k_event_wait(&sUwbEvents, 0xFFFF, false, K_MSEC(kUwbWaitCapabilitiesTimeoutMs)); + VerifyAndExit(event == ToUnderlying(UwbEvents::Timeout), LOG_ERR("Timeout, capabilities not received.")); + VerifyAndExit(event == ToUnderlying(UwbEvents::Error), + LOG_ERR("Error occurred while waiting for device capabilities.")); + VerifyOrExit(event == ToUnderlying(UwbEvents::DeviceCaps), + LOG_ERR("Unexpected event while waiting for device capabilities (%d).", event)); + + LOG_DBG("CCC capabilities available."); + mAliroCtx = aliro_uwb_adapter_create_reader(mCtx, mCoreEvent->data.device_caps, &mReaderConfig); + cherry_core_event_free(mCoreEvent); + mCoreEvent = nullptr; + + VerifyOrExit(mAliroCtx, LOG_ERR("Failed to create UWB adapter reader.")); + + LOG_INF("UWB device initialized successfully."); + + return ALIRO_NO_ERROR; + +exit: + _Deinit(); + + return ALIRO_UWB_INIT_FAILED; +} + +AliroError UltraWideBandImpl::_Deinit() +{ + _TerminateRangingSession(); + + if (mAliroCtx) { + aliro_uwb_adapter_destroy(mAliroCtx); + mAliroCtx = nullptr; + } + + // The Cherry context is destroyed last, after all other resources. + if (mCtx) { + cherry_destroy_sync(mCtx); + mCtx = nullptr; + } + + LOG_INF("UWB device deinitialized successfully."); + + return ALIRO_NO_ERROR; +} + +void UltraWideBandImpl::_BleTimeSync() const +{ + LOG_INF("Start Bluetooth LE and UWB time synchronization, procedure 0"); +} + +AliroError UltraWideBandImpl::_HandleBleMessage(const uint8_t *data, size_t length) +{ + VerifyOrReturnStatus(data && length > 0, ALIRO_INVALID_ARGUMENT, LOG_ERR("Invalid BLE message data.")); + + aliro_uwb_err err{}; + Message message(length); + VerifyOrExit(message, LOG_ERR("Memory allocation failed.")); + + memcpy(message->data, data, length); + message->len = length; + + err = aliro_uwb_session_message_handle(mAliroSessionCtx, message.get()); + VerifyOrReturnStatus(err == ALIRO_UWB_ERR_NONE, ConvertUwbError(err), + LOG_ERR("Cannot handle UWB session message 0x%x", err)); + + return ALIRO_NO_ERROR; + +exit: + _TerminateRangingSession(); + + return ALIRO_ERROR_INTERNAL; +} + +AliroError UltraWideBandImpl::_ConfigureRangingSession(SessionIdentifier sessionId, const uint8_t *ursk, size_t urskLen, + void *sessionUserData) +{ + VerifyOrReturnStatus(mAliroCtx, ALIRO_INVALID_STATE, LOG_ERR("UWB is not initialized.")); + VerifyOrReturnStatus(ursk && urskLen > 0, ALIRO_INVALID_ARGUMENT, LOG_ERR("Invalid URSK.")); + + aliro_uwb_err uwbErr{}; + + mAliroSessionUserData = sessionUserData; + mAliroSessionCtx = + aliro_uwb_session_create(mAliroCtx, sessionId, &SessionHandlerCallback, &TransmitBleMessage, this); + uwbErr = ALIRO_UWB_ERR_INTERNAL; + VerifyOrExit(mAliroSessionCtx, LOG_ERR("Failed to create UWB session.")); + + uwbErr = aliro_uwb_session_set_ursk(mAliroSessionCtx, ursk); + VerifyOrExit(uwbErr == ALIRO_UWB_ERR_NONE, LOG_ERR("Failed to set URSK in UWB session: 0x%x", uwbErr)); + + return ALIRO_NO_ERROR; + +exit: + _TerminateRangingSession(); + + return ConvertUwbError(uwbErr); +} + +AliroError UltraWideBandImpl::_InitiateRangingSession() +{ + VerifyOrReturnStatus(mAliroSessionCtx, ALIRO_INVALID_STATE, LOG_ERR("UWB session is not initialized.")); + aliro_uwb_err err = aliro_uwb_session_init_setup(mAliroSessionCtx); + VerifyOrReturnStatus(err == ALIRO_UWB_ERR_NONE, ConvertUwbError(err), + LOG_ERR("Failed to initialize UWB session setup: 0x%x", err)); + + return ALIRO_NO_ERROR; +} + +AliroError UltraWideBandImpl::_TerminateRangingSession() +{ + if (mAliroSessionCtx) { + aliro_uwb_session_destroy(mAliroSessionCtx); + mAliroSessionCtx = nullptr; + mAliroSessionUserData = nullptr; + } + + return ALIRO_NO_ERROR; +} + +AliroError UltraWideBandImpl::_SuspendRangingSession() +{ + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +AliroError UltraWideBandImpl::_ResumeRangingSession() +{ + return ALIRO_ERROR_NOT_IMPLEMENTED; +} + +} // namespace Aliro::Uwb diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.h b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.h new file mode 100644 index 00000000..35e71d78 --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_impl.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "aliro/errors.h" +#include "uwb/uwb.h" + +#include +#include +#include + +#include + +namespace Aliro::Uwb { + +/** + * @class UltraWideBandImpl + * @brief Implementation of the UltraWideBand interface. + * + * This class provides the implementation of the UltraWideBand interface, handling UWB operations + * such as initialization, ranging session management, and BLE message handling. + */ +class UltraWideBandImpl : public UltraWideBand { + using CoreEvent = cherry_core_event; + +public: + /** + * @brief Gets the instance of the UltraWideBand implementation. + * + * @return The instance of the UltraWideBand implementation. + */ + static UltraWideBandImpl &Instance() + { + static UltraWideBandImpl sInstance; + return sInstance; + } + + AliroError _Init(const Callbacks &callbacks); + AliroError _Deinit(); + void _BleTimeSync() const; + AliroError _HandleBleMessage(const uint8_t *data, size_t length); + AliroError _ConfigureRangingSession(SessionIdentifier sessionId, const uint8_t *ursk, size_t urskLen, + void *sessionUserData); + AliroError _InitiateRangingSession(); + AliroError _TerminateRangingSession(); + AliroError _SuspendRangingSession(); + AliroError _ResumeRangingSession(); + + // Delete copy and move constructors and assignment operators. + UltraWideBandImpl(const UltraWideBandImpl &) = delete; + UltraWideBandImpl &operator=(const UltraWideBandImpl &) = delete; + UltraWideBandImpl(UltraWideBandImpl &&) = delete; + UltraWideBandImpl &operator=(UltraWideBandImpl &&) = delete; + + friend void UwbCoreCallback(cherry_core_event *event, void *userData); + friend void TransmitBleMessage(aliro_uwb_message *message, aliro_uwb_session *sessionCtx, void *userData, + bool timeout); + +protected: + CoreEvent *mCoreEvent{}; + +private: + UltraWideBandImpl() = default; + ~UltraWideBandImpl() = default; + + Callbacks mCallbacks{}; + + cherry *mCtx{}; + + aliro_uwb_adapter *mAliroCtx{}; + aliro_uwb_session *mAliroSessionCtx{}; + + void *mAliroSessionUserData{}; + + aliro_uwb_adapter_reader_config mReaderConfig = { + .min_ran_multiplier = CONFIG_ALIRO_UWB_MIN_RAN_MULTIPLIER, + .preferred_hopping_config = { CONFIG_ALIRO_UWB_PREFERRED_HOPPING_CONFIG_VALUE, 0x00, 0x00, 0x00, 0x00 }, + .mac_mode = + (uint8_t)(CONFIG_ALIRO_UWB_MAC_MODE_OFFSET | (CONFIG_ALIRO_UWB_MAC_MODE_RANGING_ROUNDS << 6)), + }; +}; + +} // namespace Aliro::Uwb diff --git a/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_message.h b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_message.h new file mode 100644 index 00000000..4e5b842f --- /dev/null +++ b/app/src/platform/uwb_impl/uwb_qm35_impl/uwb_message.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include +#include + +namespace Aliro::Uwb { + +/** + * @brief Wrapper class for aliro_uwb_message. + * + * This class is used to wrap the aliro_uwb_message struct and provide a more convenient interface for + * interacting with the UWB message. + */ +struct Message { + /** + * @brief Constructor. + * Allocates memory for the message and initializes the message structure. + * + * @param dataLength The length of the data to allocate for the message. + */ + explicit Message(size_t dataLength) + : mMessage(static_cast(qmalloc(sizeof(aliro_uwb_message) + dataLength))) + { + } + + /** + * @brief Destructor. + * Releases the allocated memory for the message. + */ + ~Message() + { + if (mMessage) { + qfree(mMessage); + } + } + + /** + * @brief Get the message pointer. + * + * @return The message pointer. + */ + aliro_uwb_message *get() const { return mMessage; } + + /** + * @brief Get the message pointer. + * + * @return The message pointer. + */ + aliro_uwb_message *operator->() const { return mMessage; } + + /** + * @brief Check if the message is valid. + * + * @return True if the memory is allocated for the message, false otherwise. + */ + explicit operator bool() const { return mMessage != nullptr; } + + // Delete copy constructor and assignment. + Message(const Message &) = delete; + Message &operator=(const Message &) = delete; + + // Delete move constructor and assignment. + Message(const Message &&) = delete; + Message &operator=(const Message &&) = delete; + +private: + aliro_uwb_message *mMessage{ nullptr }; +}; + +} // namespace Aliro::Uwb diff --git a/app/sysbuild/ipc_radio/boards/nrf5340dk_nrf5340_cpunet.conf b/app/sysbuild/ipc_radio/boards/nrf5340dk_nrf5340_cpunet.conf index 89f20aff..423a4660 100644 --- a/app/sysbuild/ipc_radio/boards/nrf5340dk_nrf5340_cpunet.conf +++ b/app/sysbuild/ipc_radio/boards/nrf5340dk_nrf5340_cpunet.conf @@ -4,5 +4,8 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # +# Don't build Aliro stack for the network core +CONFIG_NCS_ALIRO=n + # Enable dynamic power control for the BT controller (on net core) CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/docs/building_and_running.rst b/docs/building_and_running.rst index 2eed0645..5fc4a913 100644 --- a/docs/building_and_running.rst +++ b/docs/building_and_running.rst @@ -1,68 +1,68 @@ -.. _building_and_running: - -Building and running -#################### - -In the :file:`door-lock-workspace`, the |APP_NAME| is placed in the :file:`ncs-door-lock-app` directory. -To build and run the application on one of the :ref:`supported development kits (DKs) `, complete the following steps: - -1. Connect the DK to your computer using the **DEBUGGER** port on the DK. - Set the **POWER** switch to **ON**. - -#. In the :file:`door-lock-workspace` directory, navigate to the :file:`ncs-door-lock-app` folder. - -#. Depending on the :ref:`NFC reader expansion board ` connected to the development kit, - build the application by running the corresponding command: - - +-----------------------+-----------------------+------------------------------------------------------------------------------------------------+ - | Build type | X-NUCLEO-NFC board | Command | - +=======================+=======================+================================================================================================+ - | Debug (default) | `X-NUCLEO-NFC09A1`_ | ``west build -p -b build_target app`` | - | +-----------------------+------------------------------------------------------------------------------------------------+ - | | `X-NUCLEO-NFC08A1`_ | ``west build -p -b build_target app -- -DCONFIG_ST25R3916B_DRV=y`` | - | +-----------------------+------------------------------------------------------------------------------------------------+ - | | `X-NUCLEO-NFC05A1`_ | ``west build -p -b build_target app -- -DCONFIG_ST25R3911_DRV=y`` | - +-----------------------+-----------------------+------------------------------------------------------------------------------------------------+ - - You can find the ``build_target`` of your device in the :ref:`hw_requirements_development_kit` section. - - For example, if you are using the nRF5340 DK and `X-NUCLEO-NFC09A1`_, the command is: - - .. code-block:: bash - - west build -p -b nrf5340dk/nrf5340/cpuapp app - - If you are using the nRF54L15 DK and `X-NUCLEO-NFC08A1`_, the command is: - - .. code-block:: bash - - west build -p -b nrf54l15dk/nrf54l15/cpuapp app -- -DCONFIG_ST25R3916B_DRV=y - - If you are using the nRF52840 DK and `X-NUCLEO-NFC05A1`_, the command is: - - .. code-block:: bash - - west build -p -b nrf52840dk/nrf52840 app -- -DCONFIG_ST25R3911_DRV=y - -#. Once you have built the application, run the following command to flash it: - - .. code-block:: bash - - west flash - -#. To verify if the application runs, connect to the DK with a terminal emulator that supports VT100/ANSI escape characters. - It is recommended to use the `Serial Terminal app`_. - See the `Testing and optimization`_ page in the |NCS| documentation for the required settings. - - .. note:: - |app_hwfc_enabled| - -#. Press the **RESET** button on the DK in order to refresh the application. - You should see the following logs: - - .. code-block:: console - - *** Booting My Application v0.1.0-f0e5cf444fb0 *** - *** Using nRF Connect SDK v2.9.0-7787b2649840 *** - *** Using Zephyr OS v3.7.99-1f8f3dc29142 *** - [00:00:00.009,613] door_lock_app: Starting nRF Door Lock Reference Application for the nRF Connect SDK +.. _building_and_running: + +Building and running +#################### + +In the :file:`door-lock-workspace`, the |APP_NAME| is placed in the :file:`ncs-door-lock-app` directory. +To build and run the application on one of the :ref:`supported development kits (DKs) `, complete the following steps: + +1. Connect the DK to your computer using the **DEBUGGER** port on the DK. + Set the **POWER** switch to **ON**. + +#. In the :file:`door-lock-workspace` directory, navigate to the :file:`ncs-door-lock-app` folder. + +#. Depending on the :ref:`NFC reader expansion board ` connected to the development kit, + build the application by running the corresponding command: + + +-----------------------+-----------------------+------------------------------------------------------------------------------------------------+ + | Build type | X-NUCLEO-NFC board | Command | + +=======================+=======================+================================================================================================+ + | Debug (default) | `X-NUCLEO-NFC09A1`_ | ``west build -p -b build_target app`` | + | +-----------------------+------------------------------------------------------------------------------------------------+ + | | `X-NUCLEO-NFC08A1`_ | ``west build -p -b build_target app -- -DCONFIG_ST25R3916B_DRV=y`` | + | +-----------------------+------------------------------------------------------------------------------------------------+ + | | `X-NUCLEO-NFC05A1`_ | ``west build -p -b build_target app -- -DCONFIG_ST25R3911_DRV=y`` | + +-----------------------+-----------------------+------------------------------------------------------------------------------------------------+ + + You can find the ``build_target`` of your device in the :ref:`hw_requirements_development_kit` section. + + For example, if you are using the nRF5340 DK and `X-NUCLEO-NFC09A1`_, the command is: + + .. code-block:: bash + + west build -p -b nrf5340dk/nrf5340/cpuapp app + + If you are using the nRF54L15 DK and `X-NUCLEO-NFC08A1`_, the command is: + + .. code-block:: bash + + west build -p -b nrf54l15dk/nrf54l15/cpuapp app -- -DCONFIG_ST25R3916B_DRV=y + + If you are using the nRF52840 DK and `X-NUCLEO-NFC05A1`_, the command is: + + .. code-block:: bash + + west build -p -b nrf52840dk/nrf52840 app -- -DCONFIG_ST25R3911_DRV=y + +#. Once you have built the application, run the following command to flash it: + + .. code-block:: bash + + west flash + +#. To verify if the application runs, connect to the DK with a terminal emulator that supports VT100/ANSI escape characters. + It is recommended to use the `Serial Terminal app`_. + See the `Testing and optimization`_ page in the |NCS| documentation for the required settings. + + .. note:: + |app_hwfc_enabled| + +#. Press the **RESET** button on the DK in order to refresh the application. + You should see the following logs: + + .. code-block:: console + + *** Booting My Application v0.1.0-f0e5cf444fb0 *** + *** Using nRF Connect SDK v2.9.0-7787b2649840 *** + *** Using Zephyr OS v3.7.99-1f8f3dc29142 *** + [00:00:00.009,613] door_lock_app: Starting nRF Door Lock Reference Application for the nRF Connect SDK diff --git a/docs/conf.py b/docs/conf.py index 48009ca9..a6e2897d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,62 +1,62 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = 'nRF Door Lock Reference Application' -copyright = '2025, Nordic Semiconductor' -author = 'Nordic Semiconductor' - -# The full version, including alpha/beta/rc tags -release = ' ' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx_tabs.tabs', - 'sphinx_copybutton' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_ncs_theme' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] (currently not in use) - -rst_epilog = """ -.. include:: /links.txt -.. include:: /shortcuts.txt -""" +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'nRF Door Lock Reference Application' +copyright = '2025, Nordic Semiconductor' +author = 'Nordic Semiconductor' + +# The full version, including alpha/beta/rc tags +release = ' ' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx_tabs.tabs', + 'sphinx_copybutton' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_ncs_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] (currently not in use) + +rst_epilog = """ +.. include:: /links.txt +.. include:: /shortcuts.txt +""" diff --git a/docs/door_lock_app_arch.rst b/docs/door_lock_app_arch.rst index 60c67f2d..35575a9f 100644 --- a/docs/door_lock_app_arch.rst +++ b/docs/door_lock_app_arch.rst @@ -1,34 +1,77 @@ -.. _addon_architecture: - -|APP_NAME| architecture -####################### - -The |APP_NAME| runs on the Nordic Semiconductor's :ref:`supported SoCs ` and utilizes the Aliro stack for access protocol and communication with user device over Near Field Communication (NFC) or Bluetooth® LE. -See the following diagram for an architecture overview: - -.. _arch_overview: - -.. figure:: /images/door_lock_app_arch.svg - :scale: 100% - :alt: nRF Door Lock Reference Application architecture. - - |APP_NAME| architecture overview. - -The |APP_NAME| is build using the :ref:`nRF Connect SDK `, which includes the Zephyr RTOS with all necessary modules. - -The Aliro stack implements the Access Protocol logic, Aliro-specific cryptographic primitives, and communication with the user device. -The interfaces layer is a bridge connecting the Aliro stack to the Zephyr OS modules through specific backends that implement the following components required by the Aliro: crypto, NFC and, ultra wideband (UWB). -This layer additionally allows to utilize other, custom backends for the crypto, NFC and UWB components by implementing the provided API. -By default, the |APP_NAME| uses backends shown in the :ref:`architecture overview `. -Both the Aliro stack and the interfaces layers are placed in the :file:`lib/aliro` directory. - -The RF Abstraction Layer (NFC RFAL) handles communication with the STMicroelectronics :ref:`NFC integrated circuit (IC) `. -This layer contains drivers, platform abstraction layer (PAL) and the NFC protocol stack, covering evrything from physical characteristic to the application layer. - -Communication with external IC's is done through the Serial Peripheral Interface (SPI) bus. - -The `Platform Security Architecture (PSA)`_ API provides a portable programming interface for cryptographic operations and key storage across a wide range of hardware. -It is designed to be user-friendly while still providing access to the low-level primitives essential for modern cryptography. - -.. note:: - In the current implementation, the Bluetooth® LE transport protocol and UWB proximity sensing are not supported. +.. _addon_architecture: + +|APP_NAME| architecture +####################### + +The |APP_NAME| runs on the Nordic Semiconductor's :ref:`supported SoCs ` and utilizes the Aliro stack for access protocol and communication with user device over Near Field Communication (NFC) or Bluetooth® LE. +See the following diagram for an architecture overview: + +.. _arch_overview: + +.. figure:: /images/door_lock_app_arch.svg + :scale: 100% + :alt: nRF Door Lock Reference Application architecture. + + |APP_NAME| architecture overview. + +The |APP_NAME| is build using the :ref:`nRF Connect SDK `, which includes the Zephyr RTOS with all necessary modules. + +The Aliro stack implements the Access Protocol logic, Aliro-specific cryptographic primitives, and communication with the user device. +The interfaces layer is a bridge connecting the Aliro stack to the Zephyr OS modules through specific backends that implement the following components required by the Aliro: crypto, NFC and, ultra wideband (UWB). +This layer additionally allows to utilize other, custom backends for the crypto, NFC and UWB components by implementing the provided API. +By default, the |APP_NAME| uses backends shown in the :ref:`architecture overview `. +The Aliro stack library files are placed in the :file:`lib/aliro` directory. + +The RF Abstraction Layer (NFC RFAL) handles communication with the STMicroelectronics :ref:`NFC integrated circuit (IC) `. +This layer contains drivers, platform abstraction layer (PAL) and the NFC protocol stack, covering evrything from physical characteristic to the application layer. + +Communication with external IC's is done through the Serial Peripheral Interface (SPI) bus. + +The `Platform Security Architecture (PSA)`_ API provides a portable programming interface for cryptographic operations and key storage across a wide range of hardware. +It is designed to be user-friendly while still providing access to the low-level primitives essential for modern cryptography. + +The `Bluetooth LE Controller`_ provides the necessary functionality for Bluetooth LE communication. +Bluetooth LE transport is supported on the `nRF5340 DK`_ platform and is configured to operate in the peripheral role, allowing the device to advertise its presence and accept connections from Bluetooth LE central devices. +The advertising payload is generated according to the Aliro specification, based on the ``reader group identifier`` and ``reader group sub-identifier``. +The payload updates automatically whenever these values change, ensuring that the device always advertises the latest group information. + +.. note:: + The device is preconfigured with default values for the ``reader group identifier`` and ``reader group sub-identifier``. + You can provide custom values using the ``dl install`` command through the console to override the defaults. + For more information about setting these values, see the :ref:`testing_environment_configuration` section. + +When a Bluetooth LE central device connects, the Aliro stack manages the Bluetooth LE session, handling connection events, security, and data exchange over a dedicated L2CAP channel with Aliro-specific GATT services. +Each session uses unique keys, which are destroyed after termination. +In case of NFC transport, only one session can be active at a time. +For Bluetooth LE transport, the maximum number of concurrent sessions is limited by the ``ALIRO_BLE_TP_MAX_SESSIONS`` Kconfig option and defaults to the value of ``BT_MAX_CONN``. + +To configure number of Bluetooth LE sessions, set the ``BT_MAX_CONN`` to maximum number of connections and optionally use the ``ALIRO_BLE_TP_MAX_SESSIONS`` to limit the number of sessions. + +.. note:: + Each session consumes resources, such as RAM and PSA key slots, therefore the maximum number of the active sessions should be determined empirically based on the requirements of the final application. + +You can configure Bluetooth LE transport parameters, such as buffer sizes, MTU, GATT database, L2CAP channels, TX power, and PHY through Kconfig (see :file:`lib/aliro/Kconfig.ble.defconfig`). + +.. note:: + In the current implementation, the UWB proximity sensing is not supported. + +.. _Access_decision_indicator: + +Access decision indicator +========================= + +When access is granted, a generic indicator is activated for a predefined period to visually confirm successful authentication. +By default, this indicator is a dedicated LED, but it can be adapted to other types of indicators such as a buzzer. + +You can set the duration of the indication in the :file:`app/src/platform/access_decision_indicator/Kconfig` file. +Use the ``RESET_ACCESS_DECISION_INDICATOR_STATE_DELAY_MS`` Kconfig option to specify the time in milliseconds. + +You can select the hardware resource used for this indication by going to the device tree source file and setting the ``access_decision_indicator`` property in the corresponding node. + +.. code-block:: dts + + access_decision_indicator: access_decision_indicator { + status = "okay"; + compatible = "access-decision-indicator"; + gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; + }; diff --git a/docs/hardware_requirements.rst b/docs/hardware_requirements.rst index db37c83f..627ca76f 100644 --- a/docs/hardware_requirements.rst +++ b/docs/hardware_requirements.rst @@ -1,119 +1,119 @@ -.. _hw_requirements: - -Hardware requirements -##################### - -To run and test the |APP_NAME|, you must have the required hardware. - -.. _hw_requirements_development_kit: - -Development kit -*************** - -The application supports the following development kit (DK): - -.. list-table:: - :header-rows: 1 - - * - Hardware platforms - - PCA - - Board name - - Build target - * - `nRF54L15 DK`_ - - PCA10156 - - `nrf54l15dk`_ - - ``nrf54l15dk/nrf54l15/cpuapp`` - * - `nRF5340 DK`_ - - PCA10095 - - `nrf5340dk`_ - - ``nrf5340dk/nrf5340/cpuapp`` - * - `nRF52840 DK`_ - - PCA10056 - - `nrf52840dk`_ - - ``nrf52840dk/nrf52840`` - -.. _hw_requirements_vddio_configuration: - -Configuring VDDIO voltage on the nRF54L15 DK -============================================ - -The nRF54L15 DK operates at default voltage level of 1.8V. -Some expansion boards, especially Arduino-style boards, require higher voltage to operate properly. -You can adjust the voltage for ports on the nRF54L15 DK up to 3.3V using the `Board Configurator app`_. -First, you must `install the Board Configurator app `_ and once completed `Update your DK's configuration `_. - -See the recommended configuration for VDD (nPM VOUT1): - -.. figure:: /images/VDDIO-configuration.png - :scale: 70% - :alt: VDD board configuration. - - VDD board configuration. - -.. _hw_requirements_nfc_reader: - -Near Field Communication reader -******************************* - -To start working with the application, you must have at least one Near Field Communication (NFC) reader. -The application supports the following NFC readers and their corresponding development expansion boards: - -+-------------------+---------------------------------+ -| NFC reader | NFC reader expansion board | -+===================+=================================+ -| `ST25R100`_ | `X-NUCLEO-NFC09A1`_ | -+-------------------+---------------------------------+ -| `ST25R3916B`_ | `X-NUCLEO-NFC08A1`_ | -+-------------------+---------------------------------+ -| `ST25R3911B`_ | `X-NUCLEO-NFC05A1`_ | -+-------------------+---------------------------------+ - -.. note:: - - The `X-NUCLEO-NFC09A1`_ board requires a minimum of 2.7V to operate. - Because of that, you must adjust the GPIO voltage for the `nRF54L15 DK`_ as outlined in the :ref:`hw_requirements_vddio_configuration` section. - -The `nRF54L15 DK`_ does not have Arduino-compatible header, therefore, you must connect your board using wires. -To connect the NFC reader expansion board to the `nRF54L15 DK`_, refer to the following pin mapping. -The pinout is applicable for each of the supported NFC reader expansion boards: - -+-------------------+-----------------------+ -| nRF54L15 DK | X-NUCLEO board | -+===================+=======================+ -| P1.13 | SCK MCU (D13) | -+-------------------+-----------------------+ -| P1.12 | MISO MCU (D12) | -+-------------------+-----------------------+ -| P1.11 | MOSI MCU (D11) | -+-------------------+-----------------------+ -| P2.08 | /SS MCU (D10) | -+-------------------+-----------------------+ -| P0.04 | IRQ MCU (A0) | -+-------------------+-----------------------+ -| VBUS | +5V | -+-------------------+-----------------------+ -| VDDIO | +3V3 | -+-------------------+-----------------------+ -| GND | GND | -+-------------------+-----------------------+ - -.. figure:: /images/nRF54L_X_NUCLEO_connection.png - :scale: 50% - :alt: Expansion board connection to the nRF54L15 DK. - - X-NUCLEO expansion board connection to the nRF54L15 DK. - -When using the `nRF5340 DK`_ or `nRF52840 DK`_, you can connect the NFC reader expansion board directly using the Arduino-compatible header available on the DK. - -.. _hw_requirements_test_harness: - -Test harness hardware -********************* - -For testing purposes, use the official `Aliro Certification Tool`_ as a test harness. -To set it up, you must first meet the `test harness hardware requirements`_. - -.. note:: - - In case you do not have an access to this repository, send a request to the help@csa-iot.org providing your GitHub username. - Be aware that you must first become a member of the `Connectivity Standards Alliance`_ (CSA). +.. _hw_requirements: + +Hardware requirements +##################### + +To run and test the |APP_NAME|, you must have the required hardware. + +.. _hw_requirements_development_kit: + +Development kit +*************** + +The application supports the following development kit (DK): + +.. list-table:: + :header-rows: 1 + + * - Hardware platforms + - PCA + - Board name + - Build target + * - `nRF54L15 DK`_ + - PCA10156 + - `nrf54l15dk`_ + - ``nrf54l15dk/nrf54l15/cpuapp`` + * - `nRF5340 DK`_ + - PCA10095 + - `nrf5340dk`_ + - ``nrf5340dk/nrf5340/cpuapp`` + * - `nRF52840 DK`_ + - PCA10056 + - `nrf52840dk`_ + - ``nrf52840dk/nrf52840`` + +.. _hw_requirements_vddio_configuration: + +Configuring VDDIO voltage on the nRF54L15 DK +============================================ + +The nRF54L15 DK operates at default voltage level of 1.8V. +Some expansion boards, especially Arduino-style boards, require higher voltage to operate properly. +You can adjust the voltage for ports on the nRF54L15 DK up to 3.3V using the `Board Configurator app`_. +First, you must `install the Board Configurator app `_ and once completed `Update your DK's configuration `_. + +See the recommended configuration for VDD (nPM VOUT1): + +.. figure:: /images/VDDIO-configuration.png + :scale: 70% + :alt: VDD board configuration. + + VDD board configuration. + +.. _hw_requirements_nfc_reader: + +Near Field Communication reader +******************************* + +To start working with the application, you must have at least one Near Field Communication (NFC) reader. +The application supports the following NFC readers and their corresponding development expansion boards: + ++-------------------+---------------------------------+ +| NFC reader | NFC reader expansion board | ++===================+=================================+ +| `ST25R100`_ | `X-NUCLEO-NFC09A1`_ | ++-------------------+---------------------------------+ +| `ST25R3916B`_ | `X-NUCLEO-NFC08A1`_ | ++-------------------+---------------------------------+ +| `ST25R3911B`_ | `X-NUCLEO-NFC05A1`_ | ++-------------------+---------------------------------+ + +.. note:: + + The `X-NUCLEO-NFC09A1`_ board requires a minimum of 2.7V to operate. + Because of that, you must adjust the GPIO voltage for the `nRF54L15 DK`_ as outlined in the :ref:`hw_requirements_vddio_configuration` section. + +The `nRF54L15 DK`_ does not have Arduino-compatible header, therefore, you must connect your board using wires. +To connect the NFC reader expansion board to the `nRF54L15 DK`_, refer to the following pin mapping. +The pinout is applicable for each of the supported NFC reader expansion boards: + ++-------------------+-----------------------+ +| nRF54L15 DK | X-NUCLEO board | ++===================+=======================+ +| P1.13 | SCK MCU (D13) | ++-------------------+-----------------------+ +| P1.12 | MISO MCU (D12) | ++-------------------+-----------------------+ +| P1.11 | MOSI MCU (D11) | ++-------------------+-----------------------+ +| P2.08 | /SS MCU (D10) | ++-------------------+-----------------------+ +| P0.04 | IRQ MCU (A0) | ++-------------------+-----------------------+ +| VBUS | +5V | ++-------------------+-----------------------+ +| VDDIO | +3V3 | ++-------------------+-----------------------+ +| GND | GND | ++-------------------+-----------------------+ + +.. figure:: /images/nRF54L_X_NUCLEO_connection.png + :scale: 50% + :alt: Expansion board connection to the nRF54L15 DK. + + X-NUCLEO expansion board connection to the nRF54L15 DK. + +When using the `nRF5340 DK`_ or `nRF52840 DK`_, you can connect the NFC reader expansion board directly using the Arduino-compatible header available on the DK. + +.. _hw_requirements_test_harness: + +Test harness hardware +********************* + +For testing purposes, use the official `Aliro Certification Tool`_ as a test harness. +To set it up, you must first meet the `test harness hardware requirements`_. + +.. note:: + + In case you do not have an access to this repository, send a request to the help@csa-iot.org providing your GitHub username. + Be aware that you must first become a member of the `Connectivity Standards Alliance`_ (CSA). diff --git a/docs/images/door_lock_app_arch.svg b/docs/images/door_lock_app_arch.svg index 915f1a19..340d9e81 100644 --- a/docs/images/door_lock_app_arch.svg +++ b/docs/images/door_lock_app_arch.svg @@ -1,513 +1,513 @@ - - - - - - - - - - - - - - - - - Infocenter diagram - - - - - - - Sheet.1 - Max 750 px - - Sheet.2 - - - - Sheet.3 - - Sheet.4 - - - - Sheet.5 - - - - - - Sheet.6 - - - - - - Max 750 px - - - - Sheet.7 - Max 700 px - - Sheet.8 - - - - Sheet.9 - - Sheet.10 - - - - Sheet.11 - - - - - - Sheet.12 - - - - - - Max 700 px - - - Sheet.13 - - Sheet.14 - - - - Sheet.15 - - Sheet.16 - - - - Sheet.17 - - - - - - - Sheet.18 - - Sheet.19 - - - - Sheet.20 - - Sheet.21 - - - - Sheet.22 - - - - - - - Nordic Blue - - - - Sheet.24 - nRF54L15 SoC - - - - - Supported nRF SoCs - - Nordic Blueslate - Door lock application - - - - - nRF Door Lock Reference Application - - Nordic Lake - Aliro stack - - - - - Aliro stack - - Nordic Sky - Access protocol - - - - - Access protocol - - Nordic Sky.15 - Trusted framework - - - - - Trusted framework - - Nordic Sky.16 - Transport protocol - - - - - Transport protocol - - Nordic Grass - - - - Sheet.31 - Interfaces - - - - - Interfaces - - Nordic Dark Grey - NFC interface - - - - - NFC interface - - Nordic Dark Grey.25 - Crypto interface - - - - - Crypto interface - - Nordic Light Grey - UWB interface - - - - - UWB interface - - Nordic Light Grey.30 - BLE interface - - - - - BLE interface - - Nordic Sun - NFC RFAL - - - - - NFC RFAL - - Nordic Fall - PSA API - - - - - PSA API - - Nordic Light Grey.34 - UWB driver - - - - - UWB driver - - Nordic Middle Grey - - - - Sheet.40 - Zephyr OS - - - - - Zephyr OS - - Nordic Light Grey.38 - SPI - - - - - SPI - - Nordic Light Grey.39 - GPIO - - - - - GPIO - - Nordic Light Grey.40 - BLE - - - - - BLE - - Nordic Light Grey.41 - Crypto - - - - - Crypto - - Nordic Light Grey.42 - Timers - - - - - Timers - - Nordic Light Grey.43 - Power Management - - - - - Power Management - - Nordic Light Grey.44 - Memory - - - - - Memory - - Nordic Light Grey.45 - Threading - - - - - Threading - - Nordic Light Grey.46 - - - - - - - - - - Nordic Sun.47 - ST25R - - - - - ST25R - - Nordic Light Grey.1000 - Currently not available - - - - - Currently not available - - Nordic Sun.1001 - External module - - - - - External module - - Nordic Light Grey.1002 - Separate repository - - - - - Separate repository - - Nordic Light Grey.1005 - UWB module - - - - - UWB module - - Block Double Arrow.1006 - - - - - - - Sheet.56 - SPI - - - - - SPI - - Sheet.57 - SPI - - - - - SPI - - - - - - - Line Double Arrow.1010 - - Sheet.59 - - - - Sheet.60 - - - - Sheet.61 - - - - Sheet.62 - - Sheet.63 - - - - Sheet.64 - - Sheet.65 - - - - Sheet.66 - - - - - - - - - - - - - Line Double Arrow.1011 - - Sheet.68 - - - - Sheet.69 - - - - Sheet.70 - - - - Sheet.71 - - Sheet.72 - - - - Sheet.73 - - Sheet.74 - - - - Sheet.75 - - - - - - - - + + + + + + + + + + + + + + + + + Infocenter diagram + + + + + + + Sheet.1 + Max 750 px + + Sheet.2 + + + + Sheet.3 + + Sheet.4 + + + + Sheet.5 + + + + + + Sheet.6 + + + + + + Max 750 px + + + + Sheet.7 + Max 700 px + + Sheet.8 + + + + Sheet.9 + + Sheet.10 + + + + Sheet.11 + + + + + + Sheet.12 + + + + + + Max 700 px + + + Sheet.13 + + Sheet.14 + + + + Sheet.15 + + Sheet.16 + + + + Sheet.17 + + + + + + + Sheet.18 + + Sheet.19 + + + + Sheet.20 + + Sheet.21 + + + + Sheet.22 + + + + + + + Nordic Blue + + + + Sheet.24 + nRF54L15 SoC + + + + + Supported nRF SoCs + + Nordic Blueslate + Door lock application + + + + + nRF Door Lock Reference Application + + Nordic Lake + Aliro stack + + + + + Aliro stack + + Nordic Sky + Access protocol + + + + + Access protocol + + Nordic Sky.15 + Trusted framework + + + + + Trusted framework + + Nordic Sky.16 + Transport protocol + + + + + Transport protocol + + Nordic Grass + + + + Sheet.31 + Interfaces + + + + + Interfaces + + Nordic Dark Grey + NFC interface + + + + + NFC interface + + Nordic Dark Grey.25 + Crypto interface + + + + + Crypto interface + + Nordic Light Grey + UWB interface + + + + + UWB interface + + Nordic Light Grey.30 + BLE interface + + + + + BLE interface + + Nordic Sun + NFC RFAL + + + + + NFC RFAL + + Nordic Fall + PSA API + + + + + PSA API + + Nordic Light Grey.34 + UWB driver + + + + + UWB driver + + Nordic Middle Grey + + + + Sheet.40 + Zephyr OS + + + + + Zephyr OS + + Nordic Light Grey.38 + SPI + + + + + SPI + + Nordic Light Grey.39 + GPIO + + + + + GPIO + + Nordic Light Grey.40 + BLE + + + + + BLE + + Nordic Light Grey.41 + Crypto + + + + + Crypto + + Nordic Light Grey.42 + Timers + + + + + Timers + + Nordic Light Grey.43 + Power Management + + + + + Power Management + + Nordic Light Grey.44 + Memory + + + + + Memory + + Nordic Light Grey.45 + Threading + + + + + Threading + + Nordic Light Grey.46 + - + + + + + - + + Nordic Sun.47 + ST25R + + + + + ST25R + + Nordic Light Grey.1000 + Currently not available + + + + + Currently not available + + Nordic Sun.1001 + External module + + + + + External module + + Nordic Light Grey.1002 + Separate repository + + + + + Separate repository + + Nordic Light Grey.1005 + UWB module + + + + + UWB module + + Block Double Arrow.1006 + + + + + + + Sheet.56 + SPI + + + + + SPI + + Sheet.57 + SPI + + + + + SPI + + + + + + + Line Double Arrow.1010 + + Sheet.59 + + + + Sheet.60 + + + + Sheet.61 + + + + Sheet.62 + + Sheet.63 + + + + Sheet.64 + + Sheet.65 + + + + Sheet.66 + + + + + + + + + + + + + Line Double Arrow.1011 + + Sheet.68 + + + + Sheet.69 + + + + Sheet.70 + + + + Sheet.71 + + Sheet.72 + + + + Sheet.73 + + Sheet.74 + + + + Sheet.75 + + + + + + + + diff --git a/docs/images/rd_ble_stdtxn_1_0_test_selection.png b/docs/images/rd_ble_stdtxn_1_0_test_selection.png new file mode 100644 index 00000000..4101f4fd Binary files /dev/null and b/docs/images/rd_ble_stdtxn_1_0_test_selection.png differ diff --git a/docs/images/rd_ble_stdtxn_2_0_test_selection.png b/docs/images/rd_ble_stdtxn_2_0_test_selection.png new file mode 100644 index 00000000..07a14b31 Binary files /dev/null and b/docs/images/rd_ble_stdtxn_2_0_test_selection.png differ diff --git a/docs/images/test_results_rd_ble_stdtxn_1_0.png b/docs/images/test_results_rd_ble_stdtxn_1_0.png new file mode 100644 index 00000000..9108b2ab Binary files /dev/null and b/docs/images/test_results_rd_ble_stdtxn_1_0.png differ diff --git a/docs/images/test_results_rd_ble_stdtxn_2_0.png b/docs/images/test_results_rd_ble_stdtxn_2_0.png new file mode 100644 index 00000000..d5fe664d Binary files /dev/null and b/docs/images/test_results_rd_ble_stdtxn_2_0.png differ diff --git a/docs/index.rst b/docs/index.rst index 4b5dc43b..60ce2b93 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,34 +1,34 @@ -.. _index: - -|app_name| for the |NCS| -######################## - -.. note:: - |EXPERIMENTAL_NOTE| - -Aliro is the new industry-standard access control and communication protocol, offering a secure, convenient, and consistent experience for users using smartphones, wearables, or other smart digital devices to unlock doors and openings. - -Aliro features several key features that distinguish it from existing access protocols: - -* Interoperability and compatibility - Ensures seamless interaction between access readers, such as electronic locks and access control readers, and user devices like smartphone and wearables. - The standardized solution allows manufacturer-independent devices and readers to work together without compromising security. -* Flexibility - Does not dictate how your digital door lock or access control reader connects to the rest of your ecosystem. -* Protocol support - Supports various transport protocols, including mandatory Near Field Communication (NFC), Bluetooth® LE or Bluetooth LE with Ultra-Wideband (UWB). - - .. note:: - In the current implementation, the Aliro stack supports only the mandatory NFC protocol. - -.. toctree:: - :maxdepth: 1 - :glob: - :caption: Subpages: - - door_lock_app_arch.rst - other_addons.rst - hardware_requirements.rst - software_requirements.rst - building_and_running.rst - testing.rst - troubleshooting.rst - release_notes.rst - known_issues.rst +.. _index: + +|app_name| for the |NCS| +######################## + +.. note:: + |EXPERIMENTAL_NOTE| + +Aliro is the new industry-standard access control and communication protocol, offering a secure, convenient, and consistent experience for users using smartphones, wearables, or other smart digital devices to unlock doors and openings. + +Aliro features several key features that distinguish it from existing access protocols: + +* Interoperability and compatibility - Ensures seamless interaction between access readers, such as electronic locks and access control readers, and user devices like smartphone and wearables. + The standardized solution allows manufacturer-independent devices and readers to work together without compromising security. +* Flexibility - Does not dictate how your digital door lock or access control reader connects to the rest of your ecosystem. +* Protocol support - Supports various transport protocols, including mandatory Near Field Communication (NFC), Bluetooth® LE or Bluetooth LE with Ultra-Wideband (UWB). + + .. note:: + In the current implementation, the Aliro stack supports only the mandatory NFC protocol. + +.. toctree:: + :maxdepth: 1 + :glob: + :caption: Subpages: + + door_lock_app_arch.rst + other_addons.rst + hardware_requirements.rst + software_requirements.rst + building_and_running.rst + testing.rst + troubleshooting.rst + release_notes.rst + known_issues.rst diff --git a/docs/known_issues.rst b/docs/known_issues.rst index e78ca237..6823f5e1 100644 --- a/docs/known_issues.rst +++ b/docs/known_issues.rst @@ -1,65 +1,42 @@ -.. _known_issues: - -Known issues -############ - -.. contents:: - :local: - :depth: 2 - -Known issues listed on this page are valid for the current state of development. -Refer to the following sections for more information on specific items. - -A known issue can list one or both of the following entries: - -* **Affected platforms:** - - If a known issue does not have any specific platforms listed, it is valid for all hardware platforms. - -* **Workaround:** - - Some known issues have a workaround. - Sometimes, they are discovered later and added over time. - -The |APP_NAME| -************** - -`v0.2.0` - -AL-239: Occasional timeout in the reader when executing the RD-NFC-STDTXN-2.0 test from the Test Harness - When executing the RD-NFC-STDTXN-2.0 test case, the reader might report an RX timeout error code in the serial console. - For more details, see `Test Harness issue #191`_. - -`v0.2.0` - -AL-282: Undefined access decision when executing the RD-NFC-STDTXN-2.0 Test Harness case in a loop - When executing the RD-NFC-STDTXN-2.0 test case multiple times in a row (with valid credentials provisioned), the reader might not report the access decision at all. - As a result, neither ``ACCESS GRANTED`` nor ``ACCESS DENIED`` log is displayed in the serial output of the reader under test. - -`v0.1.0` `v0.2.0` - -AL-148: The RD-NFC-STDTXN-1.0 test case fails when the NFC module ST X-NUCLEO-NFC05A1 is in use - Testing RD-NFC-STDTXN-1.0 with the NFC module NFC05A1 results in failure. - The issue arises from an error indicated by the test harness, which detects the presence of an invalid TLV tag in the payload received from the Device Under Test (DUT). - - **Workaround:** Switch to X-NUCLEO-NFC09A1, a newer, recommended revision of the NFC ST module. - Attach the X-NUCLEO-NFC09A1 shield to the supported Nordic development kit, rebuild the firmware with the ``CONFIG_ST25R200_DRV`` Kconfig option enabled, and reflash the DK. - -`v0.1.0` `v0.2.0` - -AL-158: Access control is insufficient due to relying only on signature verification - The reader device does not have the capability to configure additional access rules. - Access Manager is not implemented. - -`v0.1.0` `v0.2.0` - -AL-159: Cannot provision multiple user devices - The system allows provisioning of only one user device to the reader device. - -`v0.1.0` `v0.2.0` - -AL-161: The RD-NFC-STDTXN-2.0 [X-NUCLEO-NFC08A1] test exhibits a delay in the transaction initiation step - During the RD-NFC-STDTXN-2.0 test execution, there is a noticeable delay of a few seconds after the transaction initiation step. - - **Workaround:** Switch to X-NUCLEO-NFC09A1, a newer, recommended revision of the NFC ST module. - Attach the X-NUCLEO-NFC09A1 shield to the supported Nordic development kit, rebuild the firmware with the ``CONFIG_ST25R200_DRV`` Kconfig option enabled, and reflash the DK. +.. _known_issues: + +Known issues +############ + +.. contents:: + :local: + :depth: 2 + +Known issues listed on this page are valid for the current state of development. +Refer to the following sections for more information on specific items. + +A known issue can list one or both of the following entries: + +* **Affected platforms:** + + If a known issue does not have any specific platforms listed, it is valid for all hardware platforms. + +* **Workaround:** + + Some known issues have a workaround. + Sometimes, they are discovered later and added over time. + +The |APP_NAME| v0.1.0 +********************* + +AL-148: The RD-NFC-STDTXN-1.0 test case fails when the NFC module ST X-NUCLEO-NFC05A1 is in use + Testing RD-NFC-STDTXN-1.0 with the NFC module NFC05A1 results in failure. + The issue arises from an error indicated by the test harness, which detects the presence of an invalid TLV tag in the payload received from the Device Under Test (DUT). + + **Workaround:** Switch to X-NUCLEO-NFC09A1, a newer, recommended revision of the NFC ST module. + Attach X-NUCLEO-NFC09A1 shield to the nRF54L15 DK, rebuild the firmware with the ``CONFIG_ST25R200_DRV`` Kconfig option enabled, and re-flash the nRF54L15 DK. + +AL-158: Access control is insufficient due to relying only on signature verification + The reader device does not have the capability to configure additional access rules. + Access Manager is not implemented. + +AL-159: Cannot provision multiple user devices + The system allows provisioning of only one user device to the reader device. + +AL-161: The RD-NFC-STDTXN-2.0 [X-NUCLEO-NFC08A1] test exhibits a delay in the transaction initiation step + During the RD-NFC-STDTXN-2.0 test execution, there is a noticeable delay of a few seconds after the transaction initiation step. diff --git a/docs/links.txt b/docs/links.txt index f3ce75db..37b77d8e 100644 --- a/docs/links.txt +++ b/docs/links.txt @@ -1,62 +1,62 @@ -.. ### This page lists links used in the NCS door lock reference applications docs. - - -.. ### Source: github.com - -.. _`ncs-door-lock-app`: https://github.com/nrfconnect/ncs-door-lock-app -.. _`Aliro Certification Tool`: https://github.com/csa-access-control/aliro-certification-tool -.. _`test harness hardware requirements`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#requirements -.. _`test harness usage instructions`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#usage-instructions -.. _`running test scripts`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#c---creating-a-test-run-running-test-scripts -.. _`Setting up the command-line build environment`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html#set_up_the_command-line_build_environment -.. _`Zephyr CMake package`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/build/zephyr_cmake_package.html#cmake-pkg -.. _`Test Harness issue #191`: https://github.com/csa-access-control/aliro-certification-tool/issues/191 - - -.. ### Source: docs.nordicsemi.com - Requires manual update to align it with the NCS version. - -.. ### ========================= nRF Connect SDK - v2.9.0 ========================= - -.. _`Installing the nRF Connect SDK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html -.. _`Get the nRF Connect SDK code`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html#get_the_nrf_connect_sdk_code - -.. _`Platform Security Architecture (PSA)`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/libraries/security/nrf_security/doc/configuration.html#psa_crypto_support - -.. _`West`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/dev_model_and_contributions/code_base.html#ncs-west-intro - -.. _`nRF54L15 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf54l15dk/doc/index.html#nrf54l15dk-nrf54l15 -.. _`nrf54l15dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf54l/index.html - -.. _`nRF5340 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf5340dk/doc/index.html -.. _`nrf5340dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf53/index.html - -.. _`nRF52840 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf52840dk/doc/index.html -.. _`nrf52840dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf52/index.html - -.. _`Testing and optimization`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/test_and_optimize.html -.. _`Software maturity`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/releases_and_maturity/software_maturity.html - -.. #### Development-Tools - -.. _`Board Configurator app`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/index.html -.. _`Installing Board Configurator app`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/installing.html -.. _`Updating the board configuration`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/updating.html -.. _`Serial Terminal app`: https://docs.nordicsemi.com/bundle/nrf-connect-serial-terminal/page/index.html - -.. ### External: boards and IC documentation links - -.. _`X-NUCLEO-NFC09A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc09a1.html -.. _`ST25R100`: https://www.st.com/en/nfc/st25r100.html -.. _`X-NUCLEO-NFC08A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc08a1.html -.. _`ST25R3916B`: https://www.st.com/en/nfc/st25r3916b.html -.. _`X-NUCLEO-NFC05A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc05a1.html -.. _`ST25R3911B`: https://www.st.com/en/nfc/st25r3911b.html - -.. _`OM27160B1EVK`: https://www.nxp.com/part/OM27160B1EVK -.. _`OM27160A1EVK`: https://www.nxp.com/part/OM27160A1EVK -.. _`LBUA0VG2BP-EVK-P`: https://www.murata.com/en-eu/products/connectivitymodule/ultra-wide-band/nxp/type2bp - -.. ### External links - -.. _`Connectivity Standards Alliance`: https://csa-iot.org/ +.. ### This page lists links used in the NCS door lock reference applications docs. + + +.. ### Source: github.com + +.. _`ncs-door-lock-app`: https://github.com/nrfconnect/ncs-door-lock-app +.. _`Aliro Certification Tool`: https://github.com/csa-access-control/aliro-certification-tool +.. _`test harness hardware requirements`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#requirements +.. _`test harness usage instructions`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#usage-instructions +.. _`running test scripts`: https://github.com/csa-access-control/aliro-certification-tool?tab=readme-ov-file#c---creating-a-test-run-running-test-scripts +.. _`Setting up the command-line build environment`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html#set_up_the_command-line_build_environment +.. _`Zephyr CMake package`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/build/zephyr_cmake_package.html#cmake-pkg + +.. ### Source: docs.nordicsemi.com + Requires manual update to align it with the NCS version. + +.. ### ========================= nRF Connect SDK - v2.9.0 ========================= + +.. _`Installing the nRF Connect SDK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html +.. _`Get the nRF Connect SDK code`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/installation/install_ncs.html#get_the_nrf_connect_sdk_code + +.. _`Platform Security Architecture (PSA)`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/libraries/security/nrf_security/doc/configuration.html#psa_crypto_support + +.. _`Bluetooth LE Controller` : https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/protocols/bt/bt_stack_arch.html + +.. _`West`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/dev_model_and_contributions/code_base.html#ncs-west-intro + +.. _`nRF54L15 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf54l15dk/doc/index.html#nrf54l15dk-nrf54l15 +.. _`nrf54l15dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf54l/index.html + +.. _`nRF5340 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf5340dk/doc/index.html +.. _`nrf5340dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf53/index.html + +.. _`nRF52840 DK`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/zephyr/boards/nordic/nrf52840dk/doc/index.html +.. _`nrf52840dk`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/device_guides/nrf52/index.html + +.. _`Testing and optimization`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/test_and_optimize.html +.. _`Software maturity`: https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/releases_and_maturity/software_maturity.html + +.. #### Development-Tools + +.. _`Board Configurator app`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/index.html +.. _`Installing Board Configurator app`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/installing.html +.. _`Updating the board configuration`: https://docs.nordicsemi.com/bundle/nrf-connect-board-configurator/page/updating.html +.. _`Serial Terminal app`: https://docs.nordicsemi.com/bundle/nrf-connect-serial-terminal/page/index.html + +.. ### External: boards and IC documentation links + +.. _`X-NUCLEO-NFC09A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc09a1.html +.. _`ST25R100`: https://www.st.com/en/nfc/st25r100.html +.. _`X-NUCLEO-NFC08A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc08a1.html +.. _`ST25R3916B`: https://www.st.com/en/nfc/st25r3916b.html +.. _`X-NUCLEO-NFC05A1`: https://www.st.com/en/ecosystems/x-nucleo-nfc05a1.html +.. _`ST25R3911B`: https://www.st.com/en/nfc/st25r3911b.html + +.. _`OM27160B1EVK`: https://www.nxp.com/part/OM27160B1EVK +.. _`OM27160A1EVK`: https://www.nxp.com/part/OM27160A1EVK +.. _`LBUA0VG2BP-EVK-P`: https://www.murata.com/en-eu/products/connectivitymodule/ultra-wide-band/nxp/type2bp + +.. ### External links + +.. _`Connectivity Standards Alliance`: https://csa-iot.org/ diff --git a/docs/other_addons.rst b/docs/other_addons.rst index 48b29921..7d3f655c 100644 --- a/docs/other_addons.rst +++ b/docs/other_addons.rst @@ -1,29 +1,29 @@ -.. _other_addons: - -Software components deployment -############################## - -This page details the deployment of the |APP_NAME| and its dependencies. - -Overview -******** - -The |APP_NAME| functions as the nRF Connect top-level add-on. -The top-level add-on leverages other add-ons, which are typically configured as Zephyr modules, to enhance functionality. -All add-ons provide additional software deployed outside of the |NCS|. -Each of them operates with its own release cycle but is designed to work with specific versions of the |NCS|. -Dependencies between these modules and their specific revisions are managed through the :file:`west.yaml` file using `west, a Zephyr OS meta tool `_. - -Aliro add-ons -************* - -The |APP_NAME| includes a binary library of the Aliro stack. -The binary is built from the Aliro add-on, which is a private module with restricted access. - -See the following diagram for deployment of software components used by the |APP_NAME|: - -.. figure:: /images/aliro-add-ons.svg - :scale: 100% - :alt: Aliro add-ons deployment - - Aliro add-ons deployment +.. _other_addons: + +Software components deployment +############################## + +This page details the deployment of the |APP_NAME| and its dependencies. + +Overview +******** + +The |APP_NAME| functions as the nRF Connect top-level add-on. +The top-level add-on leverages other add-ons, which are typically configured as Zephyr modules, to enhance functionality. +All add-ons provide additional software deployed outside of the |NCS|. +Each of them operates with its own release cycle but is designed to work with specific versions of the |NCS|. +Dependencies between these modules and their specific revisions are managed through the :file:`west.yaml` file using `west, a Zephyr OS meta tool `_. + +Aliro add-ons +************* + +The |APP_NAME| includes a binary library of the Aliro stack. +The binary is built from the Aliro add-on, which is a private module with restricted access. + +See the following diagram for deployment of software components used by the |APP_NAME|: + +.. figure:: /images/aliro-add-ons.svg + :scale: 100% + :alt: Aliro add-ons deployment + + Aliro add-ons deployment diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 8ce6e494..0cedce62 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -1,58 +1,53 @@ -.. _release_notes: - -Release notes -############# - -This page outlines changes introduced with each release of the |APP_NAME|. - -v0.2.0 -****** - -.. note:: - |EXPERIMENTAL_NOTE| - -Changelog -========= - -The following updates were introduced in this release. - -* Added: - - * Experimental support for the following development platforms: - - * `nRF52840 DK`_ - * `nRF5340 DK`_ - - * A platform logger implementation. - * Integrated a new NFC transport interface. - * Integrated simplified Aliro stack API. - -* Changed: - - * Improved the implementation the following components in RFAL platform abstraction layer: - - * Timers - * Semaphores - * Threading - -v0.1.0 -****** - -.. note:: - |EXPERIMENTAL_NOTE| - -Changelog -========= - -The following updates were introduced in this release. - -* Added experimental support for the following: - - * Access Protocol (the expedited standard transaction only). - * Transport Protocol over Near Field Communication (NFC) transport. - * Trusted Framework implementation with the |NCS| PSA API as a cryptography backend. - * The nRF54L15 hardware platform. - * STM NFC Reader transceivers: ST25R200, ST25R3911, ST25R3916, ST25R3916B, ST25R200. - * ST Microelectronics R/F Abstraction Layer driver with Zephyr Platform Abstraction Layer integration. - * |APP_NAME| that leverages Aliro stack and supports CLI-based provisioning of the Access Credential public key, the reader's group identifier, and the group sub-identifier. - * Sample applications that uses RFAL driver. +.. _release_notes: + +Release notes +############# + +This page outlines changes introduced with each release of the |APP_NAME|. + +v0.2.0 +****** + +.. note:: + |EXPERIMENTAL_NOTE| + +Changelog +========= + +The following updates were introduced in this release. + +* Added: + + * Experimental support for the following development platforms: + + * `nRF52840 DK`_ + * `nRF5340 DK`_ + + * A platform logger implementation. + * A new NFC transport interface integration. + * Simplified Aliro stack API integration. + +* Improved the implementation of the following components in the RFAL platform abstraction layer: + + * Timers + * Semaphores + * Threading + +v0.1.0 +****** + +.. note:: + |EXPERIMENTAL_NOTE| + +See the following section for the list of implemented features. + +* Added experimental support for the following: + + * Access Protocol (the expedited standard transaction only). + * Transport Protocol over Near Field Communication (NFC) transport. + * Trusted Framework implementation with the |NCS| PSA API as a cryptography backend. + * The nRF54L15 hardware platform. + * STM NFC Reader transceivers: ST25R200, ST25R3911, ST25R3916, ST25R3916B, ST25R200. + * ST Microelectronics R/F Abstraction Layer driver with Zephyr Platform Abstraction Layer integration. + * |APP_NAME| that leverages Aliro stack and supports CLI-based provisioning of the Access Credential public key, the reader's group identifier, and the group sub-identifier. + * Sample applications that uses RFAL driver. diff --git a/docs/requirements.txt b/docs/requirements.txt index 355a616d..b3e33a71 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -Sphinx==5.3.0 -sphinx-copybutton==0.5.2 -sphinx-ncs-theme==0.7.4 -sphinx-tabs==3.4.0 +Sphinx==5.3.0 +sphinx-copybutton==0.5.2 +sphinx-ncs-theme==0.7.4 +sphinx-tabs==3.4.0 diff --git a/docs/software_requirements.rst b/docs/software_requirements.rst index b1a5324e..345fb039 100644 --- a/docs/software_requirements.rst +++ b/docs/software_requirements.rst @@ -1,84 +1,84 @@ -.. _sw_requirements: - -Software requirements -##################### - -This page summarizes the requirements for setting up and working with the |app_name|. - -.. _sdk_set_up: - -|NCS| -***** - -Before you start working with the application, you must have installed the |NCS| development environment and |NCS| toolchain. - -Prepare the environment: - -1. From the `Installing the nRF Connect SDK`_ page, complete the following steps: updating operating system, installing prerequisities, and installing the |NCS| toolchain. - - .. note:: - - |VSC| does not support private add-ons. - You must use command-line to clone the repository. - -#. Once completed, open the repository and locate the :file:`ncs` directory. - By default, this is one level up from the location where you installed the toolchain. - This directory will hold all |NCS| repositories. - -#. Start the toolchain environment for your operating system using the following command: - - .. code-block:: console - - nrfutil toolchain-manager launch --shell - -#. Initialize west: - - .. code-block:: console - - west init -m https://github.com/nrfconnect/ncs-door-lock-app --mr main door-lock-workspace - cd door-lock-workspace - - This command will clone the `ncs-door-lock-app`_ add-on manifest repository into :file:`door-lock-workspace`. - -#. Enter the following command to clone the project repository: - - .. code-block:: console - - west update - - Depending on your connection, this might take some time. - -#. Export a `Zephyr CMake package`_. - This allows CMake to automatically load the boilerplate code required for building |NCS| applications: - - .. code-block:: console - - west zephyr-export - - With the default location to install the toolchain, your directory structure now looks similar to this: - - .. code-block:: none - - ncs - ├─── toolchains - │ └─── - └─── - ├─── .west - ├─── bootloader - ├─── modules - ├─── ncs-door-lock-app - ├─── nrf - ├─── nrfxlib - ├─── zephyr - └─── ... - - In this simplified structure preview, ** corresponds to the toolchain version and ** corresponds to the SDK version name. - -#. Complete `setting up the command-line build environment`_. - -Once you have completed all the steps, the development environment should be correctly configured. - -Aliro Certification Tool -************************ - -You must have the official :ref:`Aliro Certification Tool to be able to execute test cases `. +.. _sw_requirements: + +Software requirements +##################### + +This page summarizes the requirements for setting up and working with the |app_name|. + +.. _sdk_set_up: + +|NCS| +***** + +Before you start working with the application, you must have installed the |NCS| development environment and |NCS| toolchain. + +Prepare the environment: + +1. From the `Installing the nRF Connect SDK`_ page, complete the following steps: updating operating system, installing prerequisities, and installing the |NCS| toolchain. + + .. note:: + + |VSC| does not support private add-ons. + You must use command-line to clone the repository. + +#. Once completed, open the repository and locate the :file:`ncs` directory. + By default, this is one level up from the location where you installed the toolchain. + This directory will hold all |NCS| repositories. + +#. Start the toolchain environment for your operating system using the following command: + + .. code-block:: console + + nrfutil toolchain-manager launch --shell + +#. Initialize west: + + .. code-block:: console + + west init -m https://github.com/nrfconnect/ncs-door-lock-app --mr main door-lock-workspace + cd door-lock-workspace + + This command will clone the `ncs-door-lock-app`_ add-on manifest repository into :file:`door-lock-workspace`. + +#. Enter the following command to clone the project repository: + + .. code-block:: console + + west update + + Depending on your connection, this might take some time. + +#. Export a `Zephyr CMake package`_. + This allows CMake to automatically load the boilerplate code required for building |NCS| applications: + + .. code-block:: console + + west zephyr-export + + With the default location to install the toolchain, your directory structure now looks similar to this: + + .. code-block:: none + + ncs + ├─── toolchains + │ └─── + └─── + ├─── .west + ├─── bootloader + ├─── modules + ├─── ncs-door-lock-app + ├─── nrf + ├─── nrfxlib + ├─── zephyr + └─── ... + + In this simplified structure preview, ** corresponds to the toolchain version and ** corresponds to the SDK version name. + +#. Complete `setting up the command-line build environment`_. + +Once you have completed all the steps, the development environment should be correctly configured. + +Aliro Certification Tool +************************ + +You must have the official :ref:`Aliro Certification Tool to be able to execute test cases `. diff --git a/docs/testing.rst b/docs/testing.rst index e7d26cad..eead4641 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -1,198 +1,305 @@ -.. _testing: - -Testing and troubleshooting -########################### - -This page will guide you through the testing instructions for the |app_name|. - -.. _testing_environment: - -Test environment -**************** - -Test environment consists of two major components: - -* The `nRF54L15 DK`_, which serves as the Reader in the door lock component. - It must be attached to an NFC card reader expansion board. -* The Aliro Test Harness, which acts as the user device and simulates unlocking of the door lock. - -See the :ref:`hw_requirements` page for more details. - -.. _testing_environment_configuration: - -Configuring test environment -**************************** - -This section provides instructions on setting up the Test Harness, selecting tests, and executing them. -In case you do not have access to `Aliro Certification Tool`_ repository, see the :ref:`hw_requirements_test_harness` section for further guidance. - -.. note:: - All examples related to the `Aliro Certification Tool`_ are based on the ``dryrun/test_event4-2024-aliro_specification_v0.9.0-v1.0`` tag. - -#. Follow the `Test harness usage instructions`_ in the `Aliro Certification Tool`_ repository. - -#. Obtain the long-term public key and reader group identifier of the Reader device under test (DUT). - You can retrieve this information from the serial console of a DUT. - See more information on :ref:`building, flashing, and accessing the serial console`. - -#. After flashing the door lock firmware with Aliro support onto the device, observe the provisioned key and reader group identifier of the Reader printed on the DUT's serial console: - - .. code-block:: console - - Provision the Test Harness with the following Reader Public Key: - XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - ... - - .. code-block:: console - - Provision the Test Harness with the following Reader Group Identifier: - XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - ... - -#. Open your project's JSON configuration and locate the ``dut_reader_public_key``, ``th_access_credential_public_key``, ``dut_reader_group_identifier``, and ``dut_reader_group_sub_identifier`` fields. - - .. figure:: /images/th_config.png - :scale: 70% - :alt: Test harness project configuration. - - Test harness project configuration. - -#. Set up the test harness by inputting the 65-byte long Reader public key into the ``dut_reader_public_key`` field. - -#. Install the 16-byte long Reader group identifier and reader group sub-identifier in the Reader device. - Both values can be provided to the DUT using the following ``dl install`` shell commands: - - .. code-block:: console - - uart:~$ dl install group_id <16-byte reader_group_identifier in hex without 0x> - uart:~$ dl install group_sub_id <16-byte reader_group_sub_identifier in hex without 0x> - - For example: - - .. code-block:: console - - uart:~$ dl install group_id 00113344667799AA00113344667799AA - uart:~$ dl install group_sub_id 113344667799AA00113344667799AA00 - - Executing the same commands without specifying values will return the stored value. - For example: - - .. code-block:: console - - uart:~$ dl install group_id - 00000000: 00 11 33 44 66 77 99 aa 00 11 33 44 66 77 99 aa |..3Dfw.. ..3Dfw..| - - Alternatively, you can set the Reader group identifier retrieved from DUT in the test harness project configuration, next to the ``dut_reader_group_identifier`` field. - -#. Set the ``th_access_credential_public_key`` in the DUT using the following ``dl provisioning`` shell command: - - .. code-block:: console - - uart:~$ dl provisioning AC_key <65-byte public key in hex in hex without 0x> - - For example: - - .. code-block:: console - - uart:~$ dl provisioning AC_key 04742df736d0fc9be978c45b00e8fdf7cea684ea105ae574c1505a2c24ab6198e3125b7f1b7e1d134c55ece69681ba8ecc18a3836dc5199c759f31e8ccf17e3efa - - Executing the same command without specifying the public key will return the stored value. - For example: - - .. code-block:: console - - uart:~$ dl provisioning AC_key - 00000000: 04 74 2d f7 36 d0 fc 9b e9 78 c4 5b 00 e8 fd f7 |.t-.6... .x.[....| - 00000010: ce a6 84 ea 10 5a e5 74 c1 50 5a 2c 24 ab 61 98 |.....Z.t .PZ,$.a.| - 00000020: e3 12 5b 7f 1b 7e 1d 13 4c 55 ec e6 96 81 ba 8e |..[..~.. LU......| - 00000030: cc 18 a3 83 6d c5 19 9c 75 9f 31 e8 cc f1 7e 3e |....m... u.1...~>| - 00000040: fa |. | - -.. _testing_verification: - -Verification and testing process -******************************** - -Perform tests to ensure your devices are functioning correctly. -You can see the full list of available test on the `Aliro Certification Tool`_ repository. -Note, that NFC Reader tests start with the ``RD`` prefix. -This means that the Test Harness device will be operating as Aliro user device. - -For verification, execute the following tests: - -1. RD-NFC-CONTROLFLOW-2.0 test, which allows you to verify if the communication between the Reader and the user device terminates correctly when sending the ``CONTROL_FLOW`` command. -2. RD-NFC-STDTXN-2.0 test, which allows you to verify if the Reader properly implements the Aliro authentication protocol. - -Running the test -================ - -Complete the following steps for the required tests: - -#. Navigate to the project you created in the Test Harness web interface and click :guilabel:`Go To Test-Run`. -#. Click on :guilabel:`Add New Test`. -#. In the test suites, select :guilabel:`NFC Reader` and under the :guilabel:`Test Cases` section check the box of the test you wish to run. -#. Choose the operator and click :guilabel:`Start`. -#. Position the Reader and Test Harness hardware close to each other, and align them to ensure optimal NFC communication. -#. A notification will appear asking you to set the Reader DUT in the NFC polling mode and to place the devices next to each other for automatic detection. - Select :guilabel:`Ok` and click :guilabel:`Submit`. -#. Depending on the test you executed, you should see the following results: - - .. tabs:: - - .. tab:: RD-NFC-CONTROLFLOW-2.0 - - .. figure:: /images/control_flow_test_selection.png - :scale: 50% - :alt: Tests selection view. - - Tests selection view. - - The Reader device selects the Test Harness user device, which then terminates the communication and expects the ``CONTROL_FLOW`` command from the Reader in response. - - In the DUT's serial console, you will see logs that indicate the state of the operation and the data payloads transmitted and received by the Reader. - If the results show as ``passed``, you will see the following output in the Test Harness web interface: - - .. figure:: /images/test_results_control_flow.png - :scale: 50% - :alt: Basic test results view. - - Basic test results view. - - .. tab:: RD-NFC-STDTXN-2.0 - - .. figure:: /images/stdtxn_test_selection.png - :scale: 50% - :alt: Tests selection view. - - Tests selection view. - - The Reader device will select the Test Harness user device and initiate the Aliro Access Protocol commands exchange. - - In the DUT's serial console, you will see logs that indicate the state of the operation and the data payloads transmitted and received by the Reader. - If the results show as ``passed``, you will see the following output in the Test Harness web interface: - - .. figure:: /images/test_results_stdtxn.png - :scale: 50% - :alt: Example of the advanced test results. - - Example of the advanced test results. - - After test execution is complete, you can check DUT logs to verify the communication and data exchange between the Reader and the test harness. - The logs will provide detailed information about the test execution and authorization process (signature verification). - When all installation and provisioning data provided in :ref:`testing_environment_configuration` are correct then you will see the following output in the DUT serial console: - - .. code-block:: console - - [00:00:39.678,248] Verify signature - [00:00:39.679,533] door_lock_app: ACCESS GRANTED - [00:00:39.679,704] Finishing secure session - [00:00:39.679,724] Communication finished - - When the provided access credential public key is incorrect the following output will be displayed: - - .. code-block:: console - - [00:00:20.383,849] Verify signature - [00:00:20.384,034] door_lock_app: ACCESS DENIED - [00:00:20.384,199] Finishing secure session - [00:00:20.384,219] Communication finished +.. _testing: + +Testing and troubleshooting +########################### + +This page will guide you through the testing instructions for the |app_name|. + +.. _testing_environment: + +Test environment +**************** + +Test environment consists of two major components: + +* The Nordic Semiconductor’s :ref:`development kit (DK) `, which serves as the Reader in the door lock component. + It must be attached to an NFC card reader expansion board. +* The Aliro Test Harness, which acts as the user device and simulates unlocking of the door lock. + +See the :ref:`hw_requirements` page for more details. + +.. _testing_environment_configuration: + +Configuring test environment +**************************** + +This section provides instructions on setting up the Test Harness, selecting tests, and executing them. +In case you do not have access to `Aliro Certification Tool`_ repository, see the :ref:`hw_requirements_test_harness` section for further guidance. + +.. note:: + All examples related to the `Aliro Certification Tool`_ are based on the ``dryrun/test_event4-2024-aliro_specification_v0.9.0-v1.0`` tag. + +#. Follow the `Test harness usage instructions`_ in the `Aliro Certification Tool`_ repository. + +#. Obtain the long-term public key and reader group identifier of the Reader device under test (DUT). + You can retrieve this information from the serial console of a DUT. + See more information on :ref:`building, flashing, and accessing the serial console`. + +#. After flashing the door lock firmware with Aliro support onto the device, observe the provisioned key and reader group identifier of the Reader printed on the DUT's serial console: + + .. code-block:: console + + Provision the Test Harness with the following Reader Public Key: + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ... + + .. code-block:: console + + Provision the Test Harness with the following Reader Group Identifier: + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ... + +#. Open your project's JSON configuration and locate the ``dut_reader_public_key``, ``th_access_credential_public_key``, ``dut_reader_group_identifier``, and ``dut_reader_group_sub_identifier`` fields. + + .. figure:: /images/th_config.png + :scale: 70% + :alt: Test harness project configuration. + + Test harness project configuration. + +#. Set up the test harness by inputting the 65-byte long Reader public key into the ``dut_reader_public_key`` field. + +#. Install the 16-byte long Reader group identifier and reader group sub-identifier in the Reader device. + Both values can be provided to the DUT using the following ``dl install`` shell commands: + + .. code-block:: console + + uart:~$ dl install group_id <16-byte reader_group_identifier in hex without 0x> + uart:~$ dl install group_sub_id <16-byte reader_group_sub_identifier in hex without 0x> + + For example: + + .. code-block:: console + + uart:~$ dl install group_id 00113344667799AA00113344667799AA + uart:~$ dl install group_sub_id 113344667799AA00113344667799AA00 + + Executing the same commands without specifying values will return the stored value. + For example: + + .. code-block:: console + + uart:~$ dl install group_id + 00000000: 00 11 33 44 66 77 99 aa 00 11 33 44 66 77 99 aa |..3Dfw.. ..3Dfw..| + + Alternatively, you can set the Reader group identifier retrieved from DUT in the test harness project configuration, next to the ``dut_reader_group_identifier`` field. + +#. Set the ``th_access_credential_public_key`` in the DUT using the following ``dl provisioning`` shell command: + + .. code-block:: console + + uart:~$ dl provisioning AC_key <65-byte public key in hex in hex without 0x> + + For example: + + .. code-block:: console + + uart:~$ dl provisioning AC_key 04742df736d0fc9be978c45b00e8fdf7cea684ea105ae574c1505a2c24ab6198e3125b7f1b7e1d134c55ece69681ba8ecc18a3836dc5199c759f31e8ccf17e3efa + + Executing the same command without specifying the public key will return the stored value. + For example: + + .. code-block:: console + + uart:~$ dl provisioning AC_key + 00000000: 04 74 2d f7 36 d0 fc 9b e9 78 c4 5b 00 e8 fd f7 |.t-.6... .x.[....| + 00000010: ce a6 84 ea 10 5a e5 74 c1 50 5a 2c 24 ab 61 98 |.....Z.t .PZ,$.a.| + 00000020: e3 12 5b 7f 1b 7e 1d 13 4c 55 ec e6 96 81 ba 8e |..[..~.. LU......| + 00000030: cc 18 a3 83 6d c5 19 9c 75 9f 31 e8 cc f1 7e 3e |....m... u.1...~>| + 00000040: fa |. | + +.. _testing_verification: + +Verification and testing process +******************************** + +Perform tests to ensure your devices are functioning correctly. +You can see the full list of available tests in the `Aliro Certification Tool`_ repository. +Note that NFC Reader tests start with the ``RD`` prefix, and Bluetooth LE Reader tests start with ``RD-BLE``. +This means that the Test Harness device will be operating as the Aliro user device. + +For verification, execute the following tests: + +* NFC: + * RD-NFC-CONTROLFLOW-2.0 – Verifies if the communication between the Reader and the user device terminates correctly when sending the ``CONTROL_FLOW`` command. + * RD-NFC-STDTXN-2.0 – Verifies if the Reader properly implements the Aliro authentication protocol over NFC. +* Bluetooth LE: + * RD-BLE-STDTXN-1.0 – Verifies if the Reader advertises proper data over Bluetooth LE and if the GATT characteristics are implemented. + * RD-BLE-STDTXN-2.0 – Verifies if the Reader properly implements the Aliro authentication protocol over Bluetooth LE. + +Running the test +================ + +Complete the following steps for the required tests: + +#. Navigate to the project you created in the Test Harness web interface and click :guilabel:`Go To Test-Run`. + +#. Click on :guilabel:`Add New Test`. + +#. In the test suites, select either :guilabel:`NFC Reader` or :guilabel:`BLE Reader` and under the :guilabel:`Test Cases` section check the box of the test you wish to run. + +#. Choose the operator and click :guilabel:`Start`. + +#. Complete the test: + + .. tabs:: + + .. tab:: NFC + + a. Position the Reader and Test Harness hardware close to each other, and align them to ensure optimal NFC communication. + #. A notification will appear asking you to set the Reader DUT in the appropriate mode and to place the devices next to each other for automatic NFC detection. + Select :guilabel:`Ok` and click :guilabel:`Submit`. + + .. tab:: Bluetooth LE + + a. Ensure the Reader is advertising and ready to accept Bluetooth LE connections from the Test Harness. + You should see a notification requesting Bluetooth LE visibility for automatic detection. + #. Confirm that the Reader is advertising by checking the DUT console for logs indicating that advertising has started. + + .. code-block:: console + + L2CAP server registered with PSM: 0x0080 + + #. Select :guilabel:`Ok` and click :guilabel:`Submit`. + Restarting the Murata device, if prompted, is optional. + + .. note:: + At the start of each Bluetooth LE test, the firmware is uploaded to the Murata device, which may take some time. + The Murata module (`LBUA0VG2BP-EVK-P`_) is used by the Test Harness to establish and handle Bluetooth LE communication with the device under test. + +#. Depending on the test you executed, you should see the following results: + + .. tabs:: + + .. tab:: RD-NFC-CONTROLFLOW-2.0 + + .. figure:: /images/control_flow_test_selection.png + :scale: 50% + :alt: Tests selection view. + + Tests selection view. + + The Reader device selects the Test Harness user device, which then terminates the communication and expects the ``CONTROL_FLOW`` command from the Reader in response. + + In the DUT's serial console, you will see logs that indicate the state of the operation and the data payloads transmitted and received by the Reader. + If the results show as ``passed``, you will see the following output in the Test Harness web interface: + + .. figure:: /images/test_results_control_flow.png + :scale: 50% + :alt: Basic test results view. + + Basic test results view. + + .. tab:: RD-NFC-STDTXN-2.0 + + .. figure:: /images/stdtxn_test_selection.png + :scale: 50% + :alt: Tests selection view. + + Tests selection view. + + The Reader device will select the Test Harness user device and initiate the Aliro Access Protocol commands exchange. + + In the DUT's serial console, you will see logs that indicate the state of the operation and the data payloads transmitted and received by the Reader. + If the results show as ``passed``, you will see the following output in the Test Harness web interface: + + .. figure:: /images/test_results_stdtxn.png + :scale: 50% + :alt: Example of the advanced test results. + + Example of the advanced test results. + + After test execution is complete, you can check DUT logs to verify the communication and data exchange between the Reader and the test harness. + The logs will provide detailed information about the test execution and authorization process (signature verification). + When all installation and provisioning data provided in :ref:`testing_environment_configuration` are correct then you will see the following output in the DUT serial console: + + .. code-block:: console + + [00:00:39.678,248] Verify signature + [00:00:39.679,533] door_lock_app: ACCESS GRANTED + [00:00:39.679,704] Finishing secure session + [00:00:39.679,724] Communication finished + + .. note:: + When access is granted, the device also signals this event by turning on a dedicated LED. For details, see the :ref:`access decision indicator ` section. + + When the provided access credential public key is incorrect the following output will be displayed: + + .. code-block:: console + + [00:00:20.383,849] Verify signature + [00:00:20.384,034] door_lock_app: ACCESS DENIED + [00:00:20.384,199] Finishing secure session + [00:00:20.384,219] Communication finished + + .. tab:: RD-BLE-STDTXN-1.0 + + .. figure:: /images/rd_ble_stdtxn_1_0_test_selection.png + :scale: 50% + :alt: Tests selection view. + + Tests selection view. + + The Reader device will advertise over Bluetooth LE and the Test Harness will connect as a Bluetooth LE central device, initiating the Aliro Access Protocol commands exchange over Bluetooth LE. + + In the DUT's serial console, you will see logs that indicate the state of the Bluetooth LE connection, protocol execution, and the data payloads transmitted and received by the Reader. + If the results show as ``passed``, you will see the following output in the Test Harness web interface: + + .. figure:: /images/test_results_rd_ble_stdtxn_1_0.png + :scale: 50% + :alt: Basic test results view. + + Basic test results view. + + .. tab:: RD-BLE-STDTXN-2.0 + + .. figure:: /images/rd_ble_stdtxn_2_0_test_selection.png + :scale: 50% + :alt: Tests selection view. + + Tests selection view. + + The Reader device will select the Test Harness user device and initiate the Aliro Access Protocol commands exchange. + + In the DUT's serial console, you will see logs that indicate the state of the operation and the data payloads transmitted and received by the Reader. + If the results show as ``passed``, you will see the following output in the Test Harness web interface: + + .. figure:: /images/test_results_rd_ble_stdtxn_2_0.png + :scale: 50% + :alt: Example of the advanced test results. + + Example of the advanced test results. + + After test execution is complete, you can check DUT logs to verify the communication and data exchange between the Reader and the test harness. + The logs will provide detailed information about the test execution and authorization process (signature verification). + When all installation and provisioning data provided in :ref:`testing_environment_configuration` are correct then you will see the following output in the DUT serial console: + + .. code-block:: console + + [00:00:39.678,248] Verify signature + [00:00:39.679,533] door_lock_app: ACCESS GRANTED + [00:00:39.679,704] Finishing secure session + [00:00:39.679,724] Communication finished + + .. note:: + When access is granted, the device also signals this event by turning on a dedicated LED. For details, see the :ref:`access decision indicator ` section. + + When the provided access credential public key is incorrect the following output will be displayed: + + .. code-block:: console + + [00:00:20.383,849] Verify signature + [00:00:20.384,034] door_lock_app: ACCESS DENIED + [00:00:20.384,199] Finishing secure session + [00:00:20.384,219] Communication finished + +Additional CLI commands +======================= + +To check the revision of the Aliro library on your device, run the following command in the device shell: + +.. code-block:: console + + uart:~$ dl info + Aliro version: v0.2.0-22-g7da4b2e + NFC reader: ST25R100 diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index f9fabb3b..04f6e741 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -1,40 +1,40 @@ -.. _troubleshooting: - -Troubleshooting -############### - -The following page outlines common troubleshooting scenarios for device under test (DUT) and test harness setups. - -Issues when connecting to RaspberryPi -************************************* - -In cases where it is impossible to connect to a Raspberry Pi through WiFi or an Ethernet cable, you must configure the network manually: - -1. Eject the SD card from the RaspberryPi and mount it on your laptop. - You will see two partitions: ``writable`` and ``system-boot``. - -#. On the ``writable`` partition, navigate to the :file:`writable/etc/netplan/99_config.yaml` file. - Apply the following configuration for the ``eth0`` interface: - - .. code-block:: yaml - - network: - version: 2 - ethernets: - eth0: - addresses: - - 192.167.1.10/24 - gateway4: 192.167.1.1 - nameservers: - addresses: - - 8.8.8.8 - - 8.8.4.4 - .. - -#. Identify the Ethernet device on your local machine and assign network configurations. - Ensure both your local machine and RaspberryPi are on the same network: - - .. code-block:: console - - ip link set enx109819b3e9d4 up - ip addr add 192.167.1.1/24 dev +.. _troubleshooting: + +Troubleshooting +############### + +The following page outlines common troubleshooting scenarios for device under test (DUT) and test harness setups. + +Issues when connecting to RaspberryPi +************************************* + +In cases where it is impossible to connect to a Raspberry Pi through WiFi or an Ethernet cable, you must configure the network manually: + +1. Eject the SD card from the RaspberryPi and mount it on your laptop. + You will see two partitions: ``writable`` and ``system-boot``. + +#. On the ``writable`` partition, navigate to the :file:`writable/etc/netplan/99_config.yaml` file. + Apply the following configuration for the ``eth0`` interface: + + .. code-block:: yaml + + network: + version: 2 + ethernets: + eth0: + addresses: + - 192.167.1.10/24 + gateway4: 192.167.1.1 + nameservers: + addresses: + - 8.8.8.8 + - 8.8.4.4 + .. + +#. Identify the Ethernet device on your local machine and assign network configurations. + Ensure both your local machine and RaspberryPi are on the same network: + + .. code-block:: console + + ip link set enx109819b3e9d4 up + ip addr add 192.167.1.1/24 dev diff --git a/drivers/nfc/stm/CMakeLists.txt b/drivers/nfc/stm/CMakeLists.txt index a2ea7f65..2bdfd061 100644 --- a/drivers/nfc/stm/CMakeLists.txt +++ b/drivers/nfc/stm/CMakeLists.txt @@ -14,30 +14,30 @@ set(ST_RFAL_INC_DIR ${ST_RFAL_DIR}/include) set(INCLUDE_DIR include) if(CONFIG_ST25R3911_DRV) - zephyr_library_compile_definitions(-DST25R3911) - set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r3911) + zephyr_library_compile_definitions(-DST25R3911) + set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r3911) elseif(CONFIG_ST25R3916B_DRV OR CONFIG_ST25R3916_DRV) - zephyr_library_compile_definitions_ifdef(CONFIG_ST25R3916_DRV -DST25R3916) - zephyr_library_compile_definitions_ifdef(CONFIG_ST25R3916B_DRV -DST25R3916B) - set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r3916) + zephyr_library_compile_definitions_ifdef(CONFIG_ST25R3916_DRV -DST25R3916) + zephyr_library_compile_definitions_ifdef(CONFIG_ST25R3916B_DRV -DST25R3916B) + set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r3916) elseif(CONFIG_ST25R200_DRV) - zephyr_library_compile_definitions(-DST25R200) - set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r200) + zephyr_library_compile_definitions(-DST25R200) + set(ST_DRIVER_INC ${ST_RFAL_SRC_DIR}/st25r200) else() - message(FATAL_ERROR "NFC driver not defined") + message(FATAL_ERROR "NFC driver not defined") endif() -file(GLOB ST_RFAL_SOURCES ${ST_RFAL_SRC_DIR}/*.c) -file(GLOB_RECURSE ST_DRIVER_SOURCES ${ST_DRIVER_INC}/*.c) +file(GLOB ST_RFAL_SOURCES CONFIGURE_DEPENDS ${ST_RFAL_SRC_DIR}/*.c) +file(GLOB_RECURSE ST_DRIVER_SOURCES CONFIGURE_DEPENDS ${ST_DRIVER_INC}/*.c) zephyr_include_directories( - ${ST_DRIVER_INC} - ${ST_RFAL_INC_DIR} - ${ST_RFAL_SRC_DIR} - ${INCLUDE_DIR} + ${ST_DRIVER_INC} + ${ST_RFAL_INC_DIR} + ${ST_RFAL_SRC_DIR} + ${INCLUDE_DIR} ) zephyr_library_sources( - ${ST_DRIVER_SOURCES} - ${ST_RFAL_SOURCES} + ${ST_DRIVER_SOURCES} + ${ST_RFAL_SOURCES} ) diff --git a/drivers/nfc/stm/PAL/CMakeLists.txt b/drivers/nfc/stm/PAL/CMakeLists.txt index d8e58267..984c4d44 100644 --- a/drivers/nfc/stm/PAL/CMakeLists.txt +++ b/drivers/nfc/stm/PAL/CMakeLists.txt @@ -4,10 +4,8 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # -file(GLOB_RECURSE ST_PAL_SOURCES ./*.c) +file(GLOB_RECURSE ST_PAL_SOURCES CONFIGURE_DEPENDS ./*.c) zephyr_include_directories(.) -zephyr_library_sources( - ${ST_PAL_SOURCES} -) +zephyr_library_sources(${ST_PAL_SOURCES}) diff --git a/drivers/nfc/stm/PAL/ncs_pal_gpio.c b/drivers/nfc/stm/PAL/ncs_pal_gpio.c index d46b7af9..deaa1a62 100644 --- a/drivers/nfc/stm/PAL/ncs_pal_gpio.c +++ b/drivers/nfc/stm/PAL/ncs_pal_gpio.c @@ -15,6 +15,8 @@ LOG_MODULE_REGISTER(pal_gpio, CONFIG_NFC_LOG_LEVEL); static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_GET(DT_INST(0, x_nucleo_nfc), irq_gpios); +// The reset GPIO is optional, so we use GPIO_DT_SPEC_GET_OR to avoid errors if it is not defined. +static const struct gpio_dt_spec reset_gpio = GPIO_DT_SPEC_GET_OR(DT_INST(0, x_nucleo_nfc), reset_gpios, { 0 }); // TODO: This should be moved to the nRF54L style shield. #ifdef CONFIG_BOARD_NRF54L15DK @@ -51,16 +53,30 @@ int ncs_pal_pwr_pin_set() int ncs_pal_gpio_init(void) { static struct gpio_callback gpio_cb; + int err = 0; LOG_DBG("GPIO init"); - if (!device_is_ready(irq_gpio.port)) { + if (reset_gpio.port) { + if (!gpio_is_ready_dt(&reset_gpio)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + /* Configure reset pin */ + err = gpio_pin_configure_dt(&reset_gpio, GPIO_OUTPUT_LOW); + if (err) { + return err; + } + } + + if (!gpio_is_ready_dt(&irq_gpio)) { LOG_ERR("IRQ GPIO device not ready"); return -ENODEV; } /* Configure IRQ pin */ - int err = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + err = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); if (err) { return err; } diff --git a/drivers/nfc/stm/PAL/ncs_pal_nfc_worker.c b/drivers/nfc/stm/PAL/ncs_pal_nfc_worker.c index 8a7416c9..a2ce9122 100644 --- a/drivers/nfc/stm/PAL/ncs_pal_nfc_worker.c +++ b/drivers/nfc/stm/PAL/ncs_pal_nfc_worker.c @@ -10,6 +10,13 @@ struct k_thread pal_nfc_thread; k_tid_t ncs_pal_nfc_worker_start(thread_func_t thread_func) { - return k_thread_create(&pal_nfc_thread, pal_nfc_stack, CONFIG_RFAL_WORKER_THREAD_STACK_SIZE, thread_func, NULL, - NULL, NULL, K_PRIO_PREEMPT(CONFIG_RFAL_WORKER_THREAD_PRIORITY), 0, K_NO_WAIT); + const k_tid_t thread = + k_thread_create(&pal_nfc_thread, pal_nfc_stack, CONFIG_RFAL_WORKER_THREAD_STACK_SIZE, thread_func, NULL, + NULL, NULL, K_PRIO_PREEMPT(CONFIG_RFAL_WORKER_THREAD_PRIORITY), 0, K_NO_WAIT); + + if (thread) { + k_thread_name_set(thread, "PAL Worker"); + } + + return thread; } diff --git a/drivers/nfc/stm/RFAL/LICENSE.pdf b/drivers/nfc/stm/RFAL/LICENSE.pdf index 2719783a..718226f2 100644 Binary files a/drivers/nfc/stm/RFAL/LICENSE.pdf and b/drivers/nfc/stm/RFAL/LICENSE.pdf differ diff --git a/drivers/nfc/stm/nfc_configs/CMakeLists.txt b/drivers/nfc/stm/nfc_configs/CMakeLists.txt index 243eb2f4..caf68caa 100644 --- a/drivers/nfc/stm/nfc_configs/CMakeLists.txt +++ b/drivers/nfc/stm/nfc_configs/CMakeLists.txt @@ -4,10 +4,8 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # -file(GLOB_RECURSE NFC_CONFIGS_SOURCES ./*.c) +file(GLOB_RECURSE NFC_CONFIGS_SOURCES CONFIGURE_DEPENDS ./*.c) zephyr_include_directories(.) -zephyr_library_sources( - ${NFC_CONFIGS_SOURCES} -) +zephyr_library_sources(${NFC_CONFIGS_SOURCES}) diff --git a/drivers/samples/nfc_reader/CMakeLists.txt b/drivers/samples/nfc_reader/CMakeLists.txt index ec90161a..22264c5e 100644 --- a/drivers/samples/nfc_reader/CMakeLists.txt +++ b/drivers/samples/nfc_reader/CMakeLists.txt @@ -9,6 +9,4 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ncs-nfc-reader-sample) -target_sources(app PRIVATE - src/main.c -) +target_sources(app PRIVATE src/main.c) diff --git a/drivers/samples/nfc_reader/prj.conf b/drivers/samples/nfc_reader/prj.conf index a8f9fad0..2d7278ea 100644 --- a/drivers/samples/nfc_reader/prj.conf +++ b/drivers/samples/nfc_reader/prj.conf @@ -5,6 +5,9 @@ # # This file contains selected Kconfig options for the application. +# Disable Aliro stack for this sample +CONFIG_NCS_ALIRO=n + # state machine framework CONFIG_SMF=y diff --git a/drivers/samples/nfc_reader_async/CMakeLists.txt b/drivers/samples/nfc_reader_async/CMakeLists.txt index 1467895c..43d3458b 100644 --- a/drivers/samples/nfc_reader_async/CMakeLists.txt +++ b/drivers/samples/nfc_reader_async/CMakeLists.txt @@ -9,6 +9,4 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ncs-nfc-reader-async-sample) -target_sources(app PRIVATE - src/main.c -) +target_sources(app PRIVATE src/main.c) diff --git a/drivers/samples/nfc_reader_async/prj.conf b/drivers/samples/nfc_reader_async/prj.conf index 59ffce1e..4a2c0211 100644 --- a/drivers/samples/nfc_reader_async/prj.conf +++ b/drivers/samples/nfc_reader_async/prj.conf @@ -5,6 +5,9 @@ # # This file contains selected Kconfig options for the application. +# Disable Aliro stack for this sample +CONFIG_NCS_ALIRO=n + # compiler CONFIG_DEBUG_OPTIMIZATIONS=y diff --git a/include/aliro/access.h b/include/aliro/access.h new file mode 100644 index 00000000..0b84ef60 --- /dev/null +++ b/include/aliro/access.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "aliro/errors.h" + +namespace Aliro::Access { + +/** + * @brief Access status. + */ +enum Status : uint8_t { Denied, Granted }; + +/** + * @brief Callbacks for the command handlers. + */ +struct Callbacks { + /** + * @brief Callback for access attempts. + * + * This callback is called when an access attempt is made. + * + * @param status The status of the access attempt. + */ + void (*mOnAccessAttempt)(Status status){ nullptr }; + + /** + * @brief Callback for errors. + * + * This callback is called when an error occurs. + * + * @param error The error that occurred. + */ + void (*mOnError)(AliroError error){ nullptr }; +}; + +} // namespace Aliro::Access diff --git a/include/aliro/aliro.h b/include/aliro/aliro.h new file mode 100644 index 00000000..0c798b34 --- /dev/null +++ b/include/aliro/aliro.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "access.h" + +#include + +namespace Aliro { + +struct AliroConfig { +#ifdef CONFIG_ALIRO_BLE_TP + /** + * @brief The maximum number of BLE sessions. + */ + size_t mMaxBleSessions; +#endif +}; + +/** + * @brief Aliro stack. + */ +class AliroStack { +public: + /** + * @brief Gets the instance of the Aliro stack. + * + * @return The instance of the Aliro stack. + */ + static AliroStack &Instance() + { + static AliroStack sInstance; + return sInstance; + } + + /** + * @brief Initializes the Aliro stack. + * + * @param callbacks The Access callbacks. + * @param config The Aliro configuration. + * + * @return ALIRO_NO_ERROR if the stack was initialized successfully, an error code otherwise. + */ + AliroError Init(const Access::Callbacks &callbacks, const AliroConfig &config); + + /** + * @brief Starts the Aliro stack. + * + * @return ALIRO_NO_ERROR if the stack was started successfully, an error code otherwise. + */ + AliroError Start() const; + + /** + * @brief Gets the Aliro configuration. + * + * @return The Aliro configuration. + */ + const AliroConfig &GetConfig() const { return mConfig; } + + /** + * @brief Temporary method for processing the access decision result. + * + * Called by the state machine when access verification is complete. + * Triggers the appropriate user callback based on the access status. + * + * @param status The access decision result (Granted/Denied). + * + * @note This function finally should be replaced by appropriate application callback. + */ + void AccessDecision(Access::Status status) const; + +private: + Access::Callbacks mCallbacks; + AliroConfig mConfig; +}; + +} // namespace Aliro diff --git a/include/aliro/errors.h b/include/aliro/errors.h new file mode 100644 index 00000000..07f64502 --- /dev/null +++ b/include/aliro/errors.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include + +enum AliroErrorCode : uint8_t { + ALIRO_NO_ERROR, + ALIRO_NO_MEMORY, + ALIRO_ERROR_INTERNAL, + ALIRO_INVALID_STATE, + ALIRO_INVALID_ARGUMENT, + ALIRO_INVALID_SIGNATURE, + ALIRO_TIMEOUT, + ALIRO_ERROR_NOT_IMPLEMENTED, + ALIRO_TLV_INVALID_TAG, + ALIRO_TLV_INVALID_LEN, + ALIRO_TLV_BUFFER_TOO_SMALL, + ALIRO_TLV_WRONG_DATA_TYPE, + ALIRO_TLV_END_OF_TLV, + ALIRO_UWB_INIT_FAILED, + ALIRO_ERROR_UNKNOWN, + ALIRO_SESSION_NOT_FOUND, + ALIRO_ERROR_MAX, +}; + +/** + * @brief Error code wrapper class. + */ +class AliroError { +public: + AliroError() = default; + constexpr AliroError(AliroErrorCode code) : mCode(code) {} + + /* Converting constructors. */ + bool operator==(AliroErrorCode code) const { return code == mCode; } + bool operator==(AliroError other) const { return other.mCode == mCode; } + + operator AliroErrorCode() const { return mCode; } + + /** + * @brief Convert to undelying integer representation. + * + * This method may be a remedy in the case of implicit conversion warnings + * from the compiler. + * + * @return Underlying integer number error code + */ + int ToInt() const { return static_cast(mCode); } + + /** + * @brief Convert to string. + * + * This method may come in handy when printing the error messages. + * + * @return Corresponding string error message + */ + const char *ToString() const; + + /** + * @brief Convert from integer error code. + * + * This method can be used as a default mapping in the code that doesn't implement + * custom conversion from integer error codes to the AliroError. + * + * @return Corresponding AliroError + */ + static AliroError FromInt(int ec); + +private: + AliroErrorCode mCode{ ALIRO_NO_ERROR }; +}; diff --git a/include/aliro/shell.h b/include/aliro/shell.h new file mode 100644 index 00000000..f58c0dbd --- /dev/null +++ b/include/aliro/shell.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +namespace Aliro { + +/** + * @brief Registers shell commands for managing a door lock system. + * + * This function sets up the Zephyr shell environment with specific commands related to the door lock. + * It integrates several subcommands under the main command 'dl'. Each subcommand is designed to handle + * different aspects of the door lock configuration and control. + * + * ## Subcommands + * - `install`: + * - `group_id [value]`: Gets or sets the group identifier. If a value is provided, it sets the group ID to that + * value. + * - `group_sub_id [value]`: Gets or sets the group sub-identifier. If a value is provided, it sets the group sub ID + * to that value. + * - `provisioning`: + * - `AC_key [value]`: Gets or sets the Access Credential public key. If a value is provided, it sets the public key + * to that value. + * - `factory_reset`: Executes a factory reset of the system, clearing all stored settings and data. + * + * ## Usage + * Commands are used through the shell interface provided by the Zephyr OS. Each command might require specific + * parameters as detailed above. The commands are accessed by prefixing them with 'dl', e.g., `dl install group_id`. + * + * @note This function should be called during the system initialization phase to ensure all commands are properly + * registered before the shell is used. + */ +void RegisterShellCommands(); + +} // namespace Aliro diff --git a/include/aliro/types.h b/include/aliro/types.h new file mode 100644 index 00000000..f06bef0f --- /dev/null +++ b/include/aliro/types.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include +#include +#include + +/** + * @brief Aliro specific common types definitions. + * + * Contains type definitions, constants, and utility functions + * used commonly across the Aliro stack. + */ +namespace Aliro { + +/** + * @brief Type alias for byte values. + * + * Represents a single byte of data. + */ +using Byte = uint8_t; + +/** + * @brief Type alias for size values. + * + * Used to represent sizes, lengths, and counts in. + */ +using Size = size_t; + +/** + * @brief Type alias for data storage. + * + * A simple struct that holds a pointer to a byte array and its length. + */ +struct Data { + uint8_t *mData{ nullptr }; + Size mLength{ 0 }; +}; + +/** + * @brief Type alias for const data storage. + * + * A simple struct that holds a pointer to a const byte array and its length. + */ +struct ConstData { + const uint8_t *mData{ nullptr }; + size_t mLength{ 0 }; +}; + +} // namespace Aliro + +namespace Aliro::CryptoTypes { +/** + * @brief Type alias for key identifiers. + * + * Used to uniquely identify cryptographic keys. + */ +using KeyId = uint32_t; + +/** + * @brief ECC P-256 public key prefix byte. + * + * The standard prefix byte (0x04) used to indicate an uncompressed + * ECC P-256 public key format. + */ +constexpr uint8_t kEccP256PublicKeyPrefix{ 0x04 }; + +/** + * @brief Length of the ECC P-256 public key prefix. + * + * The number of bytes used for the public key prefix. + */ +constexpr size_t kEccP256PublicKeyPrefixLength{ 1 }; + +/** + * @brief Length of a single ECC P-256 coordinate. + * + * Both x and y coordinates of an ECC P-256 public key have this length. + * This corresponds to 32 bytes (256 bits) per coordinate. + */ +constexpr size_t kEccP256KeySingleCoordinateLength{ 32 }; + +/** + * @brief Total length of an ECC P-256 public key. + * + * Calculated as: prefix (1 byte) + x coordinate (32 bytes) + y coordinate (32 bytes) + * Total: 65 bytes for an uncompressed ECC P-256 public key. + */ +constexpr size_t kEccP256PublicKeyLength{ kEccP256PublicKeyPrefixLength + (2 * kEccP256KeySingleCoordinateLength) }; + +/** + * @brief Type alias for ECC P-256 public key storage. + * + * A fixed-size array that can hold a complete ECC P-256 public key + * in uncompressed format (prefix + x coordinate + y coordinate). + */ +using PublicKey = std::array; + +} // namespace Aliro::CryptoTypes diff --git a/include/aliro/utils.h b/include/aliro/utils.h new file mode 100644 index 00000000..e4e4026c --- /dev/null +++ b/include/aliro/utils.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include + +// clang-format off +/** + * @def VerifyOrReturnStatus(expr, value, ...) + * + * @brief + * Returns a specified status code if expression evaluates to false. + * + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] value A value to return if @a expr is false. + * @param[in] ... Statements to execute before returning. Optional. Good for logging. + * + */ +#define VerifyOrReturnStatus(expr, value, ...) \ + do { \ + if (!(expr)) { \ + __VA_ARGS__; \ + return (value); \ + } \ + } while (false) + +/** + * @brief Aliases for VerifyOrReturnStatus(). + */ +#define VerifyOrReturnValue(expr, value, ...) VerifyOrReturnStatus(expr, value, ##__VA_ARGS__) +#define VerifyOrReturnFalse(expr, ...) VerifyOrReturnStatus(expr, false, ##__VA_ARGS__) +#define VerifyOrReturnTrue(expr, ...) VerifyOrReturnStatus(expr, true, ##__VA_ARGS__) + +/** + * @def VerifyOrReturn(expr, ...) + * + * @brief + * Returns from the function if expression evaluates to false. + * + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] ... Statements to execute before returning. Optional. Good for logging. + */ +// clang-format off +#define VerifyOrReturn(expr, ...) \ + do { \ + if (!(expr)) { \ + __VA_ARGS__; \ + return; \ + } \ + } while (false) + +/** + * @def VerifyOrExit(expr, value, ...) + * + * @brief + * Goes to exit if expression evaluates to false. + * + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] ... Statements to execute before exiting. Optional. Good for logging. + */ +#define VerifyOrExit(expr, ...) \ + do { \ + if (!(expr)) { \ + __VA_ARGS__; \ + goto exit; \ + } \ + } while (false) + +/** + * @def VerifyAndExit(expr, value, ...) + * + * @brief + * Goes to exit if expression evaluates to true. + * + * @param[in] expr A Boolean expression to be evaluated. + * @param[in] ... Statements to execute before exiting. Optional. Good for logging. + */ +#define VerifyAndExit(expr, ...) \ + do { \ + if (expr) { \ + __VA_ARGS__; \ + goto exit; \ + } \ + } while (false) + +/** + * @def ReturnErrorOnFailure(expr) + * + * @brief + * Returns the error code if the expression returns an error, this means any value other + * than ALIRO_NO_ERROR. + * + * Example usage: + * + * @param[in] __expr An expression to be tested. + */ +#define ReturnErrorOnFailure(__expr) \ + do { \ + auto errorCode = (__expr); \ + if (errorCode != ALIRO_NO_ERROR) { \ + return errorCode; \ + } \ + } while (false) + +/** + * @def VerifyOrDie(expr, value, ...) + * + * @brief + * Goes to exit if expression evaluates to false. + * + * @param[in] expr A Boolean expression to be evaluated. + */ +#define VerifyOrDie(expr, msg) \ + do { \ + if (!(expr)) { \ + __ASSERT(false, msg); \ + } \ + } while (false) + + +/** + * @def VerifyAndCall(clb, ...) + * + * @brief + * Calls a specific callback if it is valid. + * + * @param[in] clb A callback to be evaluated and called. + * @param[in] ... Arguments to be passed to the callback. + */ +#define VerifyAndCall(clb, ...) \ + do { \ + if (clb) { \ + clb(__VA_ARGS__); \ + } \ + } while (false) + +// clang-format on + +/** + * @brief Implemented std::to_underlying introduced in C++23. + */ +template constexpr std::underlying_type_t ToUnderlying(T e) +{ + static_assert(std::is_enum::value, "ToUnderlying called to non-enum values."); + return static_cast>(e); +} + +/** + * @brief Checks if buffer is empty. + */ +inline bool IsBufferEmpty(const uint8_t *data, size_t length) +{ + return (data == nullptr) || (length == 0); +} + +/** + * @brief Calculates the bit count based on the input bytes count. + */ +constexpr uint32_t BitsCount(uint8_t lengthInBytes) +{ + return (lengthInBytes << 3); +} + +/** + * @brief Check if a std::array is default initialized (all zeros). + * + * @param arr The array to check + * + * @return true if the array is default initialized, false otherwise + */ +template bool IsArrayDefaultInitialized(const std::array &arr) +{ + return std::all_of(arr.begin(), arr.end(), [](T x) { return x == T{}; }); +} + +/** + * @brief Custom type trait to detect std::array + * + * @tparam T The type to check + * + * @return true if the type is a std::array, false otherwise + */ +template struct IsStdArrayType : std::false_type {}; +template struct IsStdArrayType> : std::true_type {}; +template constexpr bool IsStdArray = IsStdArrayType::value; diff --git a/interfaces/crypto/backend_crypto_psa/crypto_impl.h b/interfaces/crypto/backend_crypto_psa/crypto_impl.h new file mode 100644 index 00000000..fc09ebdc --- /dev/null +++ b/interfaces/crypto/backend_crypto_psa/crypto_impl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "crypto/backend_crypto_psa/crypto_psa.h" +#include "crypto/crypto.h" + +namespace Aliro { + +class CryptoImpl final : public Crypto, public CryptoPsa { + friend class Crypto; +}; + +/* Implementation of the generic getter. */ +inline Crypto &CryptoInstance() +{ + static CryptoImpl sCrypto; + return sCrypto; +} + +} // namespace Aliro diff --git a/interfaces/crypto/backend_crypto_psa/crypto_psa.h b/interfaces/crypto/backend_crypto_psa/crypto_psa.h new file mode 100644 index 00000000..1124c7d5 --- /dev/null +++ b/interfaces/crypto/backend_crypto_psa/crypto_psa.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "crypto/crypto_common.h" +#include "crypto/crypto_key_cache.h" + +#include + +namespace Aliro { + +/** Concrete implementation of Crypto component for specific backend. */ +class CryptoPsa { +protected: + AliroError _Init(); + AliroError _GenerateRandom(Byte *rngBuf, size_t rngBufLength); + AliroError _GenerateEphemeralKeyPair(psa_key_id_t &keyId); + AliroError _ExportPublicKey(psa_key_id_t keyId, EccP256PublicKey &publicKey); + AliroError _ImportPublicKey(const EccP256PublicKey &staticPubKey, psa_key_id_t &keyId); + AliroError _ImportPrivateKey(const EccP256PrivateKey &privateKey, psa_key_id_t &privateKeyId); + AliroError _DestroyKey(psa_key_id_t &keyId) const; + AliroError _GenerateSignature(const uint8_t *msg, const size_t msgLength, TransactionSignature &signature, + psa_key_id_t privateKeyId); + AliroError _VerifySignature(const uint8_t *msg, const size_t msgLength, const TransactionSignature &signature, + psa_key_id_t spublicKeyId); + AliroError _ComputeSharedKeyDH(psa_key_id_t privKeyId, const EccP256PublicKey &publicKey, + const TransactionIdentifier &transactionId, psa_key_id_t &keyDhId); + AliroError _DeriveSessionKeys(psa_key_id_t kDh, const KdfInfo &info, const KdfSalt &salt, + SessionBoundKeys &sessionVolatileKeys); + AliroError _DeriveBleSessionKey(psa_key_id_t inputKeyId, const SharedByteSpan &info, const SharedByteSpan &salt, + psa_key_id_t &outputKeyId); + AliroError _EncryptPayload(psa_key_id_t keyId, const Byte *plainTxt, size_t plainTxtLength, + const Byte *additionalData, size_t additionalDataLength, const Nonce &nonce, + Byte *cipherText, AuthenticationTag &authTag); + AliroError _EncryptPayload(psa_key_id_t keyId, const Byte *plainTxt, size_t plainTxtLength, Byte *cipherText); + AliroError _DecryptPayload(psa_key_id_t keyId, const Byte *cipherText, size_t cipherTextLength, + const Byte *additionalData, size_t additionalDataLength, const Nonce &nonce, + Byte *plainText, size_t &plainTextLength); + AliroError _ProvisionSymmetricKey(const uint8_t *key, size_t keyLength, psa_key_id_t &keyId, + bool isPersistent = false); + AliroError _IsKeyValid(psa_key_id_t keyId) const; +}; + +} /* namespace Aliro */ diff --git a/interfaces/crypto/crypto.h b/interfaces/crypto/crypto.h new file mode 100644 index 00000000..3e0ab617 --- /dev/null +++ b/interfaces/crypto/crypto.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "crypto/crypto_key_cache.h" + +namespace Aliro { + +class CryptoImpl; + +/** + * Interface class for Crypto component. + */ +class Crypto { +public: + /** + * @brief Initialize a crypto backend. + * + * @return ALIRO_NO_ERROR on success, ALIRO_ERROR_INTERNAL otherwise. + */ + AliroError Init(); + + /** + * @brief Generate random bytes. + * + * @param rngBuf Output buffer for storing the generated bytes. + * @param rngBufLength Input number of bytes to generate. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError GenerateRandom(Byte *rngBuf, size_t rngBufLength); + + /** + * @brief Generate ephemeral EC key pair. + * + * @param keyId Output identifier for newly created keys. + * @param ephemeralPubKey Output buffer where the public key is to be copied. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError GenerateEphemeralKeyPair(uint32_t &keyId, EccP256PublicKey &ephemeralPubKey); + + /** + * @brief Generate ephemeral EC key pair. + * + * @param keyId Output identifier for newly created keys. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError GenerateEphemeralKeyPair(uint32_t &keyId); + + /** + * @brief Export EC public key. + * + * @param keyId input identifier of a private key for which the public key should be exported. + * @param ephemeralPubKey Output buffer where the public key is to be copied. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError ExportPublicKey(uint32_t keyId, EccP256PublicKey &publicKey); + + /** + * Import a EC public key. + * + * @param staticPubKey input buffer with public key. + * @param keyId output identifier of the imported key. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError ImportPublicKey(const EccP256PublicKey &staticPubKey, uint32_t &keyId); + + /** + * Import EC private key. + * + * @param privateKey input buffer with private key. + * @param privateKeyId output identifier of the imported private key. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError ImportPrivateKey(const EccP256PrivateKey &privateKey, uint32_t &privateKeyId); + + /** + * Destroy an key by ID. + * + * @param keyId identifier of a key to delete. + * NOTE: The function may set a ID to value 0. + * + * @param keyId an ID of the key to destroy. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError DestroyKey(uint32_t &keyId); + + /** + * Generate signature for a message. + * NOTE: The Reader's private key (LTK) is used for message signing. + * The key must be loaded and avialable before this method is invoked. + * + * @param msg input message to sign. + * @param msgLength input size of the message. + * @param signature output buffer where te signature is to be copied. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError GenerateSignature(const uint8_t *msg, const size_t msgLength, TransactionSignature &signature); + + /** + * Verify signature of a message. + * NOTE: The Reader's public key (LTK) is used message verify. + * The key must be loaded and avialable before this method is invoked. + * + * @param msg input message whose signature is to be verified. + * @param msgLength input size of the message. + * @param signature input signature to verify. + * + * @return ALIRO_NO_ERROR when siganture is valid, ALIRO_INVALID_SIGNATURE otherwise. + */ + AliroError VerifySignature(const uint8_t *msg, const size_t msgLength, const TransactionSignature &signature); + + /** + * Comupte shared key with ECDH procedure. + * Aliro spec chapter 8.3.1.4. + * The function agrees common key using the ECDH procedure and derives shared key. + * + * @param privKeyId input identifier of private key id to use in procedure. + * @param publicKey input user device public key to use in procedure. + * @param transacionId input Transaction identifier. + * @param keyDhId output identifier of the agreed key. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError ComputeSharedKeyDH(uint32_t privKeyId, const EccP256PublicKey &publicKey, + const TransactionIdentifier &transactionId, uint32_t &keyDhId); + + /** + * Derive session keys using Kdh. + * Aliro spec chapter 8.3.1.10 & 8.3.1.11. + * This function generates 160 bytes of derived key material and extracts from it symmetric keys: + * - ExpeditedSKReader + * - ExpeditedSKDevice + * - StepUpSK + * - BleSK + * - URSK + * + * TODO: Generate Keypersistent + * TODO: Adapt this function for 'expedited-fast' generation procedure + * + * @param kDh input identifier of the secret key. + * @param info input information for key derivation. + * @param salt input a salt for key derivation. + * @param sessionVolatileKeys output bunch of session-bound key IDs. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError DeriveSessionKeys(uint32_t kDh, const KdfInfo &info, const KdfSalt &salt, + SessionBoundKeys &sessionVolatileKeys); + + /** + * Derive 32-bytes long BLE session key according to Aliro spec. v0.9.3 11.8.1 + * + * @param inputKeyId input identifier of the secret key. + * @param info input information for key derivation. + * @param salt input a salt for key derivation. + * @param outputKeyId output identifier of the derived key. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError DeriveBleSessionKey(uint32_t inputKeyId, const SharedByteSpan &info, const SharedByteSpan &salt, + uint32_t &outputKeyId); + + /** + * Encrypt data payload. + * + * @param keyId input identifier of the key to use for encryption. + * @param plainTxt input raw paylod to encrypt. + * @param plainTxtLength input size of the payload. + * @param additionalData input a addtional data. + * @param additionalDataLength input a size of the addtional data. + * @param nonce input a nonce to use for operation. + * @param cipherText output encrypted paylod. + * @param authTag output authentication tag. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError EncryptPayload(uint32_t keyId, const Byte *plainTxt, size_t plainTxtLength, + const Byte *additionalData, size_t additionalDataLength, const Nonce &nonce, + Byte *cipherText, AuthenticationTag &authTag); + + /** + * Encrypt data payload. + * + * @param keyId input identifier of the key to use for encryption. + * @param plainTxt input raw paylod to encrypt. + * @param plainTxtLength input size of the payload. + * @param cipherText output encrypted paylod. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError EncryptPayload(uint32_t keyId, const Byte *plainTxt, size_t plainTxtLength, Byte *cipherText); + + /** + * Authenticated decryption (AEAD) data payload. + * + * @param keyId input identifier of the key to use for decryption. + * @param cipherTextWithTag input encrypted and authenticated data. The buffer must contains the encrypted data + * followed by authentication tag. + * @param cipherTextWithTagLength input size of the cipherText buffer. + * @param additionalData input a addtional data that has been authenticated but not encrypted. + * @param additionalDataLength input a size of the addtional data. + * @param nonce input a nonce to use for operation with fixed size. + * @param plainText output buffer for decrypted data. + * @param plainTextLengt input/output size of the plainText buffer. On success the size of the output after + * decryprion. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError DecryptPayload(uint32_t keyId, const Byte *cipherTextWithTag, size_t cipherTextWithTagLength, + const Byte *additionalData, size_t additionalDataLength, const Nonce &nonce, + Byte *plainText, size_t &plainTextLength); + + /** + * Authenticated decryption (AEAD) data payload. + * + * @param keyId input identifier of the key to use for decryption. + * @param cipherText input encrypted and authenticated data. The buffer must contains the encrypted data + * followed by authentication tag. + * @param cipherTextLength input size of the cipherText buffer. + * @param nonce input a nonce to use for operation with fixed size. + * @param plainText output buffer for decrypted data + * @param plainTextLengt input/output size of the plainText buffer. On success the size of the output after + * decryprion. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError DecryptPayload(uint32_t keyId, const Byte *cipherText, size_t cipherTextLength, const Nonce &nonce, + Byte *plainText, size_t &plainTextLength) + { + return DecryptPayload(keyId, cipherText, cipherTextLength, nullptr, 0U, nonce, plainText, + plainTextLength); + } + + /** + * @brief Provisions a symmetric key for cryptographic operations. + * + * This function stores a symmetric key in a secure location for future use. + * + * @param key pointer to the symmetric key data. + * @param keyLength length of the symmetric key in bytes. + * @param keyId identifier for the key to be provisioned. This ID is used + * to reference the key in subsequent operations. + * @param isPersistent flag indicating whether the key should be persistent or temporary. + * + * @return ALIRO_NO_ERROR on success, error status otherwise. + */ + AliroError ProvisionSymmetricKey(const uint8_t *key, size_t keyLength, uint32_t &keyId, + bool isPersistent = false); + + /** + * @brief Checks if a key ID exists (key is provisioned). + * + * @param keyId The key ID to check. + * + * @return ALIRO_NO_ERROR if the key available, a error code otherwise. + */ + AliroError IsKeyValid(uint32_t keyId); + +protected: + Crypto() = default; + Crypto(const Crypto &) = delete; + Crypto(Crypto &&) = delete; + ~Crypto() = default; + Crypto &operator=(const Crypto &) = delete; + Crypto &operator=(Crypto &&) = delete; + +private: + bool mInitialized{ false }; + CryptoImpl *Impl(); +}; + +extern Crypto &CryptoInstance(); + +} // namespace Aliro + +#include "crypto_impl.h" diff --git a/interfaces/logger/Kconfig b/interfaces/logger/Kconfig new file mode 100644 index 00000000..86a9202d --- /dev/null +++ b/interfaces/logger/Kconfig @@ -0,0 +1,44 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +choice NCS_ALIRO_LOG_LEVEL + prompt "Log level for Aliro module" + default NCS_ALIRO_LOG_LEVEL_DBG + +config NCS_ALIRO_LOG_LEVEL_OFF + bool "Aliro module log level set to off" + help + No logging + +config NCS_ALIRO_LOG_LEVEL_ERR + bool "Aliro module log level set to error" + help + Error logging only + +config NCS_ALIRO_LOG_LEVEL_WRN + bool "Aliro module log level set to warning" + help + Warning and error logging + +config NCS_ALIRO_LOG_LEVEL_INF + bool "Aliro module log level set to info" + help + Informational, warning and error logging + +config NCS_ALIRO_LOG_LEVEL_DBG + bool "Aliro module log level set to debug" + help + Debug, informational, warning and error logging + +endchoice + +config NCS_ALIRO_LOG_LEVEL_VALUE + int + default 0 if NCS_ALIRO_LOG_LEVEL_OFF + default 1 if NCS_ALIRO_LOG_LEVEL_ERR + default 2 if NCS_ALIRO_LOG_LEVEL_WRN + default 3 if NCS_ALIRO_LOG_LEVEL_INF + default 4 if NCS_ALIRO_LOG_LEVEL_DBG diff --git a/interfaces/logger/platform_log.h b/interfaces/logger/platform_log.h new file mode 100644 index 00000000..01ae03e5 --- /dev/null +++ b/interfaces/logger/platform_log.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#ifndef ALIRO_PLATFORM_LOG_H_ +#define ALIRO_PLATFORM_LOG_H_ + +#include +#include +#include +#include + +#define _ALIRO_LOG(level, ...) \ + do { \ + if (level <= CONFIG_NCS_ALIRO_LOG_LEVEL_VALUE) { \ + _AliroPlatformLog(level, __VA_ARGS__); \ + } \ + } while (0) + +#define _ALIRO_LOG_HEXDUMP(level, data, size, str) \ + do { \ + if (level <= CONFIG_NCS_ALIRO_LOG_LEVEL_VALUE) { \ + _AliroPlatformLogHexdump(level, data, size, str); \ + } \ + } while (0) + +#define ALIRO_LOG_ERR(...) _ALIRO_LOG(LOG_LEVEL_ERR, __VA_ARGS__) +#define ALIRO_LOG_WRN(...) _ALIRO_LOG(LOG_LEVEL_WRN, __VA_ARGS__) +#define ALIRO_LOG_INF(...) _ALIRO_LOG(LOG_LEVEL_INF, __VA_ARGS__) +#define ALIRO_LOG_DBG(...) _ALIRO_LOG(LOG_LEVEL_DBG, __VA_ARGS__) + +#define ALIRO_LOG_HEXDUMP_ERR(data, size, str) _ALIRO_LOG_HEXDUMP(LOG_LEVEL_ERR, data, size, str) +#define ALIRO_LOG_HEXDUMP_WRN(data, size, str) _ALIRO_LOG_HEXDUMP(LOG_LEVEL_WRN, data, size, str) +#define ALIRO_LOG_HEXDUMP_INF(data, size, str) _ALIRO_LOG_HEXDUMP(LOG_LEVEL_INF, data, size, str) +#define ALIRO_LOG_HEXDUMP_DBG(data, size, str) _ALIRO_LOG_HEXDUMP(LOG_LEVEL_DBG, data, size, str) + +/** + * @brief Writes a log message with the specified log level. + * @note The function is intended to be implemented by the platform. + * + * @param[in] logLevel the log level. + * @param[in] logFormat a pointer to the format string. + * @param[in] ... arguments for the format specification. + */ +void _AliroPlatformLog(uint8_t platformLogLevel, const char *logFormat, ...); + +/** + * @brief Logs binary data in hexadecimal format with the specified log level. + * @note The function is intended to be implemented by the platform. + * + * @param[in] logLevel the log level. + * @param[in] data a pointer to the data to be logged. + * @param[in] size size of the data in bytes. + * @param[in] str description string to prefix the hexdump. + */ +void _AliroPlatformLogHexdump(uint8_t platformLogLevel, const void *data, size_t size, const char *str); + +#endif // ALIRO_PLATFORM_LOG_H_ diff --git a/interfaces/transport/ble/l2cap_server_net_buf_pool.h b/interfaces/transport/ble/l2cap_server_net_buf_pool.h new file mode 100644 index 00000000..09bb2d75 --- /dev/null +++ b/interfaces/transport/ble/l2cap_server_net_buf_pool.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include + +namespace Aliro { + +/** + * @brief L2CAP server network buffer pool. + * + * Provides network buffer pool for Aliro BLE L2CAP server. + * + * Due to Zephyr API constraints, network buffer pool has to be statically + * allocated by the application. Pool size must be configured based on the + * maximum number of supported BLE sessions. + */ +extern net_buf_pool *sL2CapServerNetBufPool; + +} // namespace Aliro diff --git a/interfaces/transport/nfc/driver/interface/aliro_nfc_driver.h b/interfaces/transport/nfc/driver/interface/aliro_nfc_driver.h new file mode 100644 index 00000000..00ea7556 --- /dev/null +++ b/interfaces/transport/nfc/driver/interface/aliro_nfc_driver.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "nfc_driver_config.h" + +#include "aliro/errors.h" +#include "aliro/types.h" + +namespace Aliro { + +class NfcDriverImpl; + +/** + * @class NfcDriver + * @brief Interface class for handling NFC reader driver. + * + * NfcDriver provides an interface for NFC data exchange and control of the NFC field and detection mechanisms for a + * reader device. + */ +class NfcDriver { +public: + /** + * @struct Callbacks + * @brief Struct containing callback functions for NFC reader driver events. + * + * This struct holds pointers to functions that are called on specific NFC events. + */ + struct Callbacks { + /** Called when data is received (RX). */ + void (*mOnDataReceived)(Data, int transferError){ nullptr }; + /** Called when Tag4 is detected, anticollision is completed and ISO-DEP protocol can be activated. */ + void (*mOnTagDetected)(){ nullptr }; + /** Called on each error occurrence. */ + void (*mOnError)(AliroError){ nullptr }; + /** Called on timeout, indicating if the system is in sleep. */ + void (*mOnTimeout)(bool inSleep){ nullptr }; + }; + + /** + * @brief Initializes the NFC driver with specified callbacks. + * @param callbacks Struct containing callback functions. + * @return AliroError status of the initialization. + */ + AliroError Init(Callbacks callbacks); + + /** + * @brief Sends data via NFC to the detected tag. + * @param data Data to be sent. + * @param maximumFrameDelayTime Maximum frame delay time allowed for the transmission. + * @return AliroError status of the operation. + */ + AliroError Send(Data data, uint32_t maximumFrameDelayTime); + + /** + * @brief Enables the NFC. + * @return AliroError status of the operation. + */ + AliroError NfcOn(); + + /** + * @brief Disables the NFC. + * @return AliroError status of the operation. + */ + AliroError NfcOff(); + + /** + * @brief Restarts the NFC polling. + * @return AliroError status of the operation. + */ + AliroError RestartPolling(); + +protected: + NfcDriver() = default; + NfcDriver(const NfcDriver &) = delete; + NfcDriver(NfcDriver &&) = delete; + ~NfcDriver() = default; + NfcDriver &operator=(const NfcDriver &) = delete; + NfcDriver &operator=(NfcDriver &&) = delete; + + Callbacks mCallbacks{}; + +private: + NfcDriverImpl *Impl(); +}; + +/** + * @brief Returns the unique NfcDriver implementation object that can be used by the client code. + * @return Unique NfcDriver object reference. + */ +extern NfcDriver &NfcDriverInstance(); + +} // namespace Aliro diff --git a/interfaces/transport/nfc/isodep/interface/aliro_isodep.h b/interfaces/transport/nfc/isodep/interface/aliro_isodep.h new file mode 100644 index 00000000..a2b5335b --- /dev/null +++ b/interfaces/transport/nfc/isodep/interface/aliro_isodep.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "isodep_config.h" + +#include "aliro/errors.h" +#include "aliro/types.h" + +namespace Aliro { + +class IsoDepImpl; + +/** + * @class IsoDep + * @brief Interface class for handling NFC ISO-DEP layer. + * + * IsoDep provides an interface for NFC data exchange based on the ISO-DEP protocol. + * It allows for initialization, data preparation, and handling of ISO-DEP communication events. + */ +class IsoDep { +public: + /** + * @enum SelectStatus + * @brief Status codes for tag selection. + */ + enum SelectStatus : uint8_t { + /** Selection successful. */ + StatusOk, + /** Bitrate divisor unsupported. */ + UnsupportedBitrateDivisor + }; + + /** + * @struct Callbacks + * @brief Struct containing callback functions for NFC events. + * + * This struct holds pointers to functions that are called on specific NFC events. + */ + struct Callbacks { + /** Called when TX data is ready to be sent over the transport medium. */ + void (*mOnTxDataReady)(Data, uint32_t maxFrameDelayTime){ nullptr }; + /** Called when new processed data (RX) is available for reading. */ + void (*mOnRxDataAvailable)(Data){ nullptr }; + /** Called when a tag is selected. */ + void (*mOnTagSelected)(SelectStatus){ nullptr }; + /** Called on each error occurrence. */ + void (*mOnError)(AliroError){ nullptr }; + }; + + /** + * @brief Initializes the IsoDep component with specified callbacks. + * @param callbacks Struct containing callback functions. + * @return AliroError status of the initialization. + */ + AliroError Init(Callbacks callbacks); + + /** + * @brief Prepares data for transmission. Once data is ready to be sent, the mOnTxDataReady callback must be + * called, so that the underlying driver can send the data through the transport medium. + * @param data Data to be prepared. + * @return AliroError status of the operation. + */ + AliroError PrepareData(Data data); + + /** + * @brief Prepares the RATS (Request for Answer To Select) command payload. Once data is ready to be sent, + * the mOnTxDataReady callback must be called, so that the underlying driver can RATS command through the + * transport medium. + * @return AliroError status of the operation. + */ + AliroError PrepareRats(); + + /** + * @brief Handles the incoming data in the ISO-DEP layer. This function is supposed to be called with RX data + * forwarded from the transport medium. + * @param data Received data. + * @param transferError Error status of the data transfer. + * @return AliroError status of the operation. + */ + AliroError HandleReceivedData(Data data, int transferError); + + /** + * @brief Reports a timeout event. This function is supposed to be called to notify the ISO-DEP layer about the + * timeout that happened in the transport medium layer. + * @return AliroError status of the operation. + */ + AliroError ReportTimeout(); + +protected: + IsoDep() = default; + IsoDep(const IsoDep &) = delete; + IsoDep(IsoDep &&) = delete; + ~IsoDep() = default; + IsoDep &operator=(const IsoDep &) = delete; + IsoDep &operator=(IsoDep &&) = delete; + + Callbacks mCallbacks{}; + +private: + IsoDepImpl *Impl(); +}; + +/** + * @brief Returns the unique IsoDep implementation object that can be used by the client code. + * @return Unique IsoDep object reference. + */ +extern IsoDep &IsoDepInstance(); + +} // namespace Aliro diff --git a/interfaces/uwb/uwb.h b/interfaces/uwb/uwb.h new file mode 100644 index 00000000..e6405cd7 --- /dev/null +++ b/interfaces/uwb/uwb.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause + */ + +#pragma once + +#include "aliro/errors.h" + +#include + +namespace Aliro::Uwb { + +/** + * @class UltraWideBand + * @brief Interface class for managing ultra wideband (UWB) module and ranging session. + * + * This class provides methods to initialize, deinitialize, and manage UWB ranging sessions, + * as well as handling BLE messages and time synchronization. + */ +template class UltraWideBand { +public: + using SessionIdentifier = uint32_t; + + /** + * @struct Callbacks + * @brief Struct containing callback functions for UWB events. + * + * This struct holds pointers to functions that are called on specific UWB events, + * such as transmitting BLE messages and receiving ranging data. + */ + struct Callbacks { + /** + * @brief Callback to transmit a BLE message. + * + * This callback is invoked when the UWB module needs to send a BLE message + * as part of the Aliro protocol flow. The message must conform to the format + * specified in Table 11-10 of the Aliro specification, and the payload must stay + * unencrypted. + * + * @param userData User-defined context data. + * @param data Pointer to the formatted BLE message data. + * @param length Size of the message data in bytes. + */ + void (*mTransmitBleMessage)(void *userData, const uint8_t *data, size_t length){ nullptr }; + /** + * @brief Callback to receive ranging data. + * + * This callback is invoked when the UWB module receives ranging data. + * + * @param data Pointer to the received ranging data. + * @param length Size of the received data in bytes. + */ + void (*mRangingData)(const uint8_t *data, size_t length){ nullptr }; + }; + + /** + * @brief Initializes the UltraWideBand module. + * + * This method can be used to initialize the UWB module, setting up necessary configurations + * and preparing it for use. It should be called before any other UWB operations + * are performed. + * + * @param callbacks Struct containing callback functions for UWB events. + * + * @return ALIRO_NO_ERROR on success, or an error code on failure. + */ + AliroError Init(const Callbacks &callbacks) { return Impl()->_Init(callbacks); } + + /** + * @brief Deinitializes the UltraWideBand module. + * + * This method deinitializes the UWB hardware and releases any resources it was using. + * + * @return ALIRO_NO_ERROR on success, or an error code on failure. + */ + AliroError Deinit() { return Impl()->_Deinit(); }; + + /** + * @brief Triggers Bluetooth LE (BLE) and UWB time synchronization. + * + * This method is called just after BLE connection establishment (CONNECT_IND event). In the method + * implementaion the Procedure 0: Bluetooth LE (BLE) Timesync can be started according to the chapter 19.4.4.1 + * in Digital Key Release 3.0 Technical Specification Version 1.1.0. + * + * @note In implementation of this method for example, the GPIO pin can be used to trigger time + * synchronnization between BLE and UWB modules. + */ + void BleTimeSync() const { Impl()->_BleTimeSync(); } + + /** + * @brief Transmits deserialized and decrypted Aliro BLE messages to the UWB module. + * + * This method sends the UWB Ranging Service and Notifications (with ID == Ranging) to the UWB module. + * The message conform to the format specified in Table 11-10 of the Aliro specification, and the payload is + * decrypted. + * + * @param data Pointer to data to be transmitted. + * @param length Length of the data in bytes. + * + * @return ALIRO_NO_ERROR if the transmission was successful, an error code otherwise. + */ + AliroError HandleBleMessage(const uint8_t *data, size_t length) + { + return Impl()->_HandleBleMessage(data, length); + } + + /** + * @brief Configures the ranging session with the provided URSK in plaintext. + * + * This method sets up the ranging session using the provided URSK (UWB Ranging Secret Key). + * + * @param sessionId The session identifier for the ranging session (Chapter 11.7.2.1.3 in the Aliro spec.). + * @param ursk Pointer to the URSK. + * @param urskLen Length of the URSK in bytes. + * @param sessionUserData Pointer to user data. + * + * @return ALIRO_NO_ERROR on success, or an error code on failure. + */ + AliroError ConfigureRangingSession(SessionIdentifier sessionId, const uint8_t *ursk, size_t urskLen, + void *sessionUserData) + { + return Impl()->_ConfigureRangingSession(sessionId, ursk, urskLen, sessionUserData); + } + + /** + * @brief Initiates a UWB ranging session. + * + * This method starts a UWB ranging session by creating the M1 message and sending it + * over the BLE interface to the User Device. + * + * @return ALIRO_NO_ERROR if the session was initiated successfully, an error code otherwise. + */ + AliroError InitiateRangingSession() { return Impl()->_InitiateRangingSession(); } + + /** + * @brief Terminates the current UWB ranging session. + * + * This method terminates the current UWB ranging session and releases any resources it was using. + * + * @return ALIRO_NO_ERROR if the session was terminated successfully, an error code otherwise. + */ + AliroError TerminateRangingSession() { return Impl()->_TerminateRangingSession(); } + + /** + * @brief Suspends the current UWB ranging session. + * + * This method suspends the current UWB ranging session. It can be used to pause the session temporarily, to + * resume the session use `AliroUwbResumeRangingSession()`. + * + * @param force If true, forces the suspension even if there are ongoing operations. + * + * @return ALIRO_NO_ERROR if the session was suspended successfully, an error code otherwise. + */ + AliroError SuspendRangingSession(bool force = false) { return Impl()->_SuspendRangingSession(force); } + + /** + * @brief Resumes the suspended UWB ranging session. + * + * This method resumes the UWB ranging session that was previously suspended by + * `AliroUwbSuspendRangingSession()`. + * + * @return ALIRO_NO_ERROR if the session was resumed successfully, an error code otherwise. + */ + AliroError ResumeRangingSession() { return Impl()->_ResumeRangingSession(); } + +protected: + IfaceImpl *Impl() { return static_cast(this); } + const IfaceImpl *Impl() const { return static_cast(this); } +}; + +} // namespace Aliro::Uwb diff --git a/lib/aliro/Kconfig.ble.defconfig b/lib/aliro/Kconfig.ble.defconfig new file mode 100644 index 00000000..0dff5eee --- /dev/null +++ b/lib/aliro/Kconfig.ble.defconfig @@ -0,0 +1,44 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config BT + default y + +config BT_DEVICE_NAME + default "AliroDL" + +config BT_PERIPHERAL + default y + +config BT_SMP + default y + +config BT_USER_PHY_UPDATE + default y + +config BT_BUF_ACL_RX_SIZE + default 251 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_L2CAP_TX_MTU + default 247 + +config BT_GATT_DYNAMIC_DB + default y + +config BT_GATT_ENFORCE_SUBSCRIPTION + default y + +config BT_GATT_SERVICE_CHANGED + default y + +config BT_L2CAP_DYNAMIC_CHANNEL + default y + +config BT_CTLR_TX_PWR_DYNAMIC_CONTROL + default y if !SOC_NRF5340_CPUAPP diff --git a/lib/aliro/bin/cortex-m33/libaliro.a b/lib/aliro/bin/cortex-m33/libaliro.a old mode 100644 new mode 100755 index 2ab7184b..7eab29db Binary files a/lib/aliro/bin/cortex-m33/libaliro.a and b/lib/aliro/bin/cortex-m33/libaliro.a differ diff --git a/lib/aliro/bin/cortex-m33/libaliro_ble.a b/lib/aliro/bin/cortex-m33/libaliro_ble.a new file mode 100755 index 00000000..4f97c2a2 Binary files /dev/null and b/lib/aliro/bin/cortex-m33/libaliro_ble.a differ diff --git a/lib/aliro/bin/cortex-m4/libaliro.a b/lib/aliro/bin/cortex-m4/libaliro.a old mode 100644 new mode 100755 index 8d44dee2..938a0b62 Binary files a/lib/aliro/bin/cortex-m4/libaliro.a and b/lib/aliro/bin/cortex-m4/libaliro.a differ