Multiple Bluetooth Connections

Hello everyone,

I'm working on a Bluetooth device using the Zephyr framework. I need to maintain a current connection while also continuing to advertise. If another device tries to connect simultaneously, I want to send a specific message indicating that only one connection is allowed at a time. Currently, the device stops advertising as soon as it connects to a device and resumes advertising only after the disconnection.

Summary of the Current Code and Issue:

  • Bluetooth connection: Advertising stops after a device connects; attempts to restart advertising fail.
  • Bluetooth disconnection: Advertising restarts properly after a device disconnects.
  • Desired behavior: Keep advertising even after a device connects, and send a custom message when another connection attempt is made.

Could anyone help me understand how to achieve this behavior? Is there a way to keep advertising after a connection is established and properly handle simultaneous connection attempts?

Thank you in advance for your assistance!

// Callbacks de conexão e desconexão Bluetooth
static void bluetooth_connected(struct bt_conn *conn, uint8_t error) {
    if (error) {
        _LOG_ERR("Failed to connect with BLE device!");
        return;
    }

    if (bt_conn_le_data_len_update(conn, BT_LE_DATA_LEN_PARAM_MAX) != 0) {
        _LOG_DBG("Error updating bt_conn length");
    }

    system_data.ble_connection_current = bt_conn_ref(conn);
    k_timer_start(&system_data.timer_disconnect, K_MSEC(TIMEOUT_MS_TO_DISCONNECT_BEFORE_AUTHORIZE), K_NO_WAIT);
}

static void bluetooth_disconnected(struct bt_conn *conn, uint8_t reason) {
    _LOG_INF("BLE disconnected, reason: %u", reason);
    if (system_data.state == OTA_TRANSFER) {
        free_all_ota_channels_memory();
        system_data.state = IDLE;
    }

    bt_conn_unref(system_data.ble_connection_current);
    system_data.ble_connection_current = NULL;
    k_timer_stop(&system_data.timer_disconnect);
}

// Parâmetros de publicidade Bluetooth
static struct bt_data packet_advertisement[] = {
    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_le_adv_param advertising_params = {
    .options = BT_LE_ADV_OPT_CONNECTABLE,
    .interval_min = BT_GAP_ADV_SLOW_INT_MIN,
    .interval_max = BT_GAP_ADV_SLOW_INT_MAX,
};

// Inicialização do Bluetooth
static int bluetooth_initialize() {
    if (bt_enable(NULL) != 0) {
        _LOG_ERR("Failed to enable Bluetooth!");
        return -1;
    }
    if (bt_le_adv_start(&advertising_params, packet_advertisement, ARRAY_SIZE(packet_advertisement), packet_scan_response, ARRAY_SIZE(packet_scan_response)) != 0) {
        _LOG_ERR("Failed to start advertising!");
        return -1;
    }
    return 0;
}

// Método para atualizar dados do fabricante
static void bluetooth_set_manufacturer_data(uint8_t* data) {
    memcpy(manufacturer_data.device_identifier, data, 8);
    if (bt_le_adv_update_data(packet_advertisement, ARRAY_SIZE(packet_advertisement), packet_scan_response, ARRAY_SIZE(packet_scan_response)) != 0) {
        _LOG_ERR("Could not update advertising data");
    }
}

// Notificação Bluetooth
static void bluetooth_notify_log(char level, char *format, ...) {
    if (level != 'E') {
        return;
    }
    char output[MAX_BLUETOOTH_LOG_MESSAGE_LENGTH];
    vsnprintf(output, sizeof(output), format, args);
    bt_gatt_notify(NULL, &gatt_service.attrs[14], output, strlen(output));
}

// Timer para desconectar Bluetooth
static void timer_disconnect_expiry_fn(struct k_timer *timer_id) {
    struct bt_conn_info connection_info;
    if (bt_conn_get_info(system_data.ble_connection_current, &connection_info) != 0) {
        _LOG_DBG("Could not get connection info from the current connection");
        return;
    }
    k_sem_give(&system_data.semaphore_disconnect);
}

Parents
  • Hello,

    I understand. What do you intend to use to connect with this device? Are you in control of that device as well? Either if you are developing the central, or you are writing a phone app or something?

    The way that pops up in my mind is that you only need to change a few things in your advertising packet before you restart advertising after you have connected to a device. The reason it fails to restart the advertising is probably that you are using the same advertising packet that the first one connected to. Since that initial advertisement flags itself as "connectable", restarting this will mean that you support another connection, but the CONFIG_BT_MAX_CONN is probably set to 1. This is the default value, so unless you specificed it to be something else in your prj.conf, then that is the issue. 

    So you have two options, as I see it. I recommend option 2, but I can describe both.

    1: Increase CONFIG_BT_MAX_CONN to 2. This way, you can send your custom message, and then disconnect if you have two connections. Then you will have to handle multiple connections, since there is no way of sending a custom message without being connected.

    2: Depending on what you mean by "custom message", I think the easiest way to do this is to use a different advertisement when you are connected. You can set up a non-connectable advertisement when you are in a connection. This is just a bit saying whether or not it is possible to connect to that advertising. 

    What you would want to do in this case is that you copy the struct on line 33 in your snippet, and create a non-connectable advertising_params in addition to your connectable. Then in your connected callback, you start advertising using this one instead. When you disconnect you stop advertising the non-connectable advertisements, and start advertising with the connectable set.

    If you want to, you can change other stuff in the advertisement as well, as change the name or whatever you prefer, but perhaps it is enough to change it to non-connectable, just to show that it is still alive, but it is currently busy with another connection.

    Best regards,

    Edvin

  • Hi Edvin,

    Thank you for your response and for outlining the two potential options.

    Device Control: Yes, I have control over both the BLE device and the central. I'm developing a phone app to connect to the BLE device.

    Display Custom Message: The custom message about the device being in use is meant to be displayed by the app itself. Therefore, using a non-connectable advertisement after establishing a connection might not work well for this purpose.

    Regarding the solutions:

    I tried increasing CONFIG_BT_MAX_CONN to 2, but I ran into a RAM overflow error during the build process:

    region 'RAM' overflowed by 1568 bytes

    It appears the additional memory needed for a second connection is causing this overflow. I'm unsure how to resolve this issue with the current RAM limitations.

    How can I fix it? Thanks again!

    Best regards,
    Johny

     

Reply
  • Hi Edvin,

    Thank you for your response and for outlining the two potential options.

    Device Control: Yes, I have control over both the BLE device and the central. I'm developing a phone app to connect to the BLE device.

    Display Custom Message: The custom message about the device being in use is meant to be displayed by the app itself. Therefore, using a non-connectable advertisement after establishing a connection might not work well for this purpose.

    Regarding the solutions:

    I tried increasing CONFIG_BT_MAX_CONN to 2, but I ran into a RAM overflow error during the build process:

    region 'RAM' overflowed by 1568 bytes

    It appears the additional memory needed for a second connection is causing this overflow. I'm unsure how to resolve this issue with the current RAM limitations.

    How can I fix it? Thanks again!

    Best regards,
    Johny

     

Children
  • JohnyPeters said:
    region 'RAM' overflowed by 1568 bytes

    Can you please share the entire build log?

    JohnyPeters said:
    Display Custom Message: The custom message about the device being in use is meant to be displayed by the app itself. Therefore, using a non-connectable advertisement after establishing a connection might not work well for this purpose.

    What app? Is this an app that you are maintaining? If so, I don't see the issue. Just check the advertisement and whether it is connectable or not. If it is not connectable, then you can assume it is in use by another device, and display that message.

    BR,
    Edvin

Related