diff --git a/CODEOWNERS b/CODEOWNERS index e55da3592cc6..69942936480b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -173,6 +173,7 @@ Kconfig* @tejlmand /samples/peripheral/radio_test/ @KAGA164 @maje-emb /samples/peripheral/lpuart/ @nordic-krch /samples/peripheral/802154_phy_test/ @ankuns @jciupis @ahasztag +/samples/peripheral/802154_sniffer/ @e-rk /samples/tfm/ @frkv @Vge0rge @vili-nordic @joerchan @SebastianBoe @mswarowsky /samples/zigbee/ @tomchy @sebastiandraus /samples/CMakeLists.txt @tejlmand diff --git a/doc/nrf/links.txt b/doc/nrf/links.txt index 00b429c261f4..42fcb1a9df21 100644 --- a/doc/nrf/links.txt +++ b/doc/nrf/links.txt @@ -1247,3 +1247,5 @@ .. _`IEEE 802.11 Working Group`: https://www.ieee802.org/11/ .. _`Samsung SmartThings integration with Matter`: https://support.smartthings.com/hc/en-us/articles/11219700390804-SmartThings-x-Matter-Integration- + +.. _`Wireshark`: https://www.wireshark.org diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 45da6e641401..6332b2317818 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -438,6 +438,10 @@ Other samples * Aligned the timer's configuration to the new nrfx API. +* :ref:`802154_sniffer` sample: + + * Added the 802.15.4 sniffer sample. + Drivers ======= diff --git a/samples/peripheral/802154_sniffer/CMakeLists.txt b/samples/peripheral/802154_sniffer/CMakeLists.txt new file mode 100644 index 000000000000..7179b17ec12f --- /dev/null +++ b/samples/peripheral/802154_sniffer/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2023 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(802154_sniffer) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/peripheral/802154_sniffer/README.rst b/samples/peripheral/802154_sniffer/README.rst new file mode 100644 index 000000000000..a8b6e09f6277 --- /dev/null +++ b/samples/peripheral/802154_sniffer/README.rst @@ -0,0 +1,176 @@ +.. _802154_sniffer: + +IEEE 802.15.4 Sniffer +##################### + +.. contents:: + :local: + :depth: 2 + +The IEEE 802.15.4 Sniffer listens to a selected IEEE 802.15.4 channel (2.4GHz O-QPSK with DSSS) and integrates with the nRF 802.15.4 sniffer extcap for Wireshark. + +Requirements +************ + +The sample supports the following development kits: + +.. table-from-sample-yaml:: + +The application can be used with the `nRF Sniffer for 802.15.4`_ extcap utility for the `Wireshark`_ network protocol analyzer. + +Overview +******** + +The application presents the user with a command-line interface. + +See the :ref:`802154_sniffer_commands` for the list of the available commands. + +LED 1: + When the capture is stopped the LED blinks with a period of 2 seconds with 50% duty cycle. + When the capture is ongoing the LED blinks with a period of 0.5 seconds with 50% duty cycle. + +LED 4: + When the sniffer captures a packet the LED is toggled on and off. + +.. _802154_sniffer_commands: + +Serial commands list +******************** + +This section lists the serial commands that are supported by the sample. + +channel - Change the radio channel +================================== + +The command changes the IEEE 802.15.4 radio channel to listen on. + + .. parsed-literal:: + :class: highlight + + channel ** + +The ```` argument is an integer in the range between 11 and 26. + +For example: + + .. parsed-literal:: + :class: highlight + + channel *23* + +receive - start capturing packets +================================= + +The ``receive`` command makes the sniffer enter the RX state and start capturing packets. + + .. parsed-literal:: + :class: highlight + + receive + +The received packets will be printed to the command-line with the following format: + + .. parsed-literal:: + :class: highlight + + received: ** power: ** lqi: ** time: ** + +* The ```` is a hexidecimal string representation of the received packet. +* The ```` value is the signal power in dBm. +* The ```` value is the IEEE 802.15.4 Link Quality Indicator. +* The ```` value is the absolute time of the received packet since the sniffer booted. + +sleep - stop capturing packets +============================== + +The ``sleep`` command disables the radio and ends the receive process. + + .. parsed-literal:: + :class: highlight + + sleep + +Configuration +************* + +|config| + +Building and running +******************** + +.. |sample path| replace:: :file:`samples/peripheral/802154_sniffer` + +.. include:: /includes/build_and_run.txt + +.. _802154_sniffer_testing: + +Testing the sample +================== + +After programming the sample to your development kit, complete the following steps to test it: + +1. Connect the development kit to the computer using a USB cable. + Use the development kit's nRF USB port (**J3**). + The kits are assigned a COM port (in Windows) or a ttyACM device (in Linux), visible in the Device Manager or in the :file:`/dev` directory. +#. |connect_terminal| +#. Switch to a radio channel with an ongoing radio traffic: + + .. parsed-literal:: + :class: highlight + + channel *23* + +#. Start the capture process: + + .. parsed-literal:: + :class: highlight + + receive + + The **LED 1** will start blinking with shorter intervals. + +#. If there is radio traffic on the selected channel, the sniffer should print the captured packets: + + .. parsed-literal:: + :class: highlight + + received: 49a85d41a5fffff4110f10270000369756e65619d09428a04b301951821db234460aa5ec4ff506631ef8adb22674683700 power: -39 lqi: 220 time: 15822687 + + The **LED 4** will toggle its state when a frame is received. + +#. Disable the capture: + + .. parsed-literal:: + :class: highlight + + sleep + + The **LED 1** will start blinking with longer intervals. + +Dependencies +************ + +This sample uses the following `sdk-nrfxlib`_ libraries: + +* :ref:`nrfxlib:mpsl` +* :ref:`nrfxlib:nrf_802154` + +This sample uses the following |NCS| libraries: + +* :ref:`dk_buttons_and_leds_readme` + +This sample uses the following Zephyr libraries: + +* :ref:`zephyr:kernel_api`: + + * :file:`include/zephyr/kernel.h` + * :file:`include/zephyr/sys/util.h` + +* :ref:`zephyr:ieee802154_interface`: + + * :file:`include/zephyr/net/ieee802154_radio.h` + +* :ref:`zephyr:shell_api`: + + * :file:`include/zephyr/shell/shell.h` + * :file:`include/zephyr/shell/shell_uart.h` diff --git a/samples/peripheral/802154_sniffer/boards/nrf52840dk_nrf52840.overlay b/samples/peripheral/802154_sniffer/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 000000000000..5aa8cee9915a --- /dev/null +++ b/samples/peripheral/802154_sniffer/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,shell-uart = &cdc_acm_uart0; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/samples/peripheral/802154_sniffer/boards/nrf52840dongle_nrf52840.overlay b/samples/peripheral/802154_sniffer/boards/nrf52840dongle_nrf52840.overlay new file mode 100644 index 000000000000..5aa8cee9915a --- /dev/null +++ b/samples/peripheral/802154_sniffer/boards/nrf52840dongle_nrf52840.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,shell-uart = &cdc_acm_uart0; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/samples/peripheral/802154_sniffer/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/peripheral/802154_sniffer/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000..5aa8cee9915a --- /dev/null +++ b/samples/peripheral/802154_sniffer/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,shell-uart = &cdc_acm_uart0; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/samples/peripheral/802154_sniffer/prj.conf b/samples/peripheral/802154_sniffer/prj.conf new file mode 100644 index 000000000000..e668edcc1e36 --- /dev/null +++ b/samples/peripheral/802154_sniffer/prj.conf @@ -0,0 +1,27 @@ +# Enabling radio driver +CONFIG_NETWORKING=y +CONFIG_IEEE802154=y +CONFIG_IEEE802154_RAW_MODE=y +CONFIG_NET_PKT_TIMESTAMP=y + +# Allow sharing the RTC between IEEE 802.15.4 and Zephyr +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=3 + +# Shell configuration +CONFIG_SHELL=y +CONFIG_SHELL_PROMPT_UART="" +CONFIG_SHELL_VT100_COLORS=n + +# LED indication +CONFIG_DK_LIBRARY=y + +# USB configuration +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor ASA" +CONFIG_USB_DEVICE_PRODUCT="nRF 802154 Sniffer" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x154b +CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR=y +CONFIG_UART_LINE_CTRL=y +CONFIG_SHELL_BACKEND_SERIAL_INIT_PRIORITY=51 +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y diff --git a/samples/peripheral/802154_sniffer/sample.yaml b/samples/peripheral/802154_sniffer/sample.yaml new file mode 100644 index 000000000000..e1100b9e705d --- /dev/null +++ b/samples/peripheral/802154_sniffer/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: IEEE 802.15.4 Sniffer sample + name: IEEE 802.15.4 Sniffer +tests: + sample.peripheral.802154_sniffer: + build_only: true + integration_platforms: + - nrf52840dk_nrf52840 + - nrf52840dongle_nrf52840 + - nrf5340dk_nrf5340_cpuapp + platform_allow: nrf52840dk_nrf52840 nrf52840dongle_nrf52840 nrf5340dk_nrf5340_cpuapp + tags: ci_build diff --git a/samples/peripheral/802154_sniffer/src/main.c b/samples/peripheral/802154_sniffer/src/main.c new file mode 100644 index 000000000000..ebb82664f524 --- /dev/null +++ b/samples/peripheral/802154_sniffer/src/main.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HEX_STRING_LENGTH (2 * MAX_PACKET_SIZE + 1) + +static const struct device *radio_dev = + DEVICE_DT_GET(DT_CHOSEN(zephyr_ieee802154)); +static struct ieee802154_radio_api *radio_api; +static const struct shell *uart_shell; +static char hex_string[HEX_STRING_LENGTH]; +static bool heartbeat_led_state; +static bool packet_led_state; +static k_timeout_t heartbeat_interval; + +static void heartbeat(struct k_work *work); + +static K_WORK_DELAYABLE_DEFINE(heartbeat_work, heartbeat); + +static void heartbeat(struct k_work *work) +{ + ARG_UNUSED(work); + + heartbeat_led_state = !heartbeat_led_state; + dk_set_led(DK_LED1, heartbeat_led_state); + k_work_reschedule(&heartbeat_work, heartbeat_interval); +} + +enum net_verdict ieee802154_handle_ack(struct net_if *iface, + struct net_pkt *pkt) +{ + ARG_UNUSED(iface); + ARG_UNUSED(pkt); + + return NET_DROP; +} + +int net_recv_data(struct net_if *iface, struct net_pkt *pkt) +{ + if (!pkt) { + return -EINVAL; + } + + if (net_pkt_is_empty(pkt)) { + return -ENODATA; + } + + uint8_t *psdu = net_buf_frag_last(pkt->buffer)->data; + size_t length = net_buf_frags_len(pkt->buffer); + uint8_t lqi = net_pkt_ieee802154_lqi(pkt); + int8_t rssi = net_pkt_ieee802154_rssi(pkt); + struct net_ptp_time *pkt_time = net_pkt_timestamp(pkt); + uint64_t timestamp = + pkt_time->second * USEC_PER_SEC + pkt_time->nanosecond / NSEC_PER_USEC; + + packet_led_state = !packet_led_state; + dk_set_led(DK_LED4, packet_led_state); + bin2hex(psdu, length, hex_string, HEX_STRING_LENGTH); + + shell_print(uart_shell, + "received: %s power: %d lqi: %u time: %llu", + hex_string, + rssi, + lqi, + timestamp); + + net_pkt_unref(pkt); + + return 0; +} + +static int cmd_channel(const struct shell *shell, size_t argc, char **argv) +{ + uint32_t channel; + + switch (argc) { + case 1: + shell_print(shell, "%d", nrf_802154_channel_get()); + break; + case 2: + channel = atoi(argv[1]); + radio_api->set_channel(radio_dev, channel); + break; + default: + shell_print(shell, "invalid number of parameters: %d", argc); + break; + } + + return 0; +} +SHELL_CMD_ARG_REGISTER(channel, NULL, "Set radio channel", cmd_channel, 1, 1); + +static int cmd_receive(const struct shell *shell, size_t argc, char **argv) +{ + ARG_UNUSED(shell); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + heartbeat_interval = K_MSEC(250); + radio_api->start(radio_dev); + + return 0; +} +SHELL_CMD_ARG_REGISTER(receive, NULL, "Put radio in receive state", cmd_receive, 1, 0); + +static int cmd_sleep(const struct shell *shell, size_t argc, char **argv) +{ + ARG_UNUSED(shell); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + heartbeat_interval = K_SECONDS(1); + radio_api->stop(radio_dev); + + return 0; +} +SHELL_CMD_ARG_REGISTER(sleep, NULL, "Disable the radio", cmd_sleep, 1, 0); + +int main(void) +{ + (void) dk_leds_init(); + + uart_shell = shell_backend_uart_get_ptr(); + heartbeat_interval = K_SECONDS(1); + k_work_reschedule(&heartbeat_work, heartbeat_interval); + + struct ieee802154_config config = { + .promiscuous = true + }; + + radio_api = (struct ieee802154_radio_api *)radio_dev->api; + __ASSERT_NO_MSG(radio_api); + +#if !IS_ENABLED(CONFIG_NRF_802154_SERIALIZATION) + /* The serialization API does not support disabling the auto-ack. */ + nrf_802154_auto_ack_set(false); +#endif + + radio_api->configure(radio_dev, IEEE802154_CONFIG_PROMISCUOUS, &config); + + return 0; +}