Hello,
I am adding security feature for BLE in nrf52810 custom board. I am using v2.9.1 toolchain and 2.9.1 sdk files
PFA BLE related file as well as .conf file as well.
I am not sure what is wrong that I am doing. Its going in hard fault.
Can you help me with that? Also let me know if you want any other info.
Thanks,
Chinmay
#include "ble_handle.h"
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <soc.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/logging/log.h>
#include <uart_async_adapter.h>
#include <bluetooth/services/nus.h>
#include "../GPIO_handle/GPIO_handle.h"
#include "../uart_handle/uart_handle.h"
#include "storage_handle.h"
#include "at_cmd_handle.h"
#define LOG_MODULE_NAME BLE
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define STACKSIZE 1024
#define PRIORITY 7
K_FIFO_DEFINE(fifo_uart_tx_data);
K_FIFO_DEFINE(fifo_uart_rx_data);
static struct bt_conn *current_conn;
static struct bt_conn *auth_conn;
static struct bt_conn *security_conn;
uint16_t conn_interval;
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
static void num_comp_reply(bool accept)
{
if (accept) {
bt_conn_auth_passkey_confirm(auth_conn);
//LOG_INF("Numeric Match, conn %p", (void *)auth_conn);
} else {
bt_conn_auth_cancel(auth_conn);
//LOG_INF("Numeric Reject, conn %p", (void *)auth_conn);
}
bt_conn_unref(auth_conn);
auth_conn = NULL;
}
#endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
static K_SEM_DEFINE(ble_init_ok, 0, 1);
static const struct bt_data sd[] = {
BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
};
static char ble_name[MAX_NAME_LEN] = DEFAULT_NAME;
static 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, ble_name, 0), // Length set later
};
void send_ble_data(struct uart_data_t * buf)
{
if (bt_nus_send(NULL, buf->data, buf->len))
{
LOG_WRN("Failed to send data over BLE connection");
}
}
static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
uint16_t len)
{
int err;
//LOG_INF("Received data from: %s", addr);
// If in programming mode, treat BLE input as AT command inputx
if (programming_mode) {
char at_cmd_buf[50]; // Match size with uart_data_t
uint16_t copy_len = MIN(len, sizeof(at_cmd_buf) - 1);
memcpy(at_cmd_buf, data, copy_len);
at_cmd_buf[copy_len] = '\0'; // Null-terminate string
//LOG_INF("AT Command received: %s", at_cmd_buf);
parse_at_command(at_cmd_buf);
return;
}
// If not in programming mode, send data to UART
for (uint16_t pos = 0; pos != len;) {
struct uart_data_t *tx = k_malloc(sizeof(*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++;
// }
uart_data_send(tx);
}
}
static struct bt_nus_cb nus_cb = {
.received = bt_receive_cb,
};
#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));
//printk("Passkey for %s: %06u\n", addr, passkey);
uart_printk("Passkey for %s: %06u\n", addr, passkey);
//LOG_INF("Passkey for %s: %06u", 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", addr, passkey);
uart_printk("Confirming passkey %06u for %s\n", passkey, addr);
if (bt_conn_auth_passkey_confirm(auth_conn)) {
uart_printk("Failed to confirm passkey for %s", addr);
} else {
//LOG_INF("Passkey confirmed for %s", addr);
}
}
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", 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));
uart_printk("Pairing completed: %s, bonded: %d\n", addr, bonded);
//LOG_INF("Pairing completed: %s, bonded: %d", 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));
uart_printk("Pairing failed: %s, reason: %d %s\n", addr, reason,
bt_security_err_to_str(reason));
//LOG_INF("Pairing failed conn: %s, reason %d %s", addr, reason,
//bt_security_err_to_str(reason);
}
static void auth_passkey_entry(struct bt_conn *conn)
{
if (bt_conn_auth_passkey_entry(conn, 123456))
{
uart_printk("Failed to enter passkey for %s\n", bt_addr_str(bt_conn_get_dst(conn)));
}
else
{
uart_printk("Passkey entered for %s\n", bt_addr_str(bt_conn_get_dst(conn)));
}
}
static struct bt_conn_auth_cb conn_auth_callbacks = {
.passkey_display = auth_passkey_display,
.cancel = auth_cancel,
//.passkey_entry = auth_passkey_entry,
//.passkey_confirm = auth_passkey_confirm,
};
static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed
};
#else
static struct bt_conn_auth_cb conn_auth_callbacks;
static struct bt_conn_auth_info_cb conn_auth_info_callbacks;
#endif
static void update_data_length(struct bt_conn *conn)
{
int err;
struct bt_conn_le_data_len_param my_data_len = {
.tx_max_len = BT_GAP_DATA_LEN_MAX,
.tx_max_time = BT_GAP_DATA_TIME_MAX,
};
err = bt_conn_le_data_len_update(current_conn, &my_data_len);
if (err) {
LOG_ERR("data_len_update failed (err %d)", err);
}
}
static void exchange_func(struct bt_conn *conn, uint8_t att_err,
struct bt_gatt_exchange_params *params)
{
LOG_INF("MTU exchange %s", att_err == 0 ? "successful" : "failed");
if (!att_err) {
uint16_t payload_mtu = bt_gatt_get_mtu(conn) - 3; // 3 bytes used for Attribute headers.
LOG_INF("New MTU: %d bytes", payload_mtu);
}
}
static struct bt_gatt_exchange_params exchange_params;
static void update_mtu(struct bt_conn *conn)
{
int err;
exchange_params.func = exchange_func;
err = bt_gatt_exchange_mtu(conn, &exchange_params);
if (err) {
LOG_ERR("bt_gatt_exchange_mtu failed (err %d)", err);
}
}
static struct k_work_delayable security_work;
static void security_work_handler(struct k_work *work)
{
if (security_conn) {
uart_printk("Setting BLE security level...\n");
int err = bt_conn_set_security(security_conn, BT_SECURITY_L2);
if (err) {
uart_printk("Failed to set security: %d\n", err);
}
bt_conn_unref(security_conn);
}
}
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
if (err) {
LOG_ERR("Connection failed, err 0x%02x %s", err, bt_hci_err_to_str(err));
return;
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
//LOG_INF("Connected %s", addr);
current_conn = bt_conn_ref(conn);
struct bt_le_conn_param param = {
.interval_min = 24,
.interval_max = read_conn_interval(),
.latency = 0,
.timeout = 400,
};
bt_conn_le_param_update(conn, ¶m);
update_data_length(current_conn);
update_mtu(current_conn);
if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED))
{
security_conn = bt_conn_ref(conn);
k_work_schedule(&security_work, K_SECONDS(1)); // delay of 1 second
// security_conn = bt_conn_ref(conn);
// if (security_conn) {
// uart_printk("Setting BLE security level...\n");
// int err = bt_conn_set_security(security_conn, BT_SECURITY_L2);
// if (err) {
// uart_printk("Failed to set security: %d\n", err);
// }
// }
}
ConnectedOnBLE = true;
HandleLEDBlink();
}
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 0x%02x %s", addr, reason, bt_hci_err_to_str(reason));
if (auth_conn) {
bt_conn_unref(auth_conn);
auth_conn = NULL;
}
if (current_conn) {
bt_conn_unref(current_conn);
current_conn = NULL;
}
if (security_conn) {
bt_conn_unref(security_conn);
security_conn = NULL;
}
{
/* code */
}
ConnectedOnBLE = false;
HandleLEDBlink();
}
#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));
uart_printk("Security changed: %s level %u err %d %s\n", addr, level, err,
bt_security_err_to_str(err));
if (!err) {
//LOG_INF("Security changed: %s level %u", addr, level);
} else {
LOG_WRN("Security failed: %s level %u err %d %s", addr, level, err,
bt_security_err_to_str(err));
}
}
#endif
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
.security_changed = security_changed,
#endif
};
void ble_write_thread(void)
{
/* Don't go any further until BLE is initialized */
k_sem_take(&ble_init_ok, K_FOREVER);
// struct uart_data_t nus_data = {
// .len = 0,
// };
for (;;) {
/* Wait indefinitely for data to be sent over bluetooth */
struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
K_FOREVER);
//int plen = MIN(sizeof(nus_data.data) - nus_data.len, buf->len);
//int loc = 0;
//while (plen > 0) {
// memcpy(&nus_data.data[nus_data.len], &buf->data[loc], plen);
// nus_data.len += plen;
// loc += plen;
// if (nus_data.len >= sizeof(nus_data.data) ||
// (nus_data.data[nus_data.len - 1] == '\n') ||
// (nus_data.data[nus_data.len - 1] == '\r'))
// {
// if (bt_nus_send(NULL, nus_data.data, nus_data.len)) {
// LOG_WRN("Failed to send data over BLE connection");
// }
// nus_data.len = 0;
// // }
// plen = MIN(sizeof(nus_data.data), buf->len - loc);
//}
if (bt_nus_send(NULL, buf->data, buf->len)) {
LOG_WRN("Failed to send data over BLE connection");
}
k_free(buf);
}
}
K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL,
NULL, PRIORITY, 0, 0);
void ble_init()
{
int err = 0;
if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
err = bt_conn_auth_cb_register(&conn_auth_callbacks);
if (err) {
uart_printk("Failed to register authorization callbacks.\n");
}
err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
if (err) {
uart_printk("Failed to register authorization info callbacks.\n");
}
}
err = bt_enable(NULL);
if (err) {
LOG_ERR("Bluetooth init failed (err %d)", err);
}
if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED))
{
k_work_init_delayable(&security_work, security_work_handler);
bt_passkey_set(123456);
}
if (err) {
uart_printk("Failed to set passkey (err %d)\n", err);
}
//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);
}
int len = read_device_name(ble_name); // Pull name from NVS
if (len < 0) {
uart_printk("Using default BLE name\n");
}
ad[1].data_len = strlen(ble_name); // Set correct length dynamically
conn_interval = read_conn_interval();
uart_printk("Using connection interval: %d ms\n", conn_interval);
err = bt_le_adv_start(BT_LE_ADV_PARAM(
BT_LE_ADV_OPT_CONNECTABLE,
BT_GAP_ADV_FAST_INT_MIN_2,
BT_GAP_ADV_FAST_INT_MAX_2,
NULL),
ad, ARRAY_SIZE(ad),
sd, ARRAY_SIZE(sd));
if (err) {
uart_printk("Advertising failed to start (err %d)", err);
}
}
