BLE library in a class

I’m trying to convert a set of functions I’ve used previously into a class so that my code is more contained.

I’m stuck when I add the BLE BleUuid & BleCharacteristics inside the class is getting errors about data not being defined. When leveling them globally to the .cpp file I get an error about two functions not being declared. ‘SsidReceived & onPasswordReceived are not defined’, I understand that they are outside the class scope so I’m trying to understand how to handle this. Any ideas would be appreciated.

Errors

wifi_setup.cpp: 
"onSsidReceived\" is undefined",
invalid use of non-static member function 'uint16_t WiFiSetup::onSsidReceived(const uint8_t*, size_t, const particle::BlePeerDevice&, void*)'
identifier "onPasswordReceived" is undefined
invalid use of non-static member function 'uint16_t WiFiSetup::onPasswordReceived(const uint8_t*, size_t, const particle::BlePeerDevice&, void*)'

wifi_setp.h

/****************************************************************************
 * bleWifi.h
 * Author: Orange Charger INC 
 * Date Created: Nov 24th 2021
 * Last Updated: Nov 24th 2021
 * By: Nicholas Johnson 
 * Test SSID 6269676d6f6e6b657973
 * Test PW 74776f62616e616e6173 
*****************************************************************************/

#include "Particle.h"

enum
{
    WIFI_SUCCCES,
    WIFI_NULL_ERROR,
    WIFI_NO_DAT_AVAIL,
    WIFI_RUN_ERROR,
    WIFI_COMM_ERR,
    WIFI_DATA_ERR,
};

typedef struct wifi_data_t{
    char devcie_ID[16];    
    // more data
} wifi_data_t;

class WiFiSetup 
{

    #define MAC_ADDRESS_ADDR 500
    #define IP_ADDRESS_ADDR  550

    public:
       
        // configure all BLE settings
        uint16_t setupBLE();
        // turn on BLE advertising 
        uint16_t startAdvertisement();
        // turn of BLE ad
        void stopAdvertisement();
        // get ip address 
        void getIpAddress(wifi_data_t *ipAddress);
        void getMacAddress(wifi_data_t *macAddress);
        // check WiFi signal strength 
        uint16_t devcieConnectionStrength();
        uint16_t onSsidReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);
        uint16_t onPasswordReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);
   
    private:
    uint16_t updateStatus(uint8_t status);

    protected:
        uint16_t has_wifi;
        wifi_data_t wifi_data;       
};




wifi_setup.cpp

#include "wifi_setup.h"
#include "sytm_data.h"

const BleUuid serviceUuid("22222-dc9e-469d-9ba6-34567842222");
const BleUuid wifiSsidUuid("222222-dc9e-469d-9ba6-34567842222");
const BleUuid wifiPasswordUuid("222222-dc9e-469d-9ba6-34567842222");
const BleUuid wifiConnectedUuid("2222222-dc9e-469d-9ba6-34567842222");

BleCharacteristic wifiSsidCharacteristic("wifi-ssid", BleCharacteristicProperty::WRITE, wifiSsidUuid, serviceUuid, *onSsidReceived, nullptr);
BleCharacteristic wifiPasswordCharacteristic("wifi-password", BleCharacteristicProperty::WRITE, wifiPasswordUuid, serviceUuid, *onPasswordReceived, nullptr);
BleCharacteristic wifiConnectedCharacteristic("wifi-connected", BleCharacteristicProperty::READ, wifiConnectedUuid, serviceUuid);


// SSID Char 
char _ssid[256];

// 0 = not connected
// 1 = connecting
// 2 = success
// 3+ = error
enum WiFiStatus : uint8_t {
    NOT_CONNECTED = 1,
    CONNECTING = 2,
    CONNECTED = 3,
    ERROR = 4
};

// Helper funtion to set the current state of teh connection 
uint16_t WiFiSetup::updateStatus(uint8_t status) {
    wifiConnectedCharacteristic.setValue(status);
    return 0;
}

// Setup the BLE Connection 
uint16_t WiFiSetup::setupBLE()
{
    BLE.addCharacteristic(wifiSsidCharacteristic);
    BLE.addCharacteristic(wifiPasswordCharacteristic);
    BLE.addCharacteristic(wifiConnectedCharacteristic);
    // Only Needed if using device OS 3.1
    // #if SYSTEM_VERSION == SYSTEM_VERSION_v310
    //     // This is required with 3.1.0 only
    //     BLE.setScanPhy(BlePhy::BLE_PHYS_AUTO);
    // #endif
    return 0;
}

//
uint16_t WiFiSetup::startAdvertisement()
{
    BLE.on();
    #if Wiring_WiFi
    WiFi.disconnect();
    #endif
    // WiFi.clearCredentials();
    // WiFi.listen();
    updateStatus(NOT_CONNECTED);
    uint8_t buf[BLE_MAX_ADV_DATA_LEN];
	size_t offset = 0;
    // TODO: get this from the EEPROM (X)
    // String outletId = getDataFromEPROM(DevcieID);
    // String outletId = getDevcieName(EEPROM_DEVCIE_NAME_ADDR);
    String outletId = "123345664939230";
    Log.info("Devcie Name: %s", outletId.c_str());
	memcpy(&buf[offset], outletId, outletId.length());
	offset += outletId.length();
    BleAdvertisingData data;
    data.appendLocalName(outletId);
    delay(2);
    // data.appendCustomData(buf, offset);
    BLE.advertise(&data);
    return 0;
}

// Helper funtion tro turn BLE off 
void WiFiSetup::stopAdvertisement()
{
    BLE.off();
}


