Page 1 of 1

Checking BLE descriptor in class from spawned task

Posted: Tue Jun 09, 2020 3:27 pm
by UriShX
Hi,
My question is mostly C++ and FreeRTOS related, so if that's not in the scope of this forum please let me know where I might take.
I've been trying to migrate some code I have in a single Arduino sketch to a class in a separate .h, so I can use it as a library.
My code uses JSON data sent over BLE for configuring WiFi credentials. The working (original) sketch can be found here:https://github.com/UriShX/esp32_wifi_bl ... ree/master, and my development branch is: https://github.com/UriShX/esp32_wifi_bl ... evelopment.
In my original sketch I used a task to update the client to which WiFi AP the ESP32 was connected to. When I moved the code to a separate class I tried to keep this behavior, but when I try to get the 0x2902 descriptor value through:

Code: Select all

<myClass>->myDescriptor->getValue()
I get "LoadProhibited" or "StoreProhibited" errors and resets.
I figured that the problem was with accessing the parent class, but my understanding of scope and dereferencing is not that good. I tried using a lambda function, but I am not sure where I should place it. Since getValue() returns a pointer, I thought I may try and get the pointer address once I initialize the descriptor, pass it on to the notification handler as an int, then create a second pointer within the task to point to the same address. I don't remember exactly how to do that, but if it's feasible I'll make it work.
Sorry for the long post, hope it's understandable.
Thanks,
Uri Sh.

Re: Checking BLE descriptor in class from spawned task

