This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

memory leak in Zephyr peripheral_uart example

Hi,

This problem was found accidentally when trying to solve a different problem here: devzone.nordicsemi.com/.../nrf52833-peripheral_uart-zephyr-example-only-works-with-prj_minimal-conf-and-not-prj-conf

When I run the peripheral_uart example from the nrfconnect SDK v1.5.0 on the nrf52840dk_nrf52840, a memory leak occurs if garbage data is sent to the UART (BLE is not connected). I have added some logging to the existing code, here is the log showing the mallocs and frees when connected to the J-Link UART port at baud 115200 and I repeatedly send the letter "k":

- - - - - - - - - - - - - - - - - TARGET RESET - - - - - - - - - - - - - - - - -
[00:00:02.745,025] [0m<inf> peripheral_uart: malloc: 0x20003560 (total mallocs: 1, total frees: 0)[0m
[00:00:02.745,056] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:02.745,086] [0m<inf> peripheral_uart: malloc: 0x20003588 (total mallocs: 2, total frees: 0)[0m
[00:00:02.753,509] [0m<inf> fs_nvs: 8 Sectors of 4096 bytes[0m
[00:00:02.753,509] [0m<inf> fs_nvs: alloc wra: 0, db0[0m
[00:00:02.753,509] [0m<inf> fs_nvs: data wra: 0, 3d2[0m
[00:00:02.753,753] [0m<inf> sdc_hci_driver: SoftDevice Controller build revision: 
                                         e5 c7 9c d9 91 00 1d 66  ea fb 6e 7b 98 2f 42 0d |.......f ..n{./B.
                                         f1 60 93 c8                                      |.`..             [0m
[00:00:02.757,995] [0m<inf> bt_hci_core: No ID address. App must call settings_load()[0m
[00:00:02.757,995] [0m<inf> peripheral_uart: Bluetooth initialized[0m
[00:00:13.806,091] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:16.718,963] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:17.539,764] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:18.490,692] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:19.001,190] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:19.301,483] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:19.661,834] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:22.804,962] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:23.165,313] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:23.665,802] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:23.936,096] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:24.276,428] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:24.536,682] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:24.877,014] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:26.638,732] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:26.878,967] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:27.219,299] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:27.469,543] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:27.759,857] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:27.950,988] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:27.951,019] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:27.951,019] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x20003564[0m
[00:00:27.951,049] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:27.951,080] [0m<inf> peripheral_uart: malloc: 0x200035B0 (total mallocs: 3, total frees: 0)[0m
[00:00:27.951,110] [0m<inf> peripheral_uart: BT TX: len 20[0m
[00:00:27.951,141] [1;33m<wrn> peripheral_uart: Failed to send data over BLE connection[0m
[00:00:27.951,171] [0m<inf> peripheral_uart: free: 0x20003560 (total mallocs: 3, total frees: 1)[0m
[00:00:28.271,423] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:37.160,156] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:37.370,361] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:37.590,576] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:37.840,820] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:38.061,035] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:38.291,259] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:38.491,455] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:39.502,441] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:39.732,666] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:39.992,919] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:40.293,212] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:40.493,377] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:40.743,652] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:40.963,867] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:42.835,693] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:43.075,927] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:43.326,171] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:43.596,435] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:43.768,737] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:43.768,768] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:43.768,798] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x2000358C[0m
[00:00:43.768,798] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:43.768,829] [0m<inf> peripheral_uart: malloc: 0x20003560 (total mallocs: 4, total frees: 1)[0m
[00:00:43.768,859] [0m<inf> peripheral_uart: BT TX: len 20[0m
[00:00:43.768,890] [1;33m<wrn> peripheral_uart: Failed to send data over BLE connection[0m
[00:00:43.768,920] [0m<inf> peripheral_uart: free: 0x20003588 (total mallocs: 4, total frees: 2)[0m
[00:00:44.089,172] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:44.339,416] [0m<inf> peripheral_uart: UART_RX_RDY[0m

And here is what it looks like when the J-Link UART is set to 9600 and I press the letter "k" twice:

[00:00:01.886,138] [0m<inf> peripheral_uart: malloc: 0x20003560 (total mallocs: 1, total frees: 0)[0m
[00:00:01.886,138] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:01.886,169] [0m<inf> peripheral_uart: malloc: 0x20003588 (total mallocs: 2, total frees: 0)[0m
[00:00:01.894,531] [0m<inf> fs_nvs: 8 Sectors of 4096 bytes[0m
[00:00:01.894,561] [0m<inf> fs_nvs: alloc wra: 0, db0[0m
[00:00:01.894,561] [0m<inf> fs_nvs: data wra: 0, 3d2[0m
[00:00:01.894,805] [0m<inf> sdc_hci_driver: SoftDevice Controller build revision: 
                                         e5 c7 9c d9 91 00 1d 66  ea fb 6e 7b 98 2f 42 0d |.......f ..n{./B.
                                         f1 60 93 c8                                      |.`..             [0m
[00:00:01.899,017] [0m<inf> bt_hci_core: No ID address. App must call settings_load()[0m
[00:00:01.899,017] [0m<inf> peripheral_uart: Bluetooth initialized[0m
[00:00:11.162,200] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,231] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,506] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,536] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,719] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,750] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:11.162,750] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:11.162,750] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x20003564[0m
[00:00:11.162,780] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:11.162,780] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x2000358C[0m
[00:00:11.162,811] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.162,811] [0m<inf> peripheral_uart: UART_RX_DISABLED[0m
[00:00:11.162,841] [0m<inf> peripheral_uart: malloc: 0x200035B0 (total mallocs: 3, total frees: 0)[0m
[00:00:11.162,872] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:11.162,902] [0m<inf> peripheral_uart: malloc: 0x200035D8 (total mallocs: 4, total frees: 0)[0m
[00:00:11.163,024] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.163,055] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:11.163,574] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:11.163,574] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x200035B4[0m
[00:00:11.163,574] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:11.163,604] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x200035DC[0m
[00:00:11.163,604] [0m<inf> peripheral_uart: UART_RX_DISABLED[0m
[00:00:11.163,635] [0m<inf> peripheral_uart: malloc: 0x20003600 (total mallocs: 5, total frees: 0)[0m
[00:00:11.163,665] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:11.163,696] [0m<inf> peripheral_uart: malloc: 0x20003628 (total mallocs: 6, total frees: 0)[0m
[00:00:12.692,199] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,230] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,504] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,535] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,718] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,749] [0m<inf> peripheral_uart: UART_RX_RDY[0m
[00:00:12.692,749] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:12.692,749] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x20003604[0m
[00:00:12.692,749] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:12.692,779] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x2000362C[0m
[00:00:12.692,810] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.692,810] [0m<inf> peripheral_uart: UART_RX_DISABLED[0m
[00:00:12.692,840] [0m<inf> peripheral_uart: malloc: 0x20003650 (total mallocs: 7, total frees: 0)[0m
[00:00:12.692,871] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:12.692,901] [0m<inf> peripheral_uart: malloc: 0x20003678 (total mallocs: 8, total frees: 0)[0m
[00:00:12.693,023] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.693,054] [0m<inf> peripheral_uart: Unknown UART event: 6[0m
[00:00:12.693,572] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:12.693,572] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x20003654[0m
[00:00:12.693,572] [0m<inf> peripheral_uart: UART_RX_BUF_RELEASED[0m
[00:00:12.693,572] [0m<inf> peripheral_uart: not releasing, buf_release=0, current_buf=0x0, evt->data.rx_buf.buf=0x2000367C[0m
[00:00:12.693,603] [0m<inf> peripheral_uart: UART_RX_DISABLED[0m
[00:00:12.693,634] [0m<inf> peripheral_uart: malloc: 0x200036A0 (total mallocs: 9, total frees: 0)[0m
[00:00:12.693,664] [0m<inf> peripheral_uart: UART_RX_BUF_REQUEST[0m
[00:00:12.693,695] [0m<inf> peripheral_uart: malloc: 0x200036C8 (total mallocs: 10, total frees: 0)[0m

Obviously the memory is not being freed from this, and eventually the heap runs out if I press "k" enough times. 

I am still learning how Zephyr works, so I am not sure of the best way to handle this case. I would appreciate any pointers.

The code I am using is attached below.

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/** @file
 *  @brief Nordic UART Bridge Service (NUS) sample
 */

#include <zephyr/types.h>
#include <zephyr.h>
#include <drivers/uart.h>

#include <device.h>
#include <soc.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
#include <bluetooth/hci.h>

#include <bluetooth/services/nus.h>

#include <dk_buttons_and_leds.h>

#include <settings/settings.h>

#include <stdio.h>

#include <logging/log.h>

#define LOG_MODULE_NAME peripheral_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
#define PRIORITY 7

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN	(sizeof(DEVICE_NAME) - 1)

#define RUN_STATUS_LED DK_LED1
#define RUN_LED_BLINK_INTERVAL 1000

#define CON_STATUS_LED DK_LED2

#define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
#define KEY_PASSKEY_REJECT DK_BTN2_MSK

#define UART_BUF_SIZE CONFIG_BT_NUS_UART_BUFFER_SIZE
#define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
#define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME

static K_SEM_DEFINE(ble_init_ok, 0, 1);

static struct bt_conn *current_conn;
static struct bt_conn *auth_conn;

static const struct device *uart;
static struct k_delayed_work uart_work;

struct uart_data_t {
	void *fifo_reserved;
	uint8_t data[UART_BUF_SIZE];
	uint16_t len;
};

static K_FIFO_DEFINE(fifo_uart_tx_data);
static K_FIFO_DEFINE(fifo_uart_rx_data);

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static const struct bt_data sd[] = {
	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
};

atomic_t malloc_count;
atomic_t free_count;

static void log_malloc(uint32_t address) {
	atomic_inc(&malloc_count);
	LOG_INF("malloc: 0x%X (total mallocs: %i, total frees: %i)", address, atomic_get(&malloc_count), atomic_get(&free_count));
}

static void log_mem_free(uint32_t address) {
	atomic_inc(&free_count);
	LOG_INF("free: 0x%X (total mallocs: %i, total frees: %i)", address, atomic_get(&malloc_count), atomic_get(&free_count));
}

static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	ARG_UNUSED(dev);

	static uint8_t *current_buf;
	static size_t aborted_len;
	static bool buf_release;
	struct uart_data_t *buf;
	static uint8_t *aborted_buf;

	switch (evt->type) {
	case UART_TX_DONE:
		LOG_INF("UART_TX_DONE");
		if ((evt->data.tx.len == 0) ||
		    (!evt->data.tx.buf)) {
			return;
		}

		if (aborted_buf) {
			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
					   data);
			aborted_buf = NULL;
			aborted_len = 0;
		} else {
			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
					   data);
		}

		k_free(buf);
		log_mem_free((uint32_t)buf);

		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
		if (!buf) {
			return;
		}

		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
			LOG_WRN("Failed to send data over UART");
		}

		break;

	case UART_RX_RDY:
		LOG_INF("UART_RX_RDY");
		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
		buf->len += evt->data.rx.len;
		buf_release = false;

		if (buf->len == UART_BUF_SIZE) {
			k_fifo_put(&fifo_uart_rx_data, buf);
		} else if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
			  (evt->data.rx.buf[buf->len - 1] == '\r')) {
			k_fifo_put(&fifo_uart_rx_data, buf);
			current_buf = evt->data.rx.buf;
			buf_release = true;
			uart_rx_disable(uart);
		}

		break;

	case UART_RX_DISABLED:
		LOG_INF("UART_RX_DISABLED");
		buf = k_malloc(sizeof(*buf));
		log_malloc((uint32_t)buf);
		if (buf) {
			buf->len = 0;
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
			k_delayed_work_submit(&uart_work,
					      UART_WAIT_FOR_BUF_DELAY);
			return;
		}

		uart_rx_enable(uart, buf->data, sizeof(buf->data),
			       UART_WAIT_FOR_RX);

		break;

	case UART_RX_BUF_REQUEST:
		LOG_INF("UART_RX_BUF_REQUEST");
		buf = k_malloc(sizeof(*buf));
		log_malloc((uint32_t)buf);
		if (buf) {
			buf->len = 0;
			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
		}

		break;

	case UART_RX_BUF_RELEASED:
		LOG_INF("UART_RX_BUF_RELEASED");
		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
				   data);
		if (buf_release && (current_buf != evt->data.rx_buf.buf)) {
			k_free(buf);
			log_mem_free((uint32_t)buf);
			buf_release = false;
			current_buf = NULL;
		} else {
			LOG_INF("not releasing, buf_release=%i, current_buf=0x%X, evt->data.rx_buf.buf=0x%X", buf_release, (uint32_t)current_buf, (uint32_t)evt->data.rx_buf.buf);
		}

		break;

	case UART_TX_ABORTED:
		LOG_INF("UART_TX_ABORTED");
			if (!aborted_buf) {
				aborted_buf = (uint8_t *)evt->data.tx.buf;
			}

			aborted_len += evt->data.tx.len;
			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
					   data);

			uart_tx(uart, &buf->data[aborted_len],
				buf->len - aborted_len, SYS_FOREVER_MS);

		break;

	default:
		LOG_INF("Unknown UART event: %i", evt->type);
		break;
	}
}

static void uart_work_handler(struct k_work *item)
{
	struct uart_data_t *buf;

	LOG_INF("WORK_HANDLER");

	buf = k_malloc(sizeof(*buf));
	log_malloc((uint32_t)buf);
	if (buf) {
		buf->len = 0;
	} else {
		LOG_WRN("Not able to allocate UART receive buffer");
		k_delayed_work_submit(&uart_work, UART_WAIT_FOR_BUF_DELAY);
		return;
	}

	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
}

static int uart_init(void)
{
	int err;
	struct uart_data_t *rx;

	uart = device_get_binding(DT_LABEL(DT_NODELABEL(uart0)));
	if (!uart) {
		return -ENXIO;
	}

	rx = k_malloc(sizeof(*rx));
	log_malloc((uint32_t)rx);
	if (rx) {
		rx->len = 0;
	} else {
		return -ENOMEM;
	}

	k_delayed_work_init(&uart_work, uart_work_handler);

	err = uart_callback_set(uart, uart_cb, NULL);
	if (err) {
		return err;
	}

	return uart_rx_enable(uart, rx->data, sizeof(rx->data), 50);
}

static void connected(struct bt_conn *conn, uint8_t err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	if (err) {
		LOG_ERR("Connection failed (err %u)", err);
		return;
	}

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
	LOG_INF("Connected %s", log_strdup(addr));

	current_conn = bt_conn_ref(conn);

	dk_set_led_on(CON_STATUS_LED);
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Disconnected: %s (reason %u)", log_strdup(addr), reason);

	if (auth_conn) {
		bt_conn_unref(auth_conn);
		auth_conn = NULL;
	}

	if (current_conn) {
		bt_conn_unref(current_conn);
		current_conn = NULL;
		dk_set_led_off(CON_STATUS_LED);
	}
}

#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
static void security_changed(struct bt_conn *conn, bt_security_t level,
			     enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	if (!err) {
		LOG_INF("Security changed: %s level %u", log_strdup(addr),
			level);
	} else {
		LOG_WRN("Security failed: %s level %u err %d", log_strdup(addr),
			level, err);
	}
}
#endif

static struct bt_conn_cb conn_callbacks = {
	.connected    = connected,
	.disconnected = disconnected,
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
	.security_changed = security_changed,
#endif
};

#if defined(CONFIG_BT_NUS_SECURITY_ENABLED)
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Passkey for %s: %06u", log_strdup(addr), passkey);
}

static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	auth_conn = bt_conn_ref(conn);

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Passkey for %s: %06u", log_strdup(addr), passkey);
	LOG_INF("Press Button 1 to confirm, Button 2 to reject.");
}


static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Pairing cancelled: %s", log_strdup(addr));
}


static void pairing_confirm(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	bt_conn_auth_pairing_confirm(conn);

	LOG_INF("Pairing confirmed: %s", log_strdup(addr));
}


static void pairing_complete(struct bt_conn *conn, bool bonded)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Pairing completed: %s, bonded: %d", log_strdup(addr),
		bonded);
}


static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Pairing failed conn: %s, reason %d", log_strdup(addr),
		reason);
}


static struct bt_conn_auth_cb conn_auth_callbacks = {
	.passkey_display = auth_passkey_display,
	.passkey_confirm = auth_passkey_confirm,
	.cancel = auth_cancel,
	.pairing_confirm = pairing_confirm,
	.pairing_complete = pairing_complete,
	.pairing_failed = pairing_failed
};
#else
static struct bt_conn_auth_cb conn_auth_callbacks;
#endif

static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
			  uint16_t len)
{
	int err;
	char addr[BT_ADDR_LE_STR_LEN] = {0};

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, ARRAY_SIZE(addr));

	LOG_INF("Received data from: %s", log_strdup(addr));

	for (uint16_t pos = 0; pos != len;) {
		struct uart_data_t *tx = k_malloc(sizeof(*tx));
		log_malloc((uint32_t)tx);
		if (!tx) {
			LOG_WRN("Not able to allocate UART send data buffer");
			return;
		}

		/* Keep the last byte of TX buffer for potential LF char. */
		size_t tx_data_size = sizeof(tx->data) - 1;

		if ((len - pos) > tx_data_size) {
			tx->len = tx_data_size;
		} else {
			tx->len = (len - pos);
		}

		memcpy(tx->data, &data[pos], tx->len);

		pos += tx->len;

		/* Append the LF character when the CR character triggered
		 * transmission from the peer.
		 */
		if ((pos == len) && (data[len - 1] == '\r')) {
			tx->data[tx->len] = '\n';
			tx->len++;
		}

		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
		if (err) {
			k_fifo_put(&fifo_uart_tx_data, tx);
		}
	}
}

static struct bt_nus_cb nus_cb = {
	.received = bt_receive_cb,
};

void error(void)
{
	dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK);

	while (true) {
		/* Spin for ever */
		k_sleep(K_MSEC(1000));
	}
}

static void num_comp_reply(bool accept)
{
	if (accept) {
		bt_conn_auth_passkey_confirm(auth_conn);
		LOG_INF("Numeric Match, conn %p", auth_conn);
	} else {
		bt_conn_auth_cancel(auth_conn);
		LOG_INF("Numeric Reject, conn %p", auth_conn);
	}

	bt_conn_unref(auth_conn);
	auth_conn = NULL;
}

void button_changed(uint32_t button_state, uint32_t has_changed)
{
	uint32_t buttons = button_state & has_changed;

	if (auth_conn) {
		if (buttons & KEY_PASSKEY_ACCEPT) {
			num_comp_reply(true);
		}

		if (buttons & KEY_PASSKEY_REJECT) {
			num_comp_reply(false);
		}
	}
}

static void configure_gpio(void)
{
	int err;

	err = dk_buttons_init(button_changed);
	if (err) {
		LOG_ERR("Cannot init buttons (err: %d)", err);
	}

	err = dk_leds_init();
	if (err) {
		LOG_ERR("Cannot init LEDs (err: %d)", err);
	}
}

void main(void)
{
	int blink_status = 0;
	int err = 0;

	configure_gpio();

	err = uart_init();
	if (err) {
		error();
	}

	bt_conn_cb_register(&conn_callbacks);

	if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
		bt_conn_auth_cb_register(&conn_auth_callbacks);
	}

	err = bt_enable(NULL);
	if (err) {
		error();
	}

	LOG_INF("Bluetooth initialized");

	k_sem_give(&ble_init_ok);

	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

	err = bt_nus_init(&nus_cb);
	if (err) {
		LOG_ERR("Failed to initialize UART service (err: %d)", err);
		return;
	}

	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd,
			      ARRAY_SIZE(sd));
	if (err) {
		LOG_ERR("Advertising failed to start (err %d)", err);
	}

	printk("Starting Nordic UART service example\n");

	for (;;) {
		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
	}
}

void ble_write_thread(void)
{
	/* Don't go any further until BLE is initialized */
	k_sem_take(&ble_init_ok, K_FOREVER);

	for (;;) {
		/* Wait indefinitely for data to be sent over bluetooth */
		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
						     K_FOREVER);

		LOG_INF("BT TX: len %i", buf->len);
		if (bt_nus_send(NULL, buf->data, buf->len)) {
			LOG_WRN("Failed to send data over BLE connection");
		}

		k_free(buf);
		log_mem_free((uint32_t)buf);
	}
}

K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL,
		NULL, PRIORITY, 0, 0);

Parents
  • Hi, Jeremy!

    Thanks for reaching out. Did you make sure to update the application to reflect the 9600 baud rate? Otherwise the application will likely fail similarly to what you are seeing here. You can change the configured speed by updating the prj.overlay file like this:

    &uart0 {
    	compatible = "nordic,nrf-uarte";
    	current-speed = < 9600 >;
    };

    While not explicitly stated in this sample, our applications are in general configured with a baud rate of 115200. This is mentioned in the Testing a sample application documentation.

    Hope this helps!

    Best regards,
    Carl Richard 

Reply
  • Hi, Jeremy!

    Thanks for reaching out. Did you make sure to update the application to reflect the 9600 baud rate? Otherwise the application will likely fail similarly to what you are seeing here. You can change the configured speed by updating the prj.overlay file like this:

    &uart0 {
    	compatible = "nordic,nrf-uarte";
    	current-speed = < 9600 >;
    };

    While not explicitly stated in this sample, our applications are in general configured with a baud rate of 115200. This is mentioned in the Testing a sample application documentation.

    Hope this helps!

    Best regards,
    Carl Richard 

Children
Related