Page 1 of 1

Error during runtime after wrapping code in classes (Arduino IDE)

Posted: Mon Aug 05, 2019 12:12 pm
by JustNopIt
I am trying to write a Bluetooth LE Mouse library that works with the Arduino IDE.

Initially I had this code which worked just fine:

Code: Select all

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
#include <driver/adc.h>
#include "sdkconfig.h"
 
BLEHIDDevice* hid;
BLECharacteristic* inputMouse;
 
bool connected = false;
 
class MyCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer){
    connected = true;
    BLE2902* desc = (BLE2902*)inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
    desc->setNotifications(true);
  }
 
  void onDisconnect(BLEServer* pServer){
    connected = false;
    BLE2902* desc = (BLE2902*)inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
    desc->setNotifications(false);
  }
};
 
void taskServer(void*) {
  BLEDevice::init("Flip-O-Matic");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyCallbacks());
 
  hid = new BLEHIDDevice(pServer);
  inputMouse = hid->inputReport(1); // <-- input REPORTID from report map
 
  std::string name = "chegewara";
  hid->manufacturer()->setValue(name);
 
  hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
  hid->hidInfo(0x00,0x02);
 
  BLESecurity *pSecurity = new BLESecurity();
 
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
 
  const uint8_t reportMapMouse[] = {
    USAGE_PAGE(1),       0x01,
    USAGE(1),            0x02,
    COLLECTION(1),       0x01,
    REPORT_ID(1),        0x01,
    USAGE(1),            0x01,
    COLLECTION(1),       0x00,
    USAGE_PAGE(1),       0x09,
    USAGE_MINIMUM(1),    0x1,
    USAGE_MAXIMUM(1),    0x3,
    LOGICAL_MINIMUM(1),  0x0,
    LOGICAL_MAXIMUM(1),  0x1,
    REPORT_COUNT(1),     0x3,
    REPORT_SIZE(1),      0x1,
    0x80|0x01,           0x2,    // (Data, Variable, Absolute), ;3 button bits
    REPORT_COUNT(1),     0x1,
    REPORT_SIZE(1),      0x5,
    0x80|0x01,           0x1,    //(Constant), ;5 bit padding
    USAGE_PAGE(1),       0x1,    //(Generic Desktop),
    USAGE(1),            0x30,
    USAGE(1),            0x31,
    LOGICAL_MINIMUM(1),  0x81,
    LOGICAL_MAXIMUM(1),  0x7f,
    REPORT_SIZE(1),      0x8,
    REPORT_COUNT(1),     0x2,
    0x80|0x01,           0x6,    //(Data, Variable, Relative), ;2 position bytes (X & Y)
    END_COLLECTION(0),
    END_COLLECTION(0)
  };
 
  hid->reportMap((uint8_t*)reportMapMouse, sizeof(reportMapMouse));
  hid->startServices();
 
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->setAppearance(HID_MOUSE);
  pAdvertising->addServiceUUID(hid->hidService()->getUUID());
  pAdvertising->start();
  hid->setBatteryLevel(7);
 
  ESP_LOGD(LOG_TAG, "Advertising started!");
  delay(portMAX_DELAY);
};
 
void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  xTaskCreate(taskServer, "server", 20000, NULL, 5, NULL);
}
 
void loop() {
  if(connected) {
    Serial.println("Scroll Up by 1 unit");
    uint8_t msg[] = { 0x00, 0x00, 0x00, 0x01 };
    inputMouse->setValue(msg,4);
    inputMouse->notify();
   
  }
  delay(2000);
}
Then I tried to make a library out of that code which can be used like this:

Code: Select all

/**
 * This example turns the ESP32 into a Bluetooth LE mouse that scrolls down every 2 seconds.
 */
#include <BleMouse.h>

BleMouse bleMouse;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  bleMouse.init();
}