Posted: Wed Jun 10, 2020 9:02 am
by UriShX
Ok, tried referencing a pointer in the task to the location of a class pointer which in turn points to getValue(). That's what I think I did, at least.
In line 27 I declare a uint8_t pointer, then assign it to the getValue() pointer in line 203, after setting up the ble service. I then direct a pointer in the init section of the spawned task on line 251.
That seems to have stopped directing the task from invoking memory addresses which cause the device to crash. I still cannot be sure that it works, because now there's a new problem: for some reason the service does not display the notification service. I define the characteristic to have notifications and include a 2902 descriptor on lines 184-191, and have tried to define it both directly using ->addDescriptor(new BLE2902()) as well as indirectly, declaring a pointer to a descriptor, assigning it 2902, and then adding this descriptor to the characteristic.
I would sure appreciate some help on this subject.
Thanks.
  1. class BleWifiConfigInterface
  2. {
  3. protected:
  4.     // ESP32
  5.     /** BLE Service */
  6.     BLEService *pService;
  7.     /** BLE Server */
  8.     BLEServer *pServer;
  9.     /** Characteristic for digital output */
  10.     BLECharacteristic *pCharacteristicWiFi;
  11.     /** Characteristic for found WiFi list */
  12.     BLECharacteristic *pCharacteristicList;
  13.  
  14.     /** Private UUIDs */
  15.     std::string _sreviceUuid = DEF_SERVICE_UUID;
  16.     std::string _wifiUuid = DEF_WIFI_UUID;
  17.     std::string _listUuid = DEF_WIFI_LIST_UUID;
  18.     std::string _statusUuid = DEF_WIFI_STATUS_UUID;
  19.  
  20. public:
  21.     // callbacks
  22.     void (*_connectedCallback)() = NULL;
  23.     void (*_disconnectedCallback)() = NULL;
  24.     /** BLE connection status */
  25.     bool deviceConnected;
  26.     /** descriptor 2902 */
  27.     uint8_t *_stat2902;
  28.     /** Characteristic for connection status */
  29.     BLECharacteristic *pCharacteristicStatus;
  30.     BLEDescriptor *pStatusDescriptor;
  31.  
  32.     /** freeRTOS task handle */
  33.     TaskHandle_t sendBLEdataTask;
  34.     /** freeRTOS mutex handle */
  35.     SemaphoreHandle_t connStatSemaphore;
  36.     /** BLE Advertiser */
  37.     BLEAdvertising *pAdvertising;
  38.    
  39.     /** int representation of connected to primary ssid (1), secondary (2), or disconnected (0) */
  40.     uint16_t sendVal = 0x0000;
  41.  
  42.     /** Preferences */
  43.     /** SSIDs of local WiFi networks */
  44.     String ssidPrim;
  45.     String ssidSec;
  46.     /** Password for local WiFi network */
  47.     String pwPrim;
  48.     String pwSec;
  49.  
  50.     /** Unique device name */
  51.     String apName = "ESP32-xxxxxxxxxxxx";
  52.  
  53. protected:
  54.     /**
  55.      * Create unique device name from MAC address
  56.      **/
  57.     String createName()
  58.     {
  59.         String hostString = String((uint32_t)ESP.getEfuseMac(), HEX);
  60.         hostString.toUpperCase();
  61.         return "ESP32-" + hostString;
  62.     }
  63.  
  64.     void _init(std::string _sreviceUuid, std::string _wifiUuid, std::string _listUuid, std::string _statusUuid);
  65.  
  66.     inline bool _begin(const char *deviceName);
  67.  
  68.     void _startTask(void);
  69.  
  70.     static void sendBLEdata(void *parameter);
  71.  
  72.     void notifyFunc(uint16_t val)
  73.     {
  74.         Serial.println("notify func");
  75.         pCharacteristicStatus->setValue(val);
  76.         pCharacteristicStatus->notify(); // Send the value to the app!
  77.     }
  78.  
  79. public:
  80.     BleWifiConfigInterface() {}
  81.  
  82.     ~BleWifiConfigInterface() {}
  83.  
  84.     void onConnected(void (*fptr)())
  85.     {
  86.         _connectedCallback = fptr;
  87.     }
  88.  
  89.     void onDisconnected(void (*fptr)())
  90.     {
  91.         _disconnectedCallback = fptr;
  92.     }
  93.    
  94.     void init()
  95.     {
  96.         _sreviceUuid = DEF_SERVICE_UUID;
  97.         _wifiUuid = DEF_WIFI_UUID;
  98.         _listUuid = DEF_WIFI_LIST_UUID;
  99.         _statusUuid = DEF_WIFI_STATUS_UUID;
  100.  
  101.         _init(_sreviceUuid, _wifiUuid, _listUuid, _statusUuid);
  102.     }
  103.  
  104.  
  105.     inline bool begin()
  106.     {
  107.         return _begin(apName.c_str());
  108.     }
  109.  
  110. };
  111.  
  112. void BleWifiConfigInterface::_init(std::string _sreviceUuid, std::string _wifiUuid, std::string _listUuid, std::string _statusUuid)
  113. {
  114.     // Create unique device name
  115.     apName = createName();
  116.  
  117.     // start notification task
  118.     _startTask();
  119.  
  120.     Preferences BleWiFiPrefs;
  121.     BleWiFiPrefs.begin("BleWiFiCred", false);
  122.     bool hasPref = BleWiFiPrefs.getBool("valid", false);
  123.     if (hasPref)
  124.     {
  125.         ssidPrim = BleWiFiPrefs.getString("ssidPrim", "");
  126.         ssidSec = BleWiFiPrefs.getString("ssidSec", "");
  127.         pwPrim = BleWiFiPrefs.getString("pwPrim", "");
  128.         pwSec = BleWiFiPrefs.getString("pwSec", "");
  129.  
  130.         Serial.printf("%s,%s,%s,%s\n", ssidPrim.c_str(), pwPrim.c_str(), ssidSec.c_str(), pwSec.c_str());
  131.  
  132.         if (ssidPrim.equals("") || pwPrim.equals("") || ssidSec.equals("") || pwPrim.equals(""))
  133.         {
  134.             Serial.println("Found credentials but credentials are invalid");
  135.         }
  136.         else
  137.         {
  138.             Serial.println("Read from credentials:");
  139.             Serial.println("primary SSID: " + ssidPrim + " password: " + pwPrim);
  140.             Serial.println("secondary SSID: " + ssidSec + " password: " + pwSec);
  141.             hasCredentials = true;
  142.         }
  143.     }
  144.     else
  145.     {
  146.         Serial.println("Could not find credentials, need send data over BLE");
  147.     }
  148.     BleWiFiPrefs.end();
  149. }
  150.  
  151. bool BleWifiConfigInterface::_begin(const char *deviceName)
  152. {
  153.     if (BLEDevice::getInitialized())
  154.     {
  155.         return false;
  156.     }
  157.  
  158.     BLEDevice::init(deviceName);
  159.     BLEDevice::setPower(ESP_PWR_LVL_P7);
  160.  
  161.     // Create BLE Server
  162.     BLEServer *pServer = BLEDevice::createServer();
  163.  
  164.     // Set server callbacks
  165.     pServer->setCallbacks(new MyServerCallbacks(this));
  166.  
  167.     // Create BLE Service
  168.     BLEService *pService = pServer->createService(BLEUUID(_sreviceUuid), 20);
  169.  
  170.     // Create BLE Characteristic for WiFi settings
  171.     BLECharacteristic *pCharacteristicWiFi = pService->createCharacteristic(
  172.         BLEUUID(_wifiUuid),
  173.         // WIFI_UUID,
  174.         BLECharacteristic::PROPERTY_READ |
  175.             BLECharacteristic::PROPERTY_WRITE);
  176.     pCharacteristicWiFi->setCallbacks(new MyCallbackHandler(this));
  177.  
  178.     // Create BLE characteristic for found SSIDs
  179.     BLECharacteristic *pCharacteristicList = pService->createCharacteristic(
  180.         BLEUUID(_listUuid),
  181.         BLECharacteristic::PROPERTY_READ);
  182.     pCharacteristicList->setCallbacks(new ListCallbackHandler(this));
  183.  
  184.     // Create BLE Characteristic for status notifications
  185.     BLECharacteristic *pCharacteristicStatus = pService->createCharacteristic(
  186.         BLEUUID(_statusUuid),
  187.         BLECharacteristic::PROPERTY_NOTIFY);
  188.     // pCharacteristicStatus->setCallbacks(new MyCallbacks()); // If only notifications no need for callback?
  189.     BLEDescriptor *pStatusDescriptor = new BLE2902();
  190.     pCharacteristicStatus->addDescriptor(pStatusDescriptor);
  191.     // pCharacteristicStatus->addDescriptor(new BLE2902());
  192.  
  193.     // Start the service
  194.     pService->start();
  195.  
  196.     // Start advertising
  197.     BLEAdvertising *pAdvertising = pServer->getAdvertising();
  198.     pAdvertising->addServiceUUID(pService->getUUID());
  199.     pAdvertising->setScanResponse(true);
  200.     pAdvertising->start();
  201.  
  202.     // _stat2902 = pStatusDescriptor->getValue();
  203.     _stat2902 = pCharacteristicStatus->getDescriptorByUUID((uint16_t)0x2902)->getValue();
  204.  
  205.     return true;
  206. }
  207.  
  208. void BleWifiConfigInterface::_startTask()
  209. {
  210.     // Set up mutex semaphore
  211.     connStatSemaphore = xSemaphoreCreateMutex();
  212.  
  213.     if (connStatSemaphore == NULL)
  214.     {
  215.         Serial.println("Error creating connStatSemaphore");
  216.     }
  217.     else
  218.     {
  219.         Serial.println("Created connection status semaphore");
  220.     }
  221.  
  222.     // ble task
  223.     xTaskCreate(
  224.         sendBLEdata,
  225.         "sendBLEdataTask",
  226.         2048,
  227.         this,
  228.         1,
  229.         &sendBLEdataTask);
  230.     vTaskDelay(pdMS_TO_TICKS(500));
  231. }
  232.  
  233. /** BLE notification task
  234.  * works independently from loop(), in a separate freeRTOS task.
  235.  * if the esp32 device (server) is connected to a client, update the client every 1 second
  236.  * of the wifi connection status.
  237.  * in order to not cause interference between the two tasks, a mutex semaphore is used by the
  238.  * wifi connection callbacks which update the variable, loop(), and the notification task.
  239.  */
  240. void BleWifiConfigInterface::sendBLEdata(void *parameter)
  241. {
  242.     BleWifiConfigInterface *_bleWifiConfigInterface = (BleWifiConfigInterface *)parameter; //static_cast<BleWifiConfigInterface *>(parameter);
  243.  
  244.     TickType_t xLastWakeTime;
  245.     TickType_t xPeriod = pdMS_TO_TICKS(1000);
  246.  
  247.     xLastWakeTime = xTaskGetTickCount();
  248.  
  249.     bool notificationFlag = false;
  250.  
  251.     uint8_t *testNotify = &*_bleWifiConfigInterface->_stat2902;
  252.  
  253.     Serial.println("Starting notifiction task");
  254.  
  255.     while (1)
  256.     {
  257.         Serial.printf("Task loop. Connected: %x\n", _bleWifiConfigInterface->deviceConnected);
  258.  
  259.         // if the device is connected via BLE try to send notifications
  260.         if (_bleWifiConfigInterface->deviceConnected)
  261.         {
  262.             // Take mutex, set value, give mutex
  263.             xSemaphoreTake(_bleWifiConfigInterface->connStatSemaphore, 0);
  264.             uint16_t localSendVal = _bleWifiConfigInterface->sendVal;
  265.             xSemaphoreGive(_bleWifiConfigInterface->connStatSemaphore);
  266.  
  267.             Serial.printf("testNotify: %i sendVal: %i\n", testNotify, localSendVal);
  268.             // if enabled, send value over BLE
  269.             if (testNotify != 0)
  270.             {
  271.                 _bleWifiConfigInterface->notifyFunc(localSendVal);
  272.                 if (!notificationFlag)
  273.                 {
  274.                     Serial.println("started notification service");
  275.                     notificationFlag = true;
  276.                 }
  277.             }
  278.             else if (notificationFlag)
  279.             {
  280.                 // else print failure message to serial monitor
  281.                 Serial.print("notify failed, value of 0x2902 descriptor:\t");
  282.                 notificationFlag = false;
  283.             }
  284.         }
  285.         // sleep task for 1000 ms
  286.         vTaskDelayUntil(&xLastWakeTime, xPeriod);
  287.     }
  288. }

