Hey,
In the code below bt_conn_disconnect function is executed but the connection is still there. My goal is that peripheral is able to disconnect the connected device if there is no data received after a certain time.
Code is here
/**************************************************************************//** * @file : ble.c * @date : Jan, 2023 * * @brief BLE Api. * *****************************************************************************/ // ---------------------------------------------------------------------------- // Include files // ---------------------------------------------------------------------------- #include <zephyr/logging/log.h> #include <zephyr/types.h> #include <zephyr/kernel.h> #include <stdio.h> #include <zephyr/dfu/mcuboot.h> #include <math.h> #include <soc.h> #include <app_event_manager.h> // BLE dependencies #include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/uuid.h> #include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/hci.h> #include <zephyr/settings/settings.h> #include <stdio.h> /* modules */ #include "../events/app_module_event.h" #include "../events/ble_module_event.h" #include "../events/debug_module_event.h" #include "../events/settings_module_event.h" #include "../events/common_module_event.h" #include "../events/message_module_event.h" #include "../system/modules_common.h" #include "ble.h" #include "test_service.h" #include "../utils/hardware.h" // ---------------------------------------------------------------------------- // Private definitions // ---------------------------------------------------------------------------- #define MODULE BLE_MODULE LOG_MODULE_REGISTER(MODULE, CONFIG_BLE_MODULE_LOG); /* Data module message queue. */ #define BLE_QUEUE_ENTRY_COUNT 10 #define BLE_QUEUE_BYTE_ALIGNMENT 4 #define STACKSIZE CONFIG_BT_TEST_THREAD_STACK_SIZE #define PRIORITY 7 #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) #define KEY_PASSKEY_ACCEPT DK_BTN1_MSK #define KEY_PASSKEY_REJECT DK_BTN2_MSK /** initialize a space in the slab memory */ // #define BLE_RX_BLOCK_SIZE (CONFIG_BT_L2CAP_TX_MTU - 3) // #define BLE_RX_BUF_COUNT 3 // #define BLE_SLAB_ALIGNMENT 4 // K_MEM_SLAB_DEFINE(ble_rx_slab, BLE_RX_BLOCK_SIZE, BLE_RX_BUF_COUNT, BLE_SLAB_ALIGNMENT); static K_SEM_DEFINE(ble_init_ok, 0, 1); static K_FIFO_DEFINE(fifo_ble_tx_data); static K_FIFO_DEFINE(fifo_ble_rx_data); /* BLE module super states. */ static enum state_type { STATE_BLE_INIT, STATE_BLE_READY, STATE_BLE_DISCONNECTED, STATE_BLE_CONNECTED, STATE_SHUTDOWN } state; // ---------------------------------------------------------------------------- // Private structs // ---------------------------------------------------------------------------- struct ble_msg_data { union { struct app_module_event app; struct settings_module_event settings; struct debug_module_event debug; struct message_module_event message; struct ble_module_event ble; } module; }; K_MSGQ_DEFINE(msgq_ble, sizeof(struct ble_msg_data), BLE_QUEUE_ENTRY_COUNT, BLE_QUEUE_BYTE_ALIGNMENT); typedef struct { struct module_data self; struct bt_conn *current_conn; struct bt_conn *auth_conn; configuration_t settings; string_t name; struct k_timer connection_timeout; struct k_sem conn_timeout_sema; }ble_t; // ---------------------------------------------------------------------------- // External declarations // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Private functions definitions // ---------------------------------------------------------------------------- static void message_handler(struct ble_msg_data *msg); static void ble_get_id(void); static void send_message(uint8_t * data, size_t len, enum ble_module_event_type type); static void connection_timeout_expirefun(struct k_timer *timer_id); static void ble_connection_tmr_start(void); static void ble_connection_tmr_stop(void); static int ble_enable(void); static void connection_thread_fn(void); // ---------------------------------------------------------------------------- // Private declarations // ---------------------------------------------------------------------------- static ble_t ble = { .self = {.name = "ble", .msg_q = &msgq_ble, .supports_shutdown = true }, .settings = {0}, .name = {0} }; /* todo: implement iBeacon */ // struct bt_le_adv_param adv_param_conn = // BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE | // BT_LE_ADV_OPT_NOTIFY_SCAN_REQ, // BT_GAP_ADV_FAST_INT_MIN_1, // BT_GAP_ADV_FAST_INT_MAX_1, // NULL); // 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_TEST_VAL), // }; // ---------------------------------------------------------------------------- // Private functions // ---------------------------------------------------------------------------- /* Convenience functions used in internal state handling. */ static char *state2str(enum state_type state) { switch (state) { case STATE_BLE_INIT: return "STATE_BLE_INIT"; case STATE_BLE_READY: return "STATE_BLE_READY"; case STATE_BLE_DISCONNECTED: return "STATE_BLE_DISCONNECTED"; case STATE_BLE_CONNECTED: return "STATE_BLE_CONNECTED"; case STATE_SHUTDOWN: return "STATE_SHUTDOWN"; default: return "Unknown"; } } static void state_set(enum state_type new_state) { if (new_state == state) { LOG_DBG("State: %s", state2str(state)); return; } LOG_DBG("State transition %s --> %s", state2str(state), state2str(new_state)); state = new_state; } 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); ble.current_conn = bt_conn_ref(conn); state_set(STATE_BLE_CONNECTED); ble_connection_tmr_start(); } 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); // not needed since is nubonded in pro.conf // bt_unpair(BT_ID_DEFAULT, NULL); if (ble.auth_conn) { bt_conn_unref(ble.auth_conn); ble.auth_conn = NULL; } if (ble.current_conn) { bt_conn_unref(ble.current_conn); ble.current_conn = NULL; } state_set(STATE_BLE_DISCONNECTED); } static void ble_get_id(void) { static struct bt_le_oob _oob = { .addr = 0 }; (void)bt_le_oob_get_local(BT_ID_DEFAULT, &_oob); ble.settings.serial_number.len = CONFIG_BLE_MAC_STR_LEN; (void)bt_addr_le_to_str(&_oob.addr, ble.settings.serial_number.array, ble.settings.serial_number.len); memset(&ble.name, 0, sizeof(string_t)); ble.name.len = snprintk(ble.name.array, sizeof(ble.name.array), "%s%s", get_hardware_name_prefix(ble.settings.hardware_settings.type), ble.settings.serial_number.array); LOG_INF("MAC: %s", ble.settings.serial_number.array); send_message(&ble.settings.serial_number, sizeof(string_t), BLE_EVT_SN_READY); } static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) { //If acceptable params, return true, otherwise return false. return true; } static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout) { struct bt_conn_info info; char addr[BT_ADDR_LE_STR_LEN]; if(bt_conn_get_info(conn, &info)) { LOG_INF("Could not parse connection info\n"); } else { bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); } } #ifdef CONFIG_BT_TEST_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, .le_param_req = le_param_req, .le_param_updated = le_param_updated, #ifdef CONFIG_BT_TEST_SECURITY_ENABLED .security_changed = security_changed, #endif }; #if defined(CONFIG_BT_TEST_SECURITY_ENABLED) 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_confirm(struct bt_conn *conn) { bt_conn_auth_cancel(conn); } 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 = NULL, .passkey_confirm = NULL, .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; static struct bt_conn_auth_info_cb conn_auth_info_callbacks; #endif static void send_message(uint8_t * data, size_t len, enum ble_module_event_type type) { struct ble_module_event *ble_module_event = new_ble_module_event(); __ASSERT(ble_module_event, "Not enough heap left to allocate event"); if (len > CONFIG_BLE_MAX_BUFFER) __ASSERT(ble_module_event, "Received messaged is much bigger than what is expected"); ble_module_event->type = type; ble_module_event->data.data.len = len; memcpy(ble_module_event->data.data.ptr, data, len); APP_EVENT_SUBMIT(ble_module_event); } 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_HEXDUMP_INF(data, len, "received data:"); send_message(data, len, BLE_EVT_DATA_RECEIVED); } static struct bt_test_cb test_cb = { .received = bt_receive_cb, }; void error(void) { while (true) { /* Spin for ever */ k_sleep(K_MSEC(1000)); } } static void connection_timeout_expirefun(struct k_timer *timer_id) { LOG_DBG("Connection BLE timeout timer is expired"); k_sem_give(&ble.conn_timeout_sema); } static void ble_connection_tmr_start(void) { k_timer_start(&ble.connection_timeout, K_SECONDS(CONFIG_BLE_CONNECTION_TIMEOUT), K_NO_WAIT); } static void ble_connection_tmr_stop(void) { k_timer_stop(&ble.connection_timeout); } /**************************************************************************//** * @brief Initialize BLE. *****************************************************************************/ int ble_init(void) { k_timer_init(&ble.connection_timeout, connection_timeout_expirefun, NULL); return ble_enable(); } /**************************************************************************//** * @brief Enable BLE. *****************************************************************************/ static int ble_enable() { int blink_status = 0; int err = 0; if (IS_ENABLED(CONFIG_BT_TEST_SECURITY_ENABLED)) { err = bt_conn_auth_cb_register(&conn_auth_callbacks); if (err) { LOG_ERR("Failed to register authorization callbacks."); return; } err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks); if (err) { LOG_ERR("Failed to register authorization info callbacks."); return; } } bt_set_bondable(false); bt_passkey_set(CONFIG_BLE_PASSKEY); err = bt_enable(NULL); if (err) { error(); } ble_get_id(); LOG_INF("Bluetooth Module started"); k_sem_give(&ble_init_ok); if (IS_ENABLED(CONFIG_SETTINGS)) { settings_load(); } err = bt_test_init(&test_cb); if (err) { LOG_ERR("Failed to initialize UART service (err: %d)", err); return; } 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, ble.name.array, ble.name.len), }; const struct bt_data sd[] = { BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_TEST_VAL), }; 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; } return 0; } /* Message handler for STATE_BLE_INIT. */ static void on_state_init(struct ble_msg_data *msg) { if (IS_EVENT(msg, settings, SETTINGS_EVT_CONFIG_READY)) { int err = ble_init(); __ASSERT(err == 0, "setp() failed"); memcpy(&ble.settings, &msg->module.settings.data.device.settings, sizeof(ble.settings)); state_set(STATE_BLE_READY); } } static void connection_thread_fn(void) { k_sem_init(&ble.conn_timeout_sema, 0, 1); for (;;) { if (k_sem_take(&ble.conn_timeout_sema, K_FOREVER) == 0) { LOG_DBG("Start to disconnect the device"); if (ble.current_conn != NULL) { bt_conn_disconnect(ble.current_conn, BT_HCI_ERR_CONN_TIMEOUT); } } } } static void module_thread_fn(void) { int err; struct ble_msg_data msg = { 0 }; ble.self.thread_id = k_current_get(); err = module_start(&ble.self); if (err) { LOG_ERR("Failed starting module, error: %d", err); SEND_ERROR(ble, BLE_EVT_ERROR, err); } state_set(STATE_BLE_INIT); while (true) { module_get_next_msg(&ble.self, &msg); switch (state) { case STATE_BLE_INIT: on_state_init(&msg); break; case STATE_BLE_CONNECTED: break; case STATE_BLE_READY: break; case STATE_SHUTDOWN: /* The shutdown state has no transition. */ break; default: LOG_ERR("Unknown state."); break; } message_handler(&msg); } } static void message_handler(struct ble_msg_data *msg) { if (IS_EVENT(msg, message, MESSAGE_EVT_DATA_READY_TO_SEND)) { bt_test_send(NULL, msg->module.message.data.data.ptr, msg->module.message.data.data.len); } } /* Handlers */ static bool ble_event_handler(const struct app_event_header *aeh) { struct ble_msg_data msg = {0}; bool enqueue_msg = false, consume = false; if (is_app_module_event(aeh)) { struct app_module_event *evt = cast_app_module_event(aeh); msg.module.app = *evt; enqueue_msg = true; LOG_DBG("Receiving message from the app"); } if (is_settings_module_event(aeh)) { struct settings_module_event *evt = cast_settings_module_event(aeh); msg.module.settings = *evt; enqueue_msg = true; LOG_DBG("Receiving message from the settings"); } if (is_debug_module_event(aeh)) { struct debug_module_event *evt = cast_debug_module_event(aeh); msg.module.debug = *evt; enqueue_msg = true; } if (is_message_module_event(aeh)) { struct message_module_event *evt = cast_message_module_event(aeh); msg.module.message = *evt; enqueue_msg = true; } if (enqueue_msg) { int err = module_enqueue_msg(&ble.self, &msg); if (err) { LOG_ERR("Message could not be enqueued"); SEND_ERROR(ble, BLE_EVT_ERROR, err); } } return false; } K_THREAD_DEFINE(ble_module_thread, CONFIG_BLE_THREAD_STACK_SIZE, module_thread_fn, NULL, NULL, NULL, K_LOWEST_APPLICATION_THREAD_PRIO, 0, 0); K_THREAD_DEFINE(ble_connection_timeout_thread, CONFIG_BLE_CONNECTION_TIMEOUT_THREAD_STACK_SIZE, connection_thread_fn, NULL, NULL, NULL, K_LOWEST_APPLICATION_THREAD_PRIO, 0, 0); APP_EVENT_LISTENER(MODULE, ble_event_handler); APP_EVENT_SUBSCRIBE(MODULE, app_module_event); APP_EVENT_SUBSCRIBE(MODULE, settings_module_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, message_module_event);
Thanks in advance!