Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/bluetooth/central_uart/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ project(central_uart)
# NORDIC SDK APP START
target_sources(app PRIVATE
src/main.c
src/leds.c
)
# NORDIC SDK APP END
19 changes: 19 additions & 0 deletions samples/bluetooth/central_uart/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ When you plug the dongle into a USB port, the following interfaces are available
- NUS
- Nordic UART Service

User interface
**************

.. tabs::

.. group-tab:: nRF54LM20 Dongle

Green LED:
Lit when connected over Bluetooth LE.
Blinks briefly when data is sent or received over Bluetooth LE.

Blue LED:
Blinks when debug messages are emitted.

.. group-tab:: Other supported boards

See the list of supported boards in :ref:`central_uart_requirements`.
No buttons and LEDs are used.

.. _central_uart_debug:

Debugging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
# The sample requires UART async API that is not supported by the USB CDC ACM UART driver yet.
# Hence we need the UART async adapter as the intermediate layer.
CONFIG_UART_ASYNC_ADAPTER=y

# Indicate BLE traffic and log activity using LEDs.
CONFIG_GPIO=y
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
/ {
chosen {
zephyr,shell-uart = &nus_cdc_acm_uart;
nordic,central-uart-ble-led = &led0_green;
nordic,central-uart-log-led = &led0_blue;
};
};

Expand Down
167 changes: 167 additions & 0 deletions samples/bluetooth/central_uart/src/leds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2026 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include "leds.h"

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/logging/log_backend.h>
#include <zephyr/logging/log_msg.h>
#include <zephyr/sys/__assert.h>

#define LED_BLINK_MS 50
#define LED_BLINK_COUNT 10

LOG_MODULE_DECLARE(central_uart);

#if DT_HAS_CHOSEN(nordic_central_uart_ble_led)

static const struct gpio_dt_spec ble_led =
GPIO_DT_SPEC_GET(DT_CHOSEN(nordic_central_uart_ble_led), gpios);
static bool ble_connected;
static uint8_t ble_led_blink_remaining;
static void ble_led_blink_handler(struct k_timer *timer);
static K_TIMER_DEFINE(ble_led_blink_timer, ble_led_blink_handler, NULL);

static void ble_led_blink_handler(struct k_timer *timer)
{
int rc;

if (ble_led_blink_remaining > 0) {
ble_led_blink_remaining--;
rc = gpio_pin_toggle_dt(&ble_led);
} else {
k_timer_stop(timer);
rc = gpio_pin_set_dt(&ble_led, 1);
}

__ASSERT_NO_MSG(rc == 0);
}

void leds_init(void)
{
int rc;

if (!gpio_is_ready_dt(&ble_led)) {
LOG_WRN("BLE LED not ready");
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no log in this module, also all functions in leds.h are void. Please consider some logging on fails.
Readme says nRF54LM20 Dongle The sample uses the CDC ACM interface with index 0 for debug logging

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like me to check all error codes, such as k_timer_stop, k_timer_start and such or are you interested in specific ones?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some logs and asserts here and there.

}

rc = gpio_pin_configure_dt(&ble_led, GPIO_OUTPUT_INACTIVE);
__ASSERT_NO_MSG(rc == 0);
}

void leds_set_ble_connected(bool connected)
{
int rc;

if (!gpio_is_ready_dt(&ble_led)) {
return;
}

k_timer_stop(&ble_led_blink_timer);

ble_connected = connected;
rc = gpio_pin_set_dt(&ble_led, connected ? 1 : 0);
__ASSERT_NO_MSG(rc == 0);
}

void leds_indicate_ble_traffic(void)
{
if (!gpio_is_ready_dt(&ble_led) || !ble_connected) {
return;
}

k_timer_stop(&ble_led_blink_timer);

ble_led_blink_remaining = LED_BLINK_COUNT;
k_timer_start(&ble_led_blink_timer, K_MSEC(LED_BLINK_MS), K_MSEC(LED_BLINK_MS));
}

#else

void leds_init(void)
{
/* LED not configured */
}

void leds_set_ble_connected(bool connected)
{
/* LED not configured */

ARG_UNUSED(connected);
}

void leds_indicate_ble_traffic(void)
{
/* LED not configured */
}

#endif /* DT_HAS_CHOSEN(nordic_central_uart_ble_led) */