// helper for when SSID is recived over BLE 
uint16_t WiFiSetup::onSsidReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) {
    // Log.trace("Received SSID from: %02X:%02X:%02X:%02X:%02X:%02X:", peer.address()[0], peer.address()[1], peer.address()[2], peer.address()[3], peer.address()[4], peer.address()[5]);
    // for (size_t ii = 0; ii < len; ii++) {
    //     Serial.write(data[ii]);
    // }
    // Serial.write('\n');
    memcpy(&_ssid, data, len);
    _ssid[len] = '\0';
    return 0;
}

// Helper for when password is recived over BLE 
uint16_t WiFiSetup::onPasswordReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) 
{
    // Log.trace("Received PASSWORD from: %02X:%02X:%02X:%02X:%02X:%02X:", peer.address()[0], peer.address()[1], peer.address()[2], peer.address()[3], peer.address()[4], peer.address()[5]);
    // for (size_t ii = 0; ii < len; ii++) {
    //     Serial.write(data[ii]);
    // }
    // Serial.write('\n');
    char _password[256];
    memcpy(&_password, data, len);
    _password[len] = '\0';
    // Turn Wifi On and Send Connection Credentails 
    #if Wiring_WiFi
    WiFi.on();
    WiFi.setCredentials(_ssid, _password);
    WiFi.connect();
    WiFi.listen(false);
    #endif
    Particle.connect();
    // Update Status to over BLE 
    updateStatus(WiFiStatus::NOT_CONNECTED);
    #if Wiring_WiFi
    for (int i = 0; i < 100; i++) 
    {
        if (WiFi.ready()) 
        {
            break;
        } 
        delay(250);
    }   
    if (WiFi.ready()) {
        updateStatus(WiFiStatus::CONNECTED);
        delay(10);
        if(Particle.connected()){
            stopAdvertisement();
        }
    } else {
        updateStatus(WiFiStatus::ERROR);
        WiFi.listen();
    }
    #endif
    return 0;
}
1 Like

You need an instance of your WiFiSetup class. You might have this in a global variable, or you’ve allocated it somewhere else with new. You need to pass both the member and the instance pointer when creating the characteristic, something like this:

WiFiSetup myWiFiSetupInstance;

BleCharacteristic wifiSsidCharacteristic("wifi-ssid", BleCharacteristicProperty::WRITE, wifiSsidUuid, serviceUuid, &WiFiSetup::onSsidReceived, &myWiFiSetupInstance);

BleCharacteristic wifiPasswordCharacteristic("wifi-password", BleCharacteristicProperty::WRITE, wifiPasswordUuid, serviceUuid, &WiFiSetup::onPasswordReceived, &myWiFiSetupInstance);

2 Likes

Thanks, @rickkas7 this &WiFiSetup::onSsidReceived, &myWiFiSetupInstance fixed the issue.

On a different note, I’m getting these errors after going through the BLE/WiFi setup.

0000345563 [app] INFO: button held for 8396
0000345564 [app] INFO: WIFI INIT STATE
0000345589 [system] ERROR: sock_send returned -1 118
0000345589 [comm.dtls] WARN: mbedtls_ssl_write returned ffffffff
0000345592 [comm.protocol] ERROR: Event loop error 3
0000345593 [system] WARN: Communication loop error, closing cloud socket
0000345615 [wiring.ble] ERROR: Duplicated characteristic cannot be added.
0000345615 [wiring.ble] ERROR: Duplicated characteristic cannot be added.
0000345616 [wiring.ble] ERROR: Duplicated characteristic cannot be added.
0000345616 [app] INFO: Start Ble Advertisement
0000350961 [system] ERROR: Failed to load session data from persistent storage

Start BLE

{
    Log.info("Start Ble Advertisement");
    BLE.on();
    delay(5);
    // WiFi.disconnect();
    updateStatus(WiFiStatus::NOT_CONNECTED);
	// size_t offset = 0;
    // TODO: get this from the EEPROM
    String outletId = "5IUs1XMCDFxJsit8";
    BleAdvertisingData data;
    data.appendLocalName(outletId);
    delay(5);
    // data.appendCustomData(buf, offset);
    BLE.advertise(&data);  
}

Once the password is received it tries connecting to the internet and once connected the process should go to idle. Except it goes into an infinite loop of connecting and disconnecting in this state.

// Helper for when password is recived over BLE
void onPasswordReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) 
{
    // Log.trace("Received PASSWORD from: %02X:%02X:%02X:%02X:%02X:%02X:", peer.address()[0], peer.address()[1], peer.address()[2], peer.address()[3], peer.address()[4], peer.address()[5]);
    // for (size_t ii = 0; ii < len; ii++) {
    //     Serial.write(data[ii]);
    // }
    // Serial.write('\n');
    char _password[256];
    memcpy(&_password, data, len);
    _password[len] = '\0';
    // Turn Wifi On and Send Connection Credentails 
    #if Wiring_WiFi
    WiFi.on();
    WiFi.setCredentials(_ssid, _password);
    WiFi.connect();
    WiFi.listen(false);
    #endif
    Particle.connect();
    // Update Status to over BLE 
    updateStatus(WiFiStatus::NOT_CONNECTED);
    #if Wiring_WiFi
    for (int i = 0; i < 100; i++) 
    {
        if (WiFi.ready()) 
        {
            break;
        } 
        delay(250);
    }   
    if (WiFi.ready()) {
        updateStatus(WiFiStatus::CONNECTED);
        delay(10);
        if(Particle.connected()){
            stopAdvertisement();
        }
    } else {
        updateStatus(WiFiStatus::ERROR);
        WiFi.listen();
    }
    #endif
}

Hi Nicholas,

you could draw inspiration from this library BLE GROUP, done by a Particle employee at the time (Mariano, now ex-Particle).

The library looks well contained and it's been battle-tested in the field now for some time.
Cheers,
Gustavo.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.