Checking BLE descriptor in class from spawned task

UriShX
Posts: 4
Joined: Tue Jun 09, 2020 1:50 pm

Checking BLE descriptor in class from spawned task

Postby UriShX » Tue Jun 09, 2020 3:27 pm

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.

UriShX
Posts: 4
Joined: Tue Jun 09, 2020 1:50 pm

Re: Checking BLE descriptor in class from spawned task

Postby UriShX » Wed Jun 10, 2020 9:02 am

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. }

chegewara
Posts: 2228
Joined: Wed Jun 14, 2017 9:00 pm

Re: Checking BLE descriptor in class from spawned task

Postby chegewara » Wed Jun 10, 2020 10:24 pm

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)

UriShX
Posts: 4
Joined: Tue Jun 09, 2020 1:50 pm

Re: Checking BLE descriptor in class from spawned task

Postby UriShX » Wed Jun 10, 2020 10:40 pm

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.

chegewara
Posts: 2228
Joined: Wed Jun 14, 2017 9:00 pm

Re: Checking BLE descriptor in class from spawned task

Postby chegewara » Thu Jun 11, 2020 2:12 am

Couple things:
- _stat2902 is a pointer, so this is good uint8_t *testNotify = _bleWifiConfigInterface->_stat2902;
- if (testNotify != NULL && *testNotify != 0)

UriShX
Posts: 4
Joined: Tue Jun 09, 2020 1:50 pm

Re: Checking BLE descriptor in class from spawned task

Postby UriShX » Thu Jun 11, 2020 8:00 am

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?

Who is online

Users browsing this forum: No registered users and 57 guests