#if DT_HAS_CHOSEN(nordic_central_uart_log_led)

/*
* Implement a dummy logging backend that blinks the log LED on log activity.
*/
static const struct gpio_dt_spec log_led =
GPIO_DT_SPEC_GET(DT_CHOSEN(nordic_central_uart_log_led), gpios);
static uint8_t log_led_blink_remaining;
static void log_led_blink_handler(struct k_timer *timer);
static K_TIMER_DEFINE(log_led_blink_timer, log_led_blink_handler, NULL);

static void log_led_blink_handler(struct k_timer *timer)
{
int rc;

if (log_led_blink_remaining > 0) {
log_led_blink_remaining--;
rc = gpio_pin_toggle_dt(&log_led);
} else {
k_timer_stop(timer);
rc = gpio_pin_set_dt(&log_led, 0);
}

__ASSERT_NO_MSG(rc == 0);
}

static void log_backend_led_process(const struct log_backend *const backend,
union log_msg_generic *msg)
{
ARG_UNUSED(backend);
ARG_UNUSED(msg);

k_timer_stop(&log_led_blink_timer);

log_led_blink_remaining = LED_BLINK_COUNT;
k_timer_start(&log_led_blink_timer, K_NO_WAIT, K_MSEC(LED_BLINK_MS));
}

static void log_backend_led_init(const struct log_backend *const backend)
{
int rc;

ARG_UNUSED(backend);

if (!gpio_is_ready_dt(&log_led)) {
LOG_WRN("Log LED not ready");
return;
}

rc = gpio_pin_configure_dt(&log_led, GPIO_OUTPUT_INACTIVE);
__ASSERT_NO_MSG(rc == 0);
}

static const struct log_backend_api log_backend_led_api = {
.process = log_backend_led_process,
.init = log_backend_led_init,
};

LOG_BACKEND_DEFINE(log_backend_led, log_backend_led_api, true);
#endif /* DT_HAS_CHOSEN(nordic_central_uart_log_led) */
33 changes: 33 additions & 0 deletions samples/bluetooth/central_uart/src/leds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2026 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef LEDS_H_
#define LEDS_H_

#include <stdbool.h>

/**
* @brief Initialize status LEDs (if configured).
*
* The status LEDs may be enabled by setting the following devicetree chosen properties:
* - nordic,central-uart-ble-led: BLE activity LED
* - nordic,central-uart-log-led: Log activity LED
*/
void leds_init(void);

/**
* @brief Drive BLE LED on when connected, off when disconnected.
*/
void leds_set_ble_connected(bool connected);

/**
* @brief Indicate BLE traffic (RX or TX).
*
* While connected, briefly blinks the BLE LED to indicate traffic.
*/
void leds_indicate_ble_traffic(void);

#endif /* LEDS_H_ */
11 changes: 11 additions & 0 deletions samples/bluetooth/central_uart/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

#include <zephyr/logging/log.h>

#include "leds.h"

#define LOG_MODULE_NAME central_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

Expand Down Expand Up @@ -85,6 +87,8 @@ static void ble_data_sent(struct bt_nus_client *nus, uint8_t err,
ARG_UNUSED(data);
ARG_UNUSED(len);

leds_indicate_ble_traffic();

k_sem_give(&nus_write_sem);

if (err) {
Expand All @@ -99,6 +103,8 @@ static uint8_t ble_data_received(struct bt_nus_client *nus,

int err;

leds_indicate_ble_traffic();

for (uint16_t pos = 0; pos != len;) {
struct uart_data_t *tx = k_malloc(sizeof(*tx));

Expand Down Expand Up @@ -390,6 +396,8 @@ static void connected(struct bt_conn *conn, uint8_t conn_err)

LOG_INF("Connected: %s", addr);

leds_set_ble_connected(true);

static struct bt_gatt_exchange_params exchange_params;

exchange_params.func = exchange_func;
Expand Down Expand Up @@ -423,6 +431,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
return;
}

leds_set_ble_connected(false);
bt_conn_unref(default_conn);
default_conn = NULL;

Expand Down Expand Up @@ -624,6 +633,8 @@ int main(void)
{
int err;

leds_init();

err = bt_conn_auth_cb_register(&conn_auth_callbacks);
if (err) {
LOG_ERR("Failed to register authorization callbacks.");
Expand Down
Loading