Page 1 of 1

Why does event 21 appear as unhandled, and how can I troubleshoot it?

Posted: Sun Jan 12, 2025 1:52 am
by esp_padawan
BLE Passkey and Event Handling Issue on ESP32 Arduino Core v3.0.7 (ESP-IDF v5.1.4)

Problem Description:
Implementing BLE functionality on an ESP32 using **ESP32 Arduino Core v3.0.7**, which is based on **ESP-IDF v5.1.4**. The goal is to establish a secure BLE connection using Secure Connections with MITM (Man-In-The-Middle) protection. Despite correctly configuring BLE security, event handling, and passkey management, the BLE pairing process does not work as expected.

Observed Behavior:
1. GAP event 21 (`ESP_GAP_BLE_AUTH_CMPL_EVT`) does not log or behave as intended, even though it appears the pairing process is invoked.
2. BLE pairing and passkey mechanisms are not functioning correctly.
3. Security callbacks and GAP event handlers are correctly implemented but do not produce expected logs or responses during pairing.

Version Information:
- **ESP32 Arduino Core:** 3.0.7
- **ESP-IDF:** 5.1.4
- **Hardware:** ESP32-WROOM-32
- **nRF Connect App Version:** Latest as of January 2025

Minimal Example Code:
Below is the current implementation of BLE initialization and event handling:

Code: Select all

#include <BLEDevice.h>
#include <BLESecurity.h>
#include <esp_gap_ble_api.h>
#include "OLEDDisplay.h"

static uint32_t passkey = 0;
static bool isClientAuthenticated = false;

void gapEventHandler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param) {
    Serial.println("GAP Event Triggered: " + String(event));
    switch (event) {
        case ESP_GAP_BLE_AUTH_CMPL_EVT:
            Serial.println("ESP_GAP_BLE_AUTH_CMPL_EVT: Authentication complete.");
            if (param->ble_security.auth_cmpl.success) {
                Serial.println("Pairing successful.");
                isClientAuthenticated = true;
            } else {
                Serial.println("Pairing failed. Reason: " + String(param->ble_security.auth_cmpl.fail_reason));
                isClientAuthenticated = false;
            }
            break;

        case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
            Serial.println("ESP_GAP_BLE_PASSKEY_NOTIF_EVT: Passkey notification.");
            Serial.println("Passkey: " + String(param->ble_security.key_notif.passkey));
            OLEDDisplay::displayMessage("Passkey: ", String(param->ble_security.key_notif.passkey));
            break;

        case ESP_GAP_BLE_PASSKEY_REQ_EVT:
            Serial.println("ESP_GAP_BLE_PASSKEY_REQ_EVT: Passkey requested by the client.");
            Serial.println("Sending passkey: " + String(passkey));
            break;

        case ESP_GAP_BLE_SEC_REQ_EVT:
            Serial.println("ESP_GAP_BLE_SEC_REQ_EVT: Security request received.");
            esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
            break;

        default:
            Serial.println("Unhandled GAP event: " + String(event));
            break;
    }
}

class BLESecurityCallbacks : public ::BLESecurityCallbacks {
public:
    uint32_t onPassKeyRequest() override {
        Serial.println("onPassKeyRequest: Returning passkey.");
        return passkey;
    }

    void onPassKeyNotify(uint32_t passkey) override {
        Serial.println("onPassKeyNotify: Passkey notification.");
        Serial.println("Passkey: " + String(passkey));
    }

    bool onConfirmPIN(uint32_t passkey) override {
        Serial.println("onConfirmPIN: Confirming PIN.");
        return true;
    }

    void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl) override {
        if (auth_cmpl.success) {
            Serial.println("onAuthenticationComplete: Authentication successful.");
        } else {
            Serial.println("onAuthenticationComplete: Authentication failed.");
        }
    }
};

void begin(const String& deviceID) {
    Serial.println("Initializing BLE...");
    BLEDevice::init(deviceID.c_str());

    BLESecurity* pSecurity = new BLESecurity();
    pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM);
    pSecurity->setCapability(ESP_IO_CAP_OUT);
    pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
    pSecurity->setKeySize(16);

    BLEDevice::setSecurityCallbacks(new BLESecurityCallbacks());

    esp_ble_gap_register_callback(gapEventHandler);

    passkey = random(100000, 999999);
    Serial.println("Generated Passkey: " + String(passkey));
}
Key Configuration Details:
- **Security Mode:** `ESP_LE_AUTH_REQ_SC_MITM` (Secure Connections with MITM protection)
- **IO Capability:** `ESP_IO_CAP_OUT` (Output only, passkey displayed on OLED screen)
- **Key Distribution:** `ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK`

Steps to Reproduce:
1. Compile and upload the code to the ESP32 using Arduino IDE.
2. Use the nRF Connect app to scan for the BLE device and attempt to connect.
3. Monitor the Serial Monitor and nRF Connect logs during pairing.

Expected Behavior:
1. When pairing begins, the ESP32 should display the passkey via `ESP_GAP_BLE_PASSKEY_NOTIF_EVT`.
2. The `ESP_GAP_BLE_AUTH_CMPL_EVT` should confirm successful authentication.
3. Logs should indicate the progression of the pairing process.

Observed Behavior:
1. `ESP_GAP_BLE_PASSKEY_NOTIF_EVT` and `ESP_GAP_BLE_AUTH_CMPL_EVT` do not log as expected.
2. Pairing fails or does not complete, despite correct configurations.

Request for Assistance:
Need help identifying why:
1. GAP event `ESP_GAP_BLE_AUTH_CMPL_EVT` is not behaving as expected.
2. Passkey events and other GAP events do not trigger or log correctly.
3. The BLE pairing process is failing, even with proper configurations.

Any advice, debugging tips, or references to similar issues in ESP32 Arduino Core v3.0.7 would be greatly appreciated!