h2zero / NimBLE-Arduino

A fork of the NimBLE library structured for compilation with Arduino, for use with ESP32, nRF5x.
https://h2zero.github.io/NimBLE-Arduino/
Apache License 2.0
672 stars 138 forks source link

I can´t find solution for this error. #531

Open Apvilchez opened 1 year ago

Apvilchez commented 1 year ago

Hello, first excuse me for my level of English. I have modified the server example to add some parts of code and when I compile and load it, the code hangs and I can't find an explanation. The code is composed of a service with no features, a service with two features, and a full battery service. When I compile and send in the ble monitor that I use, all the services appear and I can request the characteristics of the service that has both characteristics, but if I try to subscribe to the battery notification service 1 does not subscribe and 2 is blocked and no longer It lets me access the features of the other service. In the arduino ide serial monitor I don't see the microprocessor reset so I'm not experiencing an overflow of some kind (or so I think). I can be working indefinitely reading the two characteristics without problem, until I touch the battery. The most curious thing is that if I remove one of the service that has two characteristics, I can now connect to the notification service without problem and the system does not hang. I've tried with an esp32s and a wroom32 in case it was a compilation problem but it didn't solve the problem so I guess I'm doing something wrong in the code. Any idea what it could be?

#include <NimBLEDevice.h>

static NimBLEServer *pServer;
/**  None of these are required as they will be handled by the library with defaults. **
 **                       Remove as you see fit for your needs                        */
class ServerCallbacks: public NimBLEServerCallbacks {
    void onConnect(NimBLEServer* pServer) {
        Serial.println("Client connected");
        Serial.println("Multi-connect support: start advertising");
        NimBLEDevice::startAdvertising();
    };
    /** Alternative onConnect() method to extract details of the connection.
     *  See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
     */
    void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
        Serial.print("Client address: ");
        Serial.println(NimBLEAddress(desc->peer_ota_addr).toString().c_str());

        pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 60);
    };
    void onDisconnect(NimBLEServer* pServer) {
        Serial.println("Client disconnected - start advertising");
        NimBLEDevice::startAdvertising();
    };
    void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
        Serial.printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
    };

/********************* Security handled here **********************
****** Note: these are the same return values as defaults ********/
    uint32_t onPassKeyRequest(){
        Serial.println("Server Passkey Request");
        /** This should return a random 6 digit number for security
         *  or make your own static passkey as done here.
         */
        return 123456;
    };

    bool onConfirmPIN(uint32_t pass_key){
        Serial.print("The passkey YES/NO number: ");Serial.println(pass_key);
        /** Return false if passkeys don't match. */
        return true;
    };

    void onAuthenticationComplete(ble_gap_conn_desc* desc){
        /** Check that encryption was successful, if not we disconnect the client */
        if(!desc->sec_state.encrypted) {
            NimBLEDevice::getServer()->disconnect(desc->conn_handle);
            Serial.println("Encrypt connection failed - disconnecting client");
            return;
        }
        Serial.println("Starting BLE work!");
    };
};

/** Handler class for characteristic actions */
class CharacteristicCallbacks: public NimBLECharacteristicCallbacks {
    void onRead(NimBLECharacteristic* pCharacteristic){
        Serial.print(pCharacteristic->getUUID().toString().c_str());
        Serial.print(": onRead(), value: ");
        Serial.println(pCharacteristic->getValue().c_str());
    };

    void onWrite(NimBLECharacteristic* pCharacteristic) {
        Serial.print(pCharacteristic->getUUID().toString().c_str());
        Serial.print(": onWrite(), value: ");
        Serial.println(pCharacteristic->getValue().c_str());
    };
    /** Called before notification or indication is sent,
     *  the value can be changed here before sending if desired.
     */
    void onNotify(NimBLECharacteristic* pCharacteristic) {
        Serial.println("Sending notification to clients");
    };

    /** The status returned in status is defined in NimBLECharacteristic.h.
     *  The value returned in code is the NimBLE host return code.
     */
    void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) {
        String str = ("Notification/Indication status code: ");
        str += status;
        str += ", return code: ";
        str += code;
        str += ", ";
        str += NimBLEUtils::returnCodeToString(code);
        Serial.println(str);
    };

    void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue) {
      Serial.println("OnSubscribe detected");
        String str = "Client ID: ";
        str += desc->conn_handle;
        str += " Address: ";
        str += std::string(NimBLEAddress(desc->peer_ota_addr)).c_str();
        if(subValue == 0) {
            str += " Unsubscribed to ";
        }else if(subValue == 1) {
            str += " Subscribed to notfications for ";
        } else if(subValue == 2) {
            str += " Subscribed to indications for ";
        } else if(subValue == 3) {
            str += " Subscribed to notifications and indications for ";
        }
        str += std::string(pCharacteristic->getUUID()).c_str();

        Serial.println(str);

    };
};

