BLE Just Works on nrf52832 and NRF Connect

Hi, I am working on something that requires me to use Just Works on nrf52832 custom board. Here is the work sccenario. under normal conditions, my module has a bonding PIN and the user is supposed to enter the PIN on his application to get data. My NRF module is a peripheral and i have enabled following in the prj.conf.


CONFIG_BT_NUS_SECURITY_ENABLED

CONFIG_BT_FIXED_PASSKEY

I have registered the necessary callbacks too.

What I now need to implement is a functionality which allows user to bond without a PIN temporarily after a button press. I assume BLE Just Works is what I need for this purpose. But I am open to any other suggestions or new perspectives to get this done.Thanks in advance.

Parents
  • Hi Midhunjac, 

    To be able to change the capability of the device to not have passkey (no display and keyboard) what you need to do is to 

    bt_conn_auth_cb_register() with NULL input to remove the callback. Then you recall the bt_conn_auth_cb_register() without the display or confirm or entry callback. 

    However we need to look at how you define your characteristics as well. Because in the characteristic definitions you also define the minimum level of security to access the characteristics. If you set it to requires MITM, having Just work bonding would not be enough to allow accessing the characteristics. 
    If it's the case you may want to reinitalize the characteristic with new parameter. 
  • I tried your suggestion but it didnt work. When I tried out what you suggested, the bonding failed. These are the logs.

    <inf>: Connected 68:4A:E9:DC:F3:BC (public)
    <wrn>: Security failed: 68:4A:E9:DC:F3:BC (public) level 1 err 4
    <inf> migration1: Pairing failed conn: 68:4A:E9:DC:F3:BC (public), reason 4
    <inf>: Disconnected: 68:4A:E9:DC:F3:BC (public) (reason 19)
    <inf>:Disconnected 68:4A:E9:DC:F3:BC (public) :
    I am sure it must be a mistake on my side. Can you please take a look at this ? Isn't this how you suggested that I do ? Just to make sure that we are not misunderstanding each other, I am using NCSv2.1.0 and for testing purposes, I have switched to the basic peripheral UART example. So the characteristics of that particular service applies now. What I am testing is if I can bond with the peripheral without a passkey. I am not trying to access any particular characteristic. I just want to bond with the peripheral straight away.

    /*some code*/
    err = bt_conn_auth_cb_register(NULL);
    err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    /* some code */
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    		.cancel = auth_cancel,
    
    };

    Tried adding the bt_conn_auth_cb_register() with the passkey display and passkey entry and passkey confirm callbacks set to NULL. That didnt work out too.

  • Hi  

    Are you sure about that ? Because I made the above two changes to the prj.conf and deleted the display callback. Now I can set my passkey on the module with bt_passkey_set(). It works fine. I have to enter the said passkey in nrf connect application to bond. But now I cannot switch to Just Works with the changes you attached. The nrf connect will still prompt me to enter the preset passkey even after pressing the Button 4. Is there anything I am missing? Can you confirm this behavior at your end please? These are my callbacks and prj.conf configurations.

    /*<main.c>*/
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	//.passkey_display = auth_passkey_display,
    	.passkey_confirm = auth_passkey_confirm,
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_cb conn_auth_callbacks2 = {
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
    	.pairing_complete = pairing_complete,
    	.pairing_failed = pairing_failed
    };
    
    /*<prj.conf>*/
    
    CONFIG_BT_SMP=y
    CONFIG_BT_FIXED_PASSKEY=y

  • Hi, 

    Do this when in button 4 handler (before bt_conn_auth_cb_register calls)  and it should work: 

                bt_passkey_set(BT_PASSKEY_INVALID);
  • Hi,

    I did as instructed, but nothing much has changed except for on thing. Here are the two cases that I have tried.

    1) Establish a bond first with passkey and then try Just Works.

    • The passkey bonding works fine. But if I try to switch to Just Works, the bonding attempt fails without any error message. It just shows 'NOT BONDED' in the nrf connect. But from what I understand by examining the flags set, it seems like the module is still remembering the previous connections.

    2) Establish a bond first using Just Works. Unpair it from the nrf connect. Try pairing again using Just Works

    • The first time pairing using Just Works works fine. The device is paired. The second time the pairing using the same callbacks and same methods will be unsuccessful.

    Below is the snippet that I use with a custom function.

    /*<main.c>*/
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	//.passkey_display = auth_passkey_display,
    	.passkey_confirm = auth_passkey_confirm,
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_cb conn_auth_callbacks2 = {
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
    	.pairing_complete = pairing_complete,
    	.pairing_failed = pairing_failed
    };
    
    void update()
    {
        LOG_INF("Update ble pairing");
       // bt_unpair(BT_ID_DEFAULT,NULL);// including this line results in system crash
    	bt_passkey_set(BT_PASSKEY_INVALID);
    	bt_conn_auth_cb_register(NULL);
    	bt_conn_auth_cb_register(&conn_auth_callbacks2);
    }
    /*<prj.conf>*/
    
    CONFIG_BT_SMP=y
    CONFIG_BT_FIXED_PASSKEY=y

    Also, whenever I use bt_unpair function, the system crashes immediately with the following message

    ASSERTION FAIL [!arch_is_in_isr()] @ WEST_TOPDIR/zephyr/kernel/mutex.c:101
            mutexes cannot be used inside ISRs
    *** Booting Zephyr OS build v3.1.99-ncs1  ***
    Starting Nordic UART service example

    From what I've observed, whenever there is a previously established bond, if we try to unpair using bt_unpair(), this assertion fails. If there are no previous bonds, there is no problem.

    So, all the testing that I did above was done without invoking the bt_unpair(). But the bonding information from the nrf connect was deleted after each successful bonding. Is this why the module was still 'remembering' its previous state ? But even if that was the case, isnt the case (2) supposed to work ?

    Can you please explain this behavior ? Is there something wrong I am doing ? I do not seem to understand the issue here. Thanks a lot for helping me out.

  • Hi, Just to add to the my previous observations, here is the wireshark capture for the events. The file 'capture_whole_new.pcapng' contains the packets for the test case 1 described above. capture_whole_new.pcapng

  • Hi, 

    Have you tried with my example ? When you press button 3 on the kit would the bond information be deleted ? 

    Please do a chip erase before testing. 

