From 4bd26e99129bec7d14879605226a83295264f108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Ku=C5=BAnia?= Date: Sat, 25 Feb 2023 06:18:10 +0100 Subject: [PATCH] samples: 802154_sniffer: Add 802154_sniffer sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sniffer sample allows the user to capture IEEE 802.15.4 packets in real time using the Wireshark protocol analyzer. The sample integrates with the nRF Sniffer for 802.15.4 extcap tool available on NordicSemiconductor GitHub respository. https://github.com/NordicSemiconductor/nRF-Sniffer-for-802.15.4 Signed-off-by: Rafał Kuźnia --- CODEOWNERS | 1 + doc/nrf/links.txt | 2 + .../releases/release-notes-changelog.rst | 4 + .../peripheral/802154_sniffer/CMakeLists.txt | 12 ++ samples/peripheral/802154_sniffer/README.rst | 176 ++++++++++++++++++ .../boards/nrf52840dk_nrf52840.overlay | 17 ++ .../boards/nrf52840dongle_nrf52840.overlay | 17 ++ .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 17 ++ samples/peripheral/802154_sniffer/prj.conf | 27 +++ samples/peripheral/802154_sniffer/sample.yaml | 12 ++ samples/peripheral/802154_sniffer/src/main.c | 154 +++++++++++++++ 11 files changed, 439 insertions(+) create mode 100644 samples/peripheral/802154_sniffer/CMakeLists.txt create mode 100644 samples/peripheral/802154_sniffer/README.rst create mode 100644 samples/peripheral/802154_sniffer/boards/nrf52840dk_nrf52840.overlay create mode 100644 samples/peripheral/802154_sniffer/boards/nrf52840dongle_nrf52840.overlay create mode 100644 samples/peripheral/802154_sniffer/boards/nrf5340dk_nrf5340_cpuapp.overlay create mode 100644 samples/peripheral/802154_sniffer/prj.conf create mode 100644 samples/peripheral/802154_sniffer/sample.yaml create mode 100644 samples/peripheral/802154_sniffer/src/main.c 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; +}