/** Handler class for descriptor actions */
class DescriptorCallbacks : public NimBLEDescriptorCallbacks {
    void onWrite(NimBLEDescriptor* pDescriptor) {
        std::string dscVal = pDescriptor->getValue();
        Serial.print("Descriptor witten value:");
        Serial.println(dscVal.c_str());
    };

    void onRead(NimBLEDescriptor* pDescriptor) {
        Serial.print(pDescriptor->getUUID().toString().c_str());
        Serial.println(" Descriptor read");
    };
};

/** Define callback instances globally to use for multiple Charateristics \ Descriptors */
static DescriptorCallbacks dscCallbacks;
static CharacteristicCallbacks chrCallbacks;

void setup() {
    Serial.begin(115200);
    Serial.println("Starting NimBLE Server in BlazePodTwo proyect");

  NimBLEDevice::init("MyBle");
    /** Optional: set the transmit power, default is 3db */
#ifdef ESP_PLATFORM
    NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
#else
    NimBLEDevice::setPower(9); /** +9db */
#endif

    NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
    pServer = NimBLEDevice::createServer();
    pServer->setCallbacks(new ServerCallbacks());

//NimBLEBatteryService batteryService("0000180F-0000-1000-8000-00805F9B34FB");
//NimBLEBatteryLevelCharacteristic batteryLevel("00002a19-0000-1000-8000-00805f9b34fb");
  NimBLEService* pParcelService = pServer->createService("10c323ba-4008-12a3-bbbb-0908ea180dd6");

    // DeviceInfoService
    #define SERIAL_NUMBER "56982"
    #define FIRMWARE_REVISION "1.4.22"

    NimBLEService* pDeviceInfoService = pServer->createService("0000180A-0000-1000-8000-0000000000AA");

//DeviceInfoService-Serial Number
    NimBLECharacteristic* pSerialNumberCharacteristic = pDeviceInfoService->createCharacteristic(
                                               ""00002A25-0000-1000-8000-0000000000aa",
                                               NIMBLE_PROPERTY::READ
                                               );
    pSerialNumberCharacteristic->setCallbacks(&chrCallbacks);
    pSerialNumberCharacteristic->setValue(SERIAL_NUMBER);

    NimBLECharacteristic* pFirmwareRevisionCharacteristic = pDeviceInfoService->createCharacteristic(
                                               "00002A26-0000-1000-8000-0000000000aa",
                                               NIMBLE_PROPERTY::READ
                                               );                                              
    pFirmwareRevisionCharacteristic->setCallbacks(&chrCallbacks);
    pFirmwareRevisionCharacteristic->setValue(FIRMWARE_REVISION);

  /*********************************** BatteryService **************************************/
    //BatteryService
    NimBLEService* pBatteryService = pServer->createService("0000180F-0000-1000-8000-0000000000aa");
    //BatteryService-BatteryLevel
    NimBLECharacteristic* pBatteryLevelCharacteristic = pBatteryService->createCharacteristic(
                                               "00002A19-0000-1000-8000-0000000000aa",
                                               NIMBLE_PROPERTY::READ |
                                               NIMBLE_PROPERTY::NOTIFY
                                               );

    pBatteryLevelCharacteristic->setCallbacks(&chrCallbacks);                                                   

    NimBLE2904* pBatteryLevelDescriptor = (NimBLE2904*)pBatteryLevelCharacteristic->createDescriptor("2904"); 
    pBatteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UTF8);
    pBatteryLevelDescriptor->setNamespace(1);
    pBatteryLevelDescriptor->setUnit(0x27ad);
    pBatteryLevelDescriptor->setCallbacks(&dscCallbacks);

    uint8_t batteryLevel = 88; // nivel de batería
    pBatteryLevelCharacteristic->setValue(&batteryLevel, 1);

    pParcelService->start();
    pDeviceInfoService->start();
    pBatteryService->start();

  NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(pParcelService->getUUID());
  pAdvertising->addServiceUUID(pDeviceInfoService->getUUID());
  pAdvertising->addServiceUUID(pBatteryService->getUUID());
  pAdvertising->setScanResponse(true);
  pAdvertising->setAppearance(0x0080);
  pAdvertising->start();
    Serial.println("Advertising Started");
  }

void loop() {
/*  batteryLevel = 98; // nivel de batería
  pBatteryLevelCharacteristic->setCallbacks(&chrCallbacks);
  pBatteryLevelCharacteristic->setValue(&batteryLevel, 1); // actualiza el valor de la característica
  pBatteryLevelCharacteristic->notify(); // notifica al cliente que el valor ha cambiado
  delay(5000);
*/
  }
h2zero commented 1 month ago

@Apvilchez Sorry I missed this, is this still an issue for you?