int bt_le_set_auto_conn(bt_addr_le_t *addr, const struct bt_le_conn_param *param) { struct bt_conn *conn; if (param && !bt_le_conn_params_valid(param->interval_min, param->interval_max, param->latency, param->timeout)) { return -EINVAL; } conn = bt_conn_lookup_addr_le(addr); if (!conn) { conn = bt_conn_add_le(addr); if (!conn) { return -ENOMEM; } } if (param) { bt_conn_set_param_le(conn, param); if (!atomic_test_and_set_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_ref(conn); } } else { if (atomic_test_and_clear_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_unref(conn); if (conn->state == BT_CONN_CONNECT_SCAN) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); } } } if (conn->state == BT_CONN_DISCONNECTED && atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { if (param) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); } bt_le_scan_update(false); } bt_conn_unref(conn); return 0; }
struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer, const bt_conn_state_t state) { int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { if (!atomic_get(&conns[i].ref)) { continue; } if (conns[i].type != BT_CONN_TYPE_LE) { continue; } if (peer && bt_addr_le_cmp(peer, &conns[i].le.dst)) { continue; } if (conns[i].state == state) { return bt_conn_ref(&conns[i]); } } return NULL; }
static void connected(struct bt_conn *conn, uint8_t err) { if (err) { printk("Connection failed (err %u)\n", err); } else { default_conn = bt_conn_ref(conn); printk("Connected\n"); } }
static void on_connected(struct bt_conn *conn, uint8_t err) { struct bt_conn_info info = { 0 }; bt_conn_get_info(conn, &info); if (!err) { if (info.role == BT_CONN_ROLE_SLAVE) { bt_conn_ref(conn); _ble_app_cb.conn_periph = conn; /* stop adv timer */ ble_app_stop_advertisement(); _ble_app_cb.conn_values.interval = info.le.interval; _ble_app_cb.conn_values.latency = info.le.latency; _ble_app_cb.conn_values.supervision_to = info.le.timeout; /* If peripheral and connection values are not compliant with the PPCP */ /* Start a timer to configure the parameters */ _ble_app_cb.conn_timer = timer_create( conn_params_timer_handler, NULL, 5000, false, true, NULL); } #if !defined(BLE_APP_DEBUG) pr_info(LOG_MODULE_MAIN, "BLE connected (conn: %p, role: %d)", conn, info.role); #else pr_info( LOG_MODULE_MAIN, "BLE connected (conn: %p, role: %d) to " "%02x:%02x:%02x:%02x:%02x:%02x/%d", conn, info.role, info.le.src->val[5], info.le.src->val[4], info.le.src->val[3], info.le.src->val[2], info.le.src->val[1], info.le.src->val[0], info.type); #endif #ifdef CONFIG_SYSTEM_EVENTS system_event_push_ble_conn(true, (uint8_t *)&info.le.src->val[0]); #endif } else { pr_info(LOG_MODULE_MAIN, "BLE connection KO(conn: %p)", conn); } }
struct bt_conn *bt_conn_lookup_handle(uint16_t handle) { int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { if (!atomic_get(&conns[i].ref)) { continue; } if (conns[i].handle == handle) { return bt_conn_ref(&conns[i]); } } return NULL; }
struct bt_conn *bt_conn_lookup_addr_le(const bt_addr_le_t *peer) { int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { if (!atomic_get(&conns[i].ref)) { continue; } if (!bt_addr_le_cmp(peer, &conns[i].dst)) { return bt_conn_ref(&conns[i]); } } return NULL; }
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer) { int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { if (!atomic_get(&conns[i].ref)) { continue; } if (conns[i].type != BT_CONN_TYPE_BR) { continue; } if (!bt_addr_cmp(peer, &conns[i].br.dst)) { return bt_conn_ref(&conns[i]); } } return NULL; }
struct bt_conn *bt_conn_lookup_handle(uint16_t handle) { int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { if (!atomic_get(&conns[i].ref)) { continue; } /* We only care about connections with a valid handle */ if (conns[i].state != BT_CONN_CONNECTED && conns[i].state != BT_CONN_DISCONNECT) { continue; } if (conns[i].handle == handle) { return bt_conn_ref(&conns[i]); } } return NULL; }
static int cmd_disconnect(int argc, char *argv[]) { struct bt_conn *conn; int err; if (default_conn && argc < 3) { conn = bt_conn_ref(default_conn); } else { bt_addr_le_t addr; if (argc < 3) { return -EINVAL; } err = str2bt_addr_le(argv[1], argv[2], &addr); if (err) { printk("Invalid peer address (err %d)\n", err); return 0; } conn = bt_conn_lookup_addr_le(&addr); } if (!conn) { printk("Not connected\n"); return 0; } err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); if (err) { printk("Disconnection failed (err %d)\n", err); } bt_conn_unref(conn); return 0; }
static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; conn_addr_str(conn, addr, sizeof(addr)); if (err) { printk("Failed to connect to %s (%u)\n", addr, err); goto done; } printk("Connected: %s\n", addr); if (!default_conn) { default_conn = bt_conn_ref(conn); } done: /* clear connection reference for sec mode 3 pairing */ if (pairing_conn) { bt_conn_unref(pairing_conn); pairing_conn = NULL; } }
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) { bt_conn_state_t old_state; BT_DBG("%s -> %s", state2str(conn->state), state2str(state)); if (conn->state == state) { BT_WARN("no transition"); return; } old_state = conn->state; conn->state = state; /* Actions needed for exiting the old state */ switch (old_state) { case BT_CONN_DISCONNECTED: /* Take a reference for the first state transition after * bt_conn_add_le() and keep it until reaching DISCONNECTED * again. */ bt_conn_ref(conn); break; case BT_CONN_CONNECT: if (conn->timeout) { fiber_delayed_start_cancel(conn->timeout); conn->timeout = NULL; /* Drop the reference taken by timeout fiber */ bt_conn_unref(conn); } break; default: break; } /* Actions needed for entering the new state */ switch (conn->state) { case BT_CONN_CONNECTED: nano_fifo_init(&conn->tx_queue); fiber_start(conn->stack, sizeof(conn->stack), conn_tx_fiber, (int)bt_conn_ref(conn), 0, 7, 0); bt_l2cap_connected(conn); notify_connected(conn); break; case BT_CONN_DISCONNECTED: /* Notify disconnection and queue a dummy buffer to wake * up and stop the tx fiber for states where it was * running. */ if (old_state == BT_CONN_CONNECTED || old_state == BT_CONN_DISCONNECT) { bt_l2cap_disconnected(conn); notify_disconnected(conn); nano_fifo_put(&conn->tx_queue, net_buf_get(&dummy, 0)); } else if (old_state == BT_CONN_CONNECT) { /* conn->err will be set in this case */ notify_connected(conn); } else if (old_state == BT_CONN_CONNECT_SCAN && conn->err) { /* this indicate LE Create Connection failed */ notify_connected(conn); } /* Release the reference we took for the very first * state transition. */ bt_conn_unref(conn); break; case BT_CONN_CONNECT_SCAN: break; case BT_CONN_CONNECT: /* * Timer is needed only for LE. For other link types controller * will handle connection timeout. */ if (conn->type != BT_CONN_TYPE_LE) { break; } /* Add LE Create Connection timeout */ conn->timeout = fiber_delayed_start(conn->stack, sizeof(conn->stack), timeout_fiber, (int)bt_conn_ref(conn), 0, 7, 0, CONN_TIMEOUT); break; case BT_CONN_DISCONNECT: break; default: BT_WARN("no valid (%u) state was set", state); break; } }