Connecting to several peripherals with the same services

Hello,

I have 4 nrf52840, 3 act as peripheral and the last is the central.

The peripherals are identical hardware with various sensors using the same FW. I order to distingish the peripherals I am storing the "location" in NVM and dynamically setting the UUID of the primary service. 

I have locations "FL", "BL", "BR". An example of the services is show in the images.

The only difference between the location is the UUID of the advertised/primary service. UUID ending with "FL=28", "BL=27", and "BR=26". The peripherals are otherwise identical. I then add these UUID to the scan filter of my central and I am able to connect to each and, via the UUID, identify which location I have connected to.

The problem I am having when discovering and subscribing to the GATT services. When I connect to one of the locations, all is working great - no issues.

Let's say I connect and subscribe to FL. All good.

Then I turn on BL and it connects, all good. Then it continues to discover services. Then I get issues:
sometimes: bt_gatt_dm: discovery_process_attribute: Characteristic discover failed, error: -12.
and other times it goes to discovering handles: <wrn> gatt_handles: bt_atlas_handles_assign: Missing Fuel Gauge characteristic or descriptor
and other times it actually works

This all seems very random. I can easily connect to all 3 peripherals at the same time using nrfConnect on my phone. So I suspect the issue is with my implementation in the central.

here is the relevant code for the central

void client_connected(struct bt_conn *conn, uint8_t conn_err) {
    if (discovery_in_progress) {
        LOG_INF("GATT discovery already in progress, deferring connection.");
        return;
    }
    LOG_INF("\n\n--------------------- START CONNECTING ---------------------------------");

    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    LOG_INF("Connected: %s", addr);

    LOG_INF("The location is of each index is 0-%s 1-%s 2-%s",atlas_clients[0].location,atlas_clients[1].location,atlas_clients[2].location);

    // Assign to the next available client slot
    if (next_client_to_connect < MAX_CLIENTS) {
        LOG_INF("CONNECTING TO CLIENT NUMBER %i",next_client_to_connect);
        atlas_clients[next_client_to_connect].conn = bt_conn_ref(conn);
        atlas_clients[next_client_to_connect].client_index = next_client_to_connect;
        discovery_in_progress = true;  // Set flag for ongoing GATT discovery
        start_gatt_discovery(conn, next_client_to_connect,atlas_clients[next_client_to_connect].location);  // Start GATT discovery immediately
    } else {
        LOG_ERR("No available slots for additional connections.");
    }
}
 

So I start the gatt_discovery where I pass the connection, the array for the handles for the specific location, and the location

void start_gatt_discovery(struct bt_conn *conn, int client_index, const char *location) {
    LOG_INF("Starting GATT discovery for client %i with location %s", client_index, location);

    // Initialize the UUIDs for different locations
    struct bt_uuid_128 fl_uuid = BT_UUID_INIT_128(BT_UUID_ATLAS_SLAVE_FL_VAL);
    struct bt_uuid_128 bl_uuid = BT_UUID_INIT_128(BT_UUID_ATLAS_SLAVE_BL_VAL);
    struct bt_uuid_128 br_uuid = BT_UUID_INIT_128(BT_UUID_ATLAS_SLAVE_BR_VAL);

    struct bt_uuid *selected_uuid = NULL;

    // Match the location and select the corresponding UUID
    if (strcmp(location, "FL") == 0) {
        selected_uuid = (struct bt_uuid *)&fl_uuid;
    } else if (strcmp(location, "BL") == 0) {
        selected_uuid = (struct bt_uuid *)&bl_uuid;
    } else if (strcmp(location, "BR") == 0) {
        selected_uuid = (struct bt_uuid *)&br_uuid;
    } else {
        LOG_ERR("Invalid location %s for client %i", location, client_index);
        return;
    }

    // Start GATT discovery with the selected UUID
    int err = bt_gatt_dm_start(conn, selected_uuid, &discovery_cb, &atlas_clients[client_index]);
    if (err == 0) {
        char uuid_str[BT_UUID_STR_LEN];
        bt_uuid_to_str(selected_uuid, uuid_str, sizeof(uuid_str));
        LOG_INF("GATT discovery started with UUID %s for client %d", uuid_str, client_index);
        atlas_clients[client_index].status = CLIENT_DISCOVERING;
    } else {
        char uuid_str[BT_UUID_STR_LEN];
        bt_uuid_to_str(selected_uuid, uuid_str, sizeof(uuid_str));
        LOG_WRN("GATT discovery failed to start with UUID %s for client %d (err %d)", uuid_str, client_index, err);
    }
}

The GATT discovery is then started for the correct UUID primary service for that location.

Works great for one location, then has all sort of issues (and sometimes it works) when adding the 2nd and 3rd peripheral.

What is the better strategy here?

Related