Re: Checking BLE descriptor in class from spawned task

Posted: Wed Jun 10, 2020 10:24 pm
by chegewara
Line 251:

Code: Select all

uint8_t *testNotify = &*_bleWifiConfigInterface->_stat2902;
here you have pointer testNotify,
then you are using it like a numeric value:

Code: Select all

Serial.printf("testNotify: %i sendVal: %i\n", testNotify, localSendVal);
            // if enabled, send value over BLE
            if (testNotify != 0)

Re: Checking BLE descriptor in class from spawned task

Posted: Wed Jun 10, 2020 10:40 pm
by UriShX
I'm trying to test if the notification descriptor is turned off or on, should I be doing it another way? In my original Arduino script it worked even though getValue() returns a pointer, so I never stopped to think about it.

In any case I can't really do anything with it since in my client I'm still not getting the 2902 descriptor. Don't really know why.

Re: Checking BLE descriptor in class from spawned task

Posted: Thu Jun 11, 2020 2:12 am
by chegewara
Couple things:
- _stat2902 is a pointer, so this is good uint8_t *testNotify = _bleWifiConfigInterface->_stat2902;
- if (testNotify != NULL && *testNotify != 0)

Re: Checking BLE descriptor in class from spawned task

Posted: Thu Jun 11, 2020 8:00 am
by UriShX
Thanks mate, I'm always happy to learn

Do you have any idea why the 2902 descriptor isn't showing? Can you maybe point me to how to check?