diff --git a/samples/dect/dect_phy/hello_dect/CMakeLists.txt b/samples/dect/dect_phy/hello_dect/CMakeLists.txt new file mode 100644 index 000000000000..001ac71af9b3 --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2024 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(hello_dect) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/dect/dect_phy/hello_dect/Kconfig b/samples/dect/dect_phy/hello_dect/Kconfig new file mode 100644 index 000000000000..147be4c7edcf --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/Kconfig @@ -0,0 +1,52 @@ +# +# Copyright (c) 2024 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config CARRIER + int "Carrier to use" + default 0 + help + The availability of the channels and the exact regulation to use them varies in different countries. + See ETSI TS 103 636-2 5.4.2 for the calculation. + +config NETWORK_ID + int "Network ID" + range 1 4294967295 + default 91 + +config MCS + int "MCS" + default 1 + help + The MCS impacts how much data can fit into each subslot. + +config TX_POWER + int "TX power" + range 0 11 + default 11 + help + Transmission power, see table 6.2.1-3 of ETSI TS 103 636-4. + +config TX_TRANSMISSIONS + int "TX transmissions" + range 0 4294967295 + default 30 + help + Transmissions before sample exits, use 0 to transmit forever. + +config RX_PERIOD_S + int "RX period" + default 5 + help + Receive window period. + Time is given in seconds. + +module = DECT_PHY_HELLO +module-str = DECT NR+ PHY Hello +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + +menu "Zephyr Kernel" +source "Kconfig.zephyr" +endmenu diff --git a/samples/dect/dect_phy/hello_dect/README.rst b/samples/dect/dect_phy/hello_dect/README.rst new file mode 100644 index 000000000000..a7cadea4df2c --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/README.rst @@ -0,0 +1,128 @@ +.. _nrf_modem_dect_phy_hello: + +nRF91x1: DECT NR+ PHY hello sample +################################## + +.. contents:: + :local: + :depth: 2 + +The sample demonstrates how to set up a simple DECT NR+ application with the DECT PHY modem firmware. + +Requirements +************ + +The sample needs at least two nRF91x1 Development Kits. + +See :ref:`nrf91x1_ug_intro` for more details. + +.. note:: + + The :ref:`nrf_modem_dect_phy_simple` sample requires the DECT NR+ PHY modem firmware to run on the nRF91x1 modem core. Please contact our sales department to know more. + +.. include:: /includes/tfm.txt + +Overview +******** + +The sample shows a simple broadcast and reception of DECT NR+ messages between devices on a hard-coded channel. + +After initialization the devices will run a loop, transmitting a counter value before listening for incoming receptions. The time to listen is given by the :kconfig:option:`CONFIG_RX_PERIOD_S` Kconfig option. +The loop is exited after a number of transmissions given by the :kconfig:option:`CONFIG_TX_TRANSMISSIONS` Kconfig option, or continue forever if the :kconfig:option:`CONFIG_TX_TRANSMISSIONS` Kconfig option is ``0``. + +Each device can be reset to run the sample again. + +Building and running +******************** + +.. |sample path| replace:: :file:`samples/modem_trace_flash` + +.. include:: /includes/build_and_run_ns.txt + +.. important:: + + DECT NR+ operates on free but regulated radio channels. The regulations and availability of the channels varies by countries and regions. + It is your responsibility to operate the devices according to the local regulation, both at the development site and the device operating regions. + If you are in the EU and US, you can use the ``overlay-eu.conf`` and ``overlay-us.conf``Kconfig overlays respectively. + Otherwise set the carrier using the :kconfig:option:`CONFIG_CARRIER` Kconfig option. + +Testing +======= + +|test_sample| + +After programming the sample to your Development Kits, test it by performing the following steps: + +#. |connect_kit| +#. |connect_terminal| +#. Observe that the devices will transmit a counter value that is received by the other devices. +#. After a given number of transmissions, observe that the devices shut down and exit the sample. + +Sample output +============= + +The sample shows an output similar to the following: + +Device 1: + +.. code-block:: console + + *** Booting nRF Connect SDK v3.5.99-ncs1 *** + [00:00:00.378,784] app: Dect NR+ PHY Hello sample started + [00:00:00.691,375] app: Dect NR+ PHY initialized, device ID: 12345 + [00:00:00.691,406] app: Transmitting 0 + [00:00:05.697,784] app: Transmitting 1 + [00:00:10.704,193] app: Transmitting 2 + [00:00:14.186,553] app: Received header from device ID 67890 + [00:00:14.186,889] app: Received data (RSSI: -54.5): Hello DECT! 0 + [00:00:15.710,571] app: Transmitting 3 + [00:00:19.192,932] app: Received header from device ID 67890 + [00:00:19.193,267] app: Received data (RSSI: -54.5): Hello DECT! 1 + [00:00:20.716,949] app: Transmitting 4 + ... + [00:02:24.352,661] app: Received header from device ID 67890 + [00:02:24.352,996] app: Received data (RSSI: -54.5): Hello DECT! 26 + [00:02:25.876,739] app: Transmitting 29 + [00:02:25.876,831] app: Reached maximum number of transmissions (30) + [00:02:25.876,831] app: Shutting down + [00:02:25.893,554] app: Bye! + +Device 2: + +.. code-block:: console + + *** Booting nRF Connect SDK v3.5.99-ncs1 *** + [00:00:00.407,287] app: Dect NR+ PHY Hello sample started + [00:00:00.719,238] app: Dect NR+ PHY initialized, device ID: 67890 + [00:00:00.719,268] app: Transmitting 0 + [00:00:02.254,211] app: Received header from device ID 12345 + [00:00:02.254,547] app: Received data (RSSI: -54.5): Hello DECT! 3 + [00:00:05.725,646] app: Transmitting 1 + [00:00:07.260,620] app: Received header from device ID 12345 + [00:00:07.260,955] app: Received data (RSSI: -54.5): Hello DECT! 4 + ... + [00:02:10.885,284] app: Transmitting 26 + [00:02:12.420,318] app: Received header from device ID 12345 + [00:02:12.420,654] app: Received data (RSSI: -54.5): Hello DECT! 29 + [00:02:15.891,693] app: Transmitting 27 + [00:02:20.898,071] app: Transmitting 28 + [00:02:25.904,449] app: Transmitting 29 + [00:02:25.904,541] app: Reached maximum number of transmissions (30) + [00:02:25.904,571] app: Shutting down + [00:02:25.921,325] app: Bye! + +Dependencies +************ + +It uses the following `sdk-nrfxlib`_ libraries: + +* :ref:`nrfxlib:nrf_modem` + +It uses the following Zephyr libraries: + +* :ref:`zephyr:uart_api` + + +In addition, it uses the following secure firmware components: + +* :ref:`Trusted Firmware-M ` diff --git a/samples/dect/dect_phy/hello_dect/overlay-eu.conf b/samples/dect/dect_phy/hello_dect/overlay-eu.conf new file mode 100644 index 000000000000..fd71e5f1617d --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/overlay-eu.conf @@ -0,0 +1 @@ +CONFIG_CARRIER=1702 diff --git a/samples/dect/dect_phy/hello_dect/overlay-us.conf b/samples/dect/dect_phy/hello_dect/overlay-us.conf new file mode 100644 index 000000000000..321322186a17 --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/overlay-us.conf @@ -0,0 +1 @@ +CONFIG_CARRIER=1677 diff --git a/samples/dect/dect_phy/hello_dect/prj.conf b/samples/dect/dect_phy/hello_dect/prj.conf new file mode 100644 index 000000000000..ec004a088ed1 --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/prj.conf @@ -0,0 +1,6 @@ +CONFIG_NRF_MODEM_LIB=y + +CONFIG_NRF_MODEM_LINK_BINARY_DECT_PHY=y +CONFIG_HWINFO=y + +CONFIG_LOG=y diff --git a/samples/dect/dect_phy/hello_dect/sample.yaml b/samples/dect/dect_phy/hello_dect/sample.yaml new file mode 100644 index 000000000000..8d1f3595cd07 --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: Dect NR+ PHY Hello +tests: + sample.nrf9161.dect_phy_hello: + build_only: true + integration_platforms: + - nrf9161dk_nrf9161_ns + platform_allow: nrf9161dk_nrf9161_ns + tags: ci_build diff --git a/samples/dect/dect_phy/hello_dect/src/main.c b/samples/dect/dect_phy/hello_dect/src/main.c new file mode 100644 index 000000000000..3222ca78e501 --- /dev/null +++ b/samples/dect/dect_phy/hello_dect/src/main.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(app); + +BUILD_ASSERT(CONFIG_CARRIER, "Carrier must be configured according to local regulations"); + +#define DATA_LEN_MAX 32 + +static bool exit; +static uint16_t device_id; + +/* Header type 1 */ +struct phy_ctrl_field_common { + uint32_t packet_length : 4; + uint32_t packet_length_type : 1; + uint32_t header_format : 3; + uint32_t short_network_id : 8; + uint32_t transmitter_id_hi : 8; + uint32_t transmitter_id_lo : 8; + uint32_t df_mcs : 3; + uint32_t reserved : 1; + uint32_t transmit_power : 4; + uint32_t pad : 24; +}; + +/* Semaphore to synchronize modem calls. */ +K_SEM_DEFINE(operation_sem, 0, 1); + +/* Callback after init operation. */ +static void init(const uint64_t *time, int16_t temp, enum nrf_modem_dect_phy_err err, + const struct nrf_modem_dect_phy_modem_cfg *cfg) +{ + if (err) { + LOG_ERR("Init failed, err %d", err); + exit = true; + return; + } + + k_sem_give(&operation_sem); +} + +/* Callback after deinit operation. */ +static void deinit(const uint64_t *time, enum nrf_modem_dect_phy_err err) +{ + if (err) { + LOG_ERR("Deinit failed, err %d", err); + return; + } + + k_sem_give(&operation_sem); +} + +/* Operation complete notification. */ +static void op_complete(const uint64_t *time, int16_t temperature, + enum nrf_modem_dect_phy_err err, uint32_t handle) +{ + LOG_DBG("Operation %d has completed with result %d", handle, err); + k_sem_give(&operation_sem); +} + +/* Callback after receive stop operation. */ +static void rx_stop(const uint64_t *time, enum nrf_modem_dect_phy_err err, uint32_t handle) +{ + LOG_DBG("operation_stop_cb Status %d Handle %d", err, handle); + k_sem_give(&operation_sem); +} + +/* Physical Control Channel reception notification. */ +static void pcc( + const uint64_t *time, + const struct nrf_modem_dect_phy_rx_pcc_status *status, + const union nrf_modem_dect_phy_hdr *hdr) +{ + struct phy_ctrl_field_common *header = (struct phy_ctrl_field_common *)hdr->type_1; + + LOG_INF("Received header from device ID %d", + header->transmitter_id_hi << 8 | header->transmitter_id_lo); +} + +/* Physical Control Channel CRC error notification. */ +static void pcc_crc_err(const uint64_t *time, + const struct nrf_modem_dect_phy_rx_pcc_crc_failure *crc_failure) +{ + LOG_DBG("PCC CRC error"); +} + +/* Physical Data Channel reception notification. */ +static void pdc(const uint64_t *time, + const struct nrf_modem_dect_phy_rx_pdc_status *status, + const void *data, uint32_t len) +{ + /* Received RSSI value is in fixed precision format Q14.1 */ + LOG_INF("Received data (RSSI: %d.%d): %s", + (status->rssi_2 / 2), (status->rssi_2 & 0b1) * 5, (char *)data); +} + +/* Physical Data Channel CRC error notification. */ +static void pdc_crc_err( + const uint64_t *time, const struct nrf_modem_dect_phy_rx_pdc_crc_failure *crc_failure) +{ + LOG_DBG("PDC CRC error"); +} + +/* RSSI measurement result notification. */ +static void rssi(const uint64_t *time, const struct nrf_modem_dect_phy_rssi_meas *status) +{ + LOG_DBG("RSSI measurement for carrier %d", status->carrier); +} + +/* Callback after link configuration operation. */ +static void link_config(const uint64_t *time, enum nrf_modem_dect_phy_err err) +{ + LOG_DBG("Link configuration callback"); +} + +/* Callback after time query operation. */ +static void time_get(const uint64_t *time, enum nrf_modem_dect_phy_err err) +{ + LOG_DBG("time_query_cb time %"PRIu64" Status %d", *time, err); +} + +/* Callback after capability get operation. */ +static void capability_get(const uint64_t *time, enum nrf_modem_dect_phy_err err, + const struct nrf_modem_dect_phy_capability *capability) +{ + LOG_DBG("capability_get time %"PRIu64" Status %d", *time, err); +} + +/* Dect PHY callbacks. */ +static struct nrf_modem_dect_phy_callbacks dect_phy_callbacks = { + .init = init, + .deinit = deinit, + .op_complete = op_complete, + .rx_stop = rx_stop, + .pcc = pcc, + .pcc_crc_err = pcc_crc_err, + .pdc = pdc, + .pdc_crc_err = pdc_crc_err, + .rssi = rssi, + .link_config = link_config, + .time_get = time_get, + .capability_get = capability_get, +}; + +/* Dect PHY init parameters. */ +static struct nrf_modem_dect_phy_init_params dect_phy_init_params = { + .harq_rx_expiry_time_us = 5000000, + .harq_rx_process_count = 4, +}; + +/* Send operation. */ +static int transmit(uint32_t handle, void *data, size_t data_len) +{ + int err; + + struct phy_ctrl_field_common header = { + .header_format = 0x0, + .packet_length_type = 0x0, + .packet_length = 0x01, + .short_network_id = (CONFIG_NETWORK_ID & 0xff), + .transmitter_id_hi = (device_id >> 8), + .transmitter_id_lo = (device_id & 0xff), + .transmit_power = CONFIG_TX_POWER, + .reserved = 0, + .df_mcs = CONFIG_MCS, + }; + + struct nrf_modem_dect_phy_tx_params tx_op_params = { + .start_time = 0, + .handle = handle, + .network_id = CONFIG_NETWORK_ID, + .phy_type = 0, + .lbt_rssi_threshold_max = 0, + .carrier = CONFIG_CARRIER, + .lbt_period = NRF_MODEM_DECT_LBT_PERIOD_MAX, + .phy_header = (union nrf_modem_dect_phy_hdr *)&header, + .data = data, + .data_size = data_len, + }; + + err = nrf_modem_dect_phy_tx(&tx_op_params); + if (err != 0) { + return err; + } + + return 0; +} + +/* Receive operation. */ +static int receive(uint32_t handle) +{ + int err; + + struct nrf_modem_dect_phy_rx_params rx_op_params = { + .start_time = 0, + .handle = handle, + .network_id = CONFIG_NETWORK_ID, + .mode = NRF_MODEM_DECT_PHY_RX_MODE_CONTINUOUS, + .rssi_interval = NRF_MODEM_DECT_PHY_RSSI_INTERVAL_OFF, + .link_id = NRF_MODEM_DECT_PHY_LINK_UNSPECIFIED, + .rssi_level = -60, + .carrier = CONFIG_CARRIER, + .duration = CONFIG_RX_PERIOD_S * MSEC_PER_SEC * + NRF_MODEM_DECT_MODEM_TIME_TICK_RATE_KHZ, + .filter.short_network_id = CONFIG_NETWORK_ID & 0xff, + .filter.is_short_network_id_used = 1, + /* listen for everything (broadcast mode used) */ + .filter.receiver_identity = 0, + }; + + err = nrf_modem_dect_phy_rx(&rx_op_params); + if (err != 0) { + return err; + } + + return 0; +} + +int main(void) +{ + int err; + uint32_t tx_handle = 0; + uint32_t rx_handle = 1; + uint32_t tx_counter_value = 0; + uint8_t tx_buf[DATA_LEN_MAX]; + size_t tx_len; + + LOG_INF("Dect NR+ PHY Hello sample started"); + + err = nrf_modem_lib_init(); + if (err) { + LOG_ERR("modem init failed, err %d", err); + return err; + } + + err = nrf_modem_dect_phy_callback_set(&dect_phy_callbacks); + if (err) { + LOG_ERR("nrf_modem_dect_phy_callback_set failed, err %d", err); + return err; + } + + err = nrf_modem_dect_phy_init(&dect_phy_init_params); + if (err) { + LOG_ERR("nrf_modem_dect_phy_init failed, err %d", err); + return err; + } + + k_sem_take(&operation_sem, K_FOREVER); + if (exit) { + return -EIO; + } + + hwinfo_get_device_id((void *)&device_id, sizeof(device_id)); + + LOG_INF("Dect NR+ PHY initialized, device ID: %d", device_id); + + while (1) { + /** Transmitting message */ + LOG_INF("Transmitting %d", tx_counter_value); + tx_len = sprintf(tx_buf, "Hello DECT! %d", tx_counter_value); + + err = transmit(tx_handle, tx_buf, tx_len); + if (err) { + LOG_ERR("Transmisstion failed, err %d", err); + return err; + } + + tx_counter_value++; + + if ((tx_counter_value >= CONFIG_TX_TRANSMISSIONS) && CONFIG_TX_TRANSMISSIONS) { + LOG_INF("Reached maximum number of transmissions (%d)", + CONFIG_TX_TRANSMISSIONS); + break; + } + + /* Wait for TX operation to complete. */ + k_sem_take(&operation_sem, K_FOREVER); + + /** Receiving messages for CONFIG_RX_PERIOD_S seconds. */ + err = receive(rx_handle); + if (err) { + LOG_ERR("Reception failed, err %d", err); + return err; + } + + /* Wait for RX operation to complete. */ + k_sem_take(&operation_sem, K_FOREVER); + } + + LOG_INF("Shutting down"); + + err = nrf_modem_dect_phy_deinit(); + if (err) { + LOG_ERR("nrf_modem_dect_phy_deinit() failed, err %d", err); + return err; + } + + k_sem_take(&operation_sem, K_FOREVER); + + err = nrf_modem_lib_shutdown(); + if (err) { + LOG_ERR("nrf_modem_lib_shutdown() failed, err %d", err); + return err; + } + + LOG_INF("Bye!"); + + return 0; +}