Reply Children
  • Yes when button 3 is pressed I can bond.But what actually happens is this same assertion failure and a consequent reboot. I hadnt gone through the logs earlier so I could not see this happening. All these happens so fast that I could not observe any thing wrong while connecting/dusconnecting/pairing. Can you please check on your side if there is this assertion failure happening ?

  • Hi again, 
    I attached here the log when I test with my example: 

    What I did was to connect, bond, then disconnect, then press button 3 (BTN3), and then Button 4 (BTN) then pair again. It worked just fine, no assert. 

  • I do not understand this. Can you please do me a favor and try again the same steps with the fixed passkey thing as I did and let me know , if that is not too much to ask ? I still have the same issue.

  • Please try the attached project with static passkey. I tested here and it worked fine.

    peripheral_uart_changebond2.zip

    6406.zephyr.hex

  • I tested the attached configuration and it works fine. I think I now understand the issue. The test procedure is incomplete. The following is the test sequence that gives the error.

    Pair using static key - SUCCESS

    Disconnect

    Button 3 (or some function to unpair )

    Button 4 ( or some function to switch to Just Works)

    Pair again - SUCCESS

    Disconnect

    Button 3 (or some function to unpair )

    Button 4 ( or some function to switch BACK TO fixed passkey ) - ASSERT

    Attempt to pair - FAILURE

    The below is a very crude form of the test setup. Sending 'h' through UART, makes the module switch to fixed passkey and sending 'c' through UART makes it switch to Just Works.

    I think this would show the failure condition. Can you please try this one? Please forgive the mess in the attached code. I have been trying a lot of things.

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Nordic UART Bridge Service (NUS) sample
     */
    #include "uart_async_adapter.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 <bluetooth/services/nus.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <zephyr/settings/settings.h>
    
    #include <stdio.h>
    
    #include <zephyr/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 = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart));
    static struct k_work_delayable 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),
    };
    
    #if CONFIG_BT_NUS_UART_ASYNC_ADAPTER
    UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
    #else
    static const struct device *const async_adapter;
    #endif
    
    static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
    {
    	ARG_UNUSED(dev);
    
    	static size_t aborted_len;
    	struct uart_data_t *buf;
    	static uint8_t *aborted_buf;
    	static bool disable_req;
    
    	switch (evt->type) {
    	case UART_TX_DONE:
    		LOG_DBG("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);
    
    		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_DBG("UART_RX_RDY");
    		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
    		buf->len += evt->data.rx.len;
    
    		if (disable_req) {
    			return;
    		}
    		if((evt->data.rx.buf[buf->len - 1] == 'c'))
    		{
    			printf("recieved %c",evt->data.rx.buf[buf->len - 1]);
    			update_ble();
    		}
    		if((evt->data.rx.buf[buf->len - 1] == 'h'))
    		{
    			printf("recieved %c",evt->data.rx.buf[buf->len - 1]);
    			update_ble2();
    		}
    		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
    		    (evt->data.rx.buf[buf->len - 1] == '\r')) {
    			disable_req = true;
    			uart_rx_disable(uart);
    		}
    
    		break;
    
    	case UART_RX_DISABLED:
    		LOG_DBG("UART_RX_DISABLED");
    		disable_req = false;
    
    		buf = k_malloc(sizeof(*buf));
    		if (buf) {
    			buf->len = 0;
    		} else {
    			LOG_WRN("Not able to allocate UART receive buffer");
    			k_work_reschedule(&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_DBG("UART_RX_BUF_REQUEST");
    		buf = k_malloc(sizeof(*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_DBG("UART_RX_BUF_RELEASED");
    		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
    				   data);
    
    		if (buf->len > 0) {
    			k_fifo_put(&fifo_uart_rx_data, buf);
    		} else {
    			k_free(buf);
    		}
    
    		break;
    
    	case UART_TX_ABORTED:
    		LOG_DBG("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:
    		break;
    	}
    }
    
    static void uart_work_handler(struct k_work *item)
    {
    	struct uart_data_t *buf;
    
    	buf = k_malloc(sizeof(*buf));
    	if (buf) {
    		buf->len = 0;
    	} else {
    		LOG_WRN("Not able to allocate UART receive buffer");
    		k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    		return;
    	}
    
    	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
    }
    
    static bool uart_test_async_api(const struct device *dev)
    {
    	const struct uart_driver_api *api =
    			(const struct uart_driver_api *)dev->api;
    
    	return (api->callback_set != NULL);
    }
    
    static int uart_init(void)
    {
    	int err;
    	int pos;
    	struct uart_data_t *rx;
    	struct uart_data_t *tx;
    
    	if (!device_is_ready(uart)) {
    		return -ENODEV;
    	}
    
    	if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) {
    		err = usb_enable(NULL);
    		if (err && (err != -EALREADY)) {
    			LOG_ERR("Failed to enable USB");
    			return err;
    		}
    	}
    
    	rx = k_malloc(sizeof(*rx));
    	if (rx) {
    		rx->len = 0;
    	} else {
    		return -ENOMEM;
    	}
    
    	k_work_init_delayable(&uart_work, uart_work_handler);
    
    
    	if (IS_ENABLED(CONFIG_BT_NUS_UART_ASYNC_ADAPTER) && !uart_test_async_api(uart)) {
    		/* Implement API adapter */
    		uart_async_adapter_init(async_adapter, uart);
    		uart = async_adapter;
    	}
    
    	err = uart_callback_set(uart, uart_cb, NULL);
    	if (err) {
    		LOG_ERR("Cannot initialize UART callback");
    		return err;
    	}
    
    	if (IS_ENABLED(CONFIG_UART_LINE_CTRL)) {
    		LOG_INF("Wait for DTR");
    		while (true) {
    			uint32_t dtr = 0;
    
    			uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
    			if (dtr) {
    				break;
    			}
    			/* Give CPU resources to low priority threads. */
    			k_sleep(K_MSEC(100));
    		}
    		LOG_INF("DTR set");
    		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DCD, 1);
    		if (err) {
    			LOG_WRN("Failed to set DCD, ret code %d", err);
    		}
    		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DSR, 1);
    		if (err) {
    			LOG_WRN("Failed to set DSR, ret code %d", err);
    		}
    	}
    
    	tx = k_malloc(sizeof(*tx));
    
    	if (tx) {
    		pos = snprintf(tx->data, sizeof(tx->data),
    			       "Starting Nordic UART service example\r\n");
    
    		if ((pos < 0) || (pos >= sizeof(tx->data))) {
    			k_free(tx);
    			LOG_ERR("snprintf returned %d", pos);
    			return -ENOMEM;
    		}
    
    		tx->len = pos;
    	} else {
    		return -ENOMEM;
    	}
    
    	err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    	if (err) {
    		LOG_ERR("Cannot display welcome message (err: %d)", 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", 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)", 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", addr, level);
    	} else {
    		LOG_WRN("Security failed: %s level %u err %d", addr,
    			level, err);
    	}
    }
    #endif
    
    BT_CONN_CB_DEFINE(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", 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);
    	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", 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", 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", addr, reason);
    }
    
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	//.passkey_display = auth_passkey_display,
    	.passkey_confirm = auth_passkey_confirm,
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_cb conn_auth_callbacks2 = {
    	.cancel = auth_cancel,
    };
    
    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;
    #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", addr);
    
    	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++;
    		}
    
    		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));
    	}
    }
    
    #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;
    }
    
    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);
    		}
    		
    	}
    	if (buttons & DK_BTN3_MSK) {
    			LOG_INF("BTN3");
    			printk("\n\r BTN3");
    			bt_unpair(BT_ID_DEFAULT,NULL);
    	}	
    	if (buttons & DK_BTN4_MSK) {
    			LOG_INF("BTN4");
    			printk("\n\r BTN4");
    			bt_passkey_set(BT_PASSKEY_INVALID);
    			bt_conn_auth_cb_register(NULL);
    			bt_conn_auth_cb_register(&conn_auth_callbacks2);
    			//bt_unpair(BT_ID_DEFAULT,NULL);
    	}	
    
    
    
    }
    #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
    
    static void configure_gpio(void)
    {
    	int err;
    
    #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
    	err = dk_buttons_init(button_changed);
    	if (err) {
    		LOG_ERR("Cannot init buttons (err: %d)", err);
    	}
    #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
    
    	err = dk_leds_init();
    	if (err) {
    		LOG_ERR("Cannot init LEDs (err: %d)", err);
    	}
    }
    
    void update_ble()
    {
    	printk("\n\r inside update");
    			bt_unpair(BT_ID_DEFAULT,NULL);
    			bt_passkey_set(BT_PASSKEY_INVALID);
    			bt_conn_auth_cb_register(NULL);
    			bt_conn_auth_cb_register(&conn_auth_callbacks2);
    }
    
    static unsigned passkey=123456;
    
    void update_ble2()
    {
    	printk("\n\r inside update_2");
    			bt_unpair(BT_ID_DEFAULT,NULL);
    			bt_passkey_set(passkey);
    			bt_conn_auth_cb_register(NULL);
    			bt_conn_auth_cb_register(&conn_auth_callbacks);
    }
    void main(void)
    {
    	int blink_status = 0;
    	int err = 0;
    
    	configure_gpio();
    	bt_passkey_set(passkey);
    	err = uart_init();
    	if (err) {
    		error();
    	}
    
    	if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			printk("Failed to register authorization callbacks.\n");
    			return;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			printk("Failed to register authorization info callbacks.\n");
    			return;
    		}
    	}
    
    	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);
    		return;
    	}
    	
    	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);
    		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);
    

Related