void loop() {
  if(bleMouse.isConnected()) {
    Serial.println("Scroll Down by 1 unit");
    bleMouse.scrollDown(1);
  }
  delay(2000);
}
The full code can be found here: https://github.com/T-vK/ESP32-BLE-Mouse
(But I'll also add it to the end of the post to make it easier.)

The example form above gets compiled and uploaded without any errors, but at soon as I try to connect to it via Bluetooth, the ESP32 prints the following error to the serial console:

Code: Select all

Starting BLE work!
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x400d39b8  PS      : 0x00060130  A0      : 0x800d2722  A1      : 0x3ffd5a90 
A2      : 0x00000018  A3      : 0x2e5470b4  A4      : 0xf0000000  A5      : 0x003ffe46 
A6      : 0xb03ffb00  A7      : 0x0001fe46  A8      : 0x3ffc607c  A9      : 0x3ffd5ad0 
A10     : 0x3ffe914c  A11     : 0x0000001c  A12     : 0x3ffe950c  A13     : 0x3ffe9554 
A14     : 0x00000002  A15     : 0x3ffd87e0  SAR     : 0x00000018  EXCCAUSE: 0x0000001c 
EXCVADDR: 0x00000024  LBEG    : 0x4000c349  LEND    : 0x4000c36b  LCOUNT  : 0xffffffff 

Backtrace: 0x400d39b8:0x3ffd5a90 0x400d271f:0x3ffd5af0 0x400d13ed:0x3ffd5b30 0x400d6019:0x3ffd5b70 0x400d3bd9:0x3ffd5bd0 0x400e440a:0x3ffd5bf0 0x400df23e:0x3ffd5c30 0x40090461:0x3ffd5c60

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:9232
load:0x40080400,len:6400
entry 0x400806a8
After decoding it looks like this:

Code: Select all

PC: 0x400d39b8: BLEDescriptorMap::getByUUID(BLEUUID) at /home/fedora/.arduino15/packages/esp32/hardware/esp32/1.0.2/libraries/BLE/src/BLEDescriptorMap.cpp line 33
EXCVADDR: 0x00000024

Decoding stack results
0x400d39b8: BLEDescriptorMap::getByUUID(BLEUUID) at /home/fedora/.arduino15/packages/esp32/hardware/esp32/1.0.2/libraries/BLE/src/BLEDescriptorMap.cpp line 33
0x400d271f: BLECharacteristic::getDescriptorByUUID(BLEUUID) at /home/fedora/.arduino15/packages/esp32/hardware/esp32/1.0.2/libraries/BLE/src/BLECharacteristic.cpp line 135
0x400d13ed: BleConnectionStatus::onConnect(BLEServer*) at /home/fedora/Arduino/libraries/ESP32-BLE-Mouse/BleConnectionStatus.cpp line 9
0x400d6019: BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t, unsigned char, esp_ble_gatts_cb_param_t*) at /home/fedora/.arduino15/packages/esp32/hardware/esp32/1.0.2/libraries/BLE/src/BLEServer.cpp line 171
0x400d3bd9: BLEDevice::gattServerEventHandler(esp_gatts_cb_event_t, unsigned char, esp_ble_gatts_cb_param_t*) at /home/fedora/.arduino15/packages/esp32/hardware/esp32/1.0.2/libraries/BLE/src/BLEDevice.cpp line 129
0x400e440a: btc_gatts_cb_handler at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c line 54
0x400df23e: btc_task at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/core/btc_task.c line 110
0x40090461: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c line 143
Any ideas how I could fix this? I guess it must be related to line 9 of the onConnect method in BleConnectionStatus.cpp because it says:

"0x400d13ed: BleConnectionStatus::onConnect(BLEServer*) at /home/fedora/Arduino/libraries/ESP32-BLE-Mouse/BleConnectionStatus.cpp line 9"

The code for the library:

BleMouse.h

Code: Select all

#ifndef ESP32_BLE_MOUSE_H
#define ESP32_BLE_MOUSE_H
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)

#include "BleConnectionStatus.h"
#include "BLEHIDDevice.h"
#include "BLECharacteristic.h"

class BleMouse {
public:
  BleMouse();
  void init();

  bool isConnected();
  void scrollDown(char units);
  void scrollUp(char units);
  void rawAction(uint8_t msg[], char msgSize);

private:
  BleConnectionStatus* connectionStatus;
  BLEHIDDevice* hid;
  BLECharacteristic* inputMouse;
  static void taskServer(void* pvParameter);
};

#endif // CONFIG_BT_ENABLED
#endif // ESP32_BLE_MOUSE_H
BleMouse.cpp

Code: Select all

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
#include <driver/adc.h>
#include "sdkconfig.h"

#include "BleConnectionStatus.h"
#include "BleMouse.h"

#if defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define LOG_TAG ""
#else
#include "esp_log.h"
static const char* LOG_TAG = "BLEDevice";
#endif

BleMouse::BleMouse() {
  this->connectionStatus = new BleConnectionStatus(this->inputMouse);
}

void BleMouse::init() {
  xTaskCreate(this->taskServer, "server", 20000, (void *)this, 5, NULL);
}

void BleMouse::taskServer(void* pvParameter) {
  BleMouse* bleMouseInstance = (BleMouse *) pvParameter; //static_cast<BleMouse *>(pvParameter);
  BLEDevice::init("ESP32-BLE-Mouse");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(bleMouseInstance->connectionStatus);

  bleMouseInstance->hid = new BLEHIDDevice(pServer);
  bleMouseInstance->inputMouse = bleMouseInstance->hid->inputReport(1); // <-- input REPORTID from report map

  std::string name = "chegewara";
  bleMouseInstance->hid->manufacturer()->setValue(name);

  bleMouseInstance->hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
  bleMouseInstance->hid->hidInfo(0x00,0x02);

  BLESecurity *pSecurity = new BLESecurity();

  pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);

  const uint8_t reportMapMouse[] = {
    USAGE_PAGE(1),       0x01,
    USAGE(1),            0x02,
    COLLECTION(1),       0x01,
    REPORT_ID(1),        0x01,
    USAGE(1),            0x01,
    COLLECTION(1),       0x00,
    USAGE_PAGE(1),       0x09,
    USAGE_MINIMUM(1),    0x1,
    USAGE_MAXIMUM(1),    0x3,
    LOGICAL_MINIMUM(1),  0x0,
    LOGICAL_MAXIMUM(1),  0x1,
    REPORT_COUNT(1),     0x3,
    REPORT_SIZE(1),      0x1,
    0x80|0x01,           0x2,    // (Data, Variable, Absolute), ;3 button bits
    REPORT_COUNT(1),     0x1,
    REPORT_SIZE(1),      0x5,
    0x80|0x01,           0x1,    //(Constant), ;5 bit padding
    USAGE_PAGE(1),       0x1,    //(Generic Desktop),
    USAGE(1),            0x30,
    USAGE(1),            0x31,
    USAGE(1),            0x38,
    LOGICAL_MINIMUM(1),  0x81,
    LOGICAL_MAXIMUM(1),  0x7f,
    REPORT_SIZE(1),      0x8,
    REPORT_COUNT(1),     0x3,
    0x80|0x01,           0x6,    //(Data, Variable, Relative), ;2 position bytes (X & Y)
    END_COLLECTION(0),
    END_COLLECTION(0)
  };

  bleMouseInstance->hid->reportMap((uint8_t*)reportMapMouse, sizeof(reportMapMouse));
  bleMouseInstance->hid->startServices();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->setAppearance(HID_MOUSE);
  pAdvertising->addServiceUUID(bleMouseInstance->hid->hidService()->getUUID());
  pAdvertising->start();
  bleMouseInstance->hid->setBatteryLevel(7);

  ESP_LOGD(LOG_TAG, "Advertising started!");
  vTaskDelay(portMAX_DELAY); //delay(portMAX_DELAY);
}

bool BleMouse::isConnected() {
  return this->connectionStatus->connected;
}

void BleMouse::rawAction(uint8_t msg[], char msgSize) {
  this->inputMouse->setValue(msg, msgSize);
  this->inputMouse->notify();
}

void BleMouse::scrollDown(char unit) {
  if(this->isConnected()) {
    uint8_t msg[] = { 0x00, 0x00, 0x00, -unit };
    this->rawAction(msg, 4);
  }
}

void BleMouse::scrollUp(char unit) {
  if(this->isConnected()) {
    uint8_t msg[] = { 0x00, 0x00, 0x00, unit };
    this->rawAction(msg, 4);
  }
}
BleConnectionStatus.h

Code: Select all

#ifndef ESP32_BLE_CONNECTION_STATUS_H
#define ESP32_BLE_CONNECTION_STATUS_H
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)

#include <BLEServer.h>
#include "BLE2902.h"
#include "BLECharacteristic.h"

class BleConnectionStatus : public BLEServerCallbacks {
public:
  BleConnectionStatus(BLECharacteristic* inputMouse);
  bool connected = false;
  void onConnect(BLEServer* pServer);
  void onDisconnect(BLEServer* pServer);
private:
  BLECharacteristic* inputMouse;
};

#endif // CONFIG_BT_ENABLED
#endif // ESP32_BLE_CONNECTION_STATUS_H
BleConnectionStatus.cpp

Code: Select all

#include "BleConnectionStatus.h"

BleConnectionStatus::BleConnectionStatus(BLECharacteristic* inputMouse) {
  this->inputMouse = inputMouse;
}

void BleConnectionStatus::onConnect(BLEServer* pServer) {
  this->connected = true;
  BLE2902* desc = (BLE2902*)this->inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
  desc->setNotifications(true);
}

void BleConnectionStatus::onDisconnect(BLEServer* pServer) {
  this->connected = false;
  BLE2902* desc = (BLE2902*)this->inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
  desc->setNotifications(false);
}

Re: Error during runtime after wrapping code in classes (Arduino IDE)

Posted: Mon Aug 05, 2019 3:13 pm
by boarchuz
You're passing around uninitialised pointers.

Re: Error during runtime after wrapping code in classes (Arduino IDE)

Posted: Mon Aug 05, 2019 4:39 pm
by JustNopIt
Oh, I wasn't aware that this wouldn't work.

If I make the inputMouse property of BleConnectionStatus public and set it every time in BleMouse::taskServer like this:

Code: Select all

bleMouseInstance->connectionStatus->inputMouse = bleMouseInstance->inputMouse;
it actually works. It just doesn't feel right.

But thanks anyway, this helped a lot! :)