BLE - Best way to stream several different variables? Also server callback issues.

moothyknight
Posts: 1
Joined: Thu Jul 26, 2018 1:14 am

BLE - Best way to stream several different variables? Also server callback issues.

Postby moothyknight » Thu Jul 26, 2018 1:25 am

Hello,

I'm using a modified BLE_uart demo from the arduino IDE to stream calculations from the device to a mobile app I have. I have two main issues troubling me:

1. What's the easiest way to stream multiple variables through the txValue? I want to output a hex string containing multiple variables at 860 samples per second (ADS1115 rate). Is there a simple command for this?
2. The server callbacks in the demo don't seem to correctly identify my device connection, as I want to make an LED blink when the connection starts.

For more info, I'm doing an open source biofeedback project and upgraded from a nano to an esp32 feather, so any help is much appreciated. I'll put the code sample below. We have a slack channel set up, too: https://github.com/moothyknight/HEG_ESP ... /README.md

Code: Select all

#include <Wire.h>
#include <Adafruit_ADS1015.h>

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;


// HEG VARIABLES
bool DEBUG = true;
bool VIEW_ADC_VALUE = true;

  // PUT IR IN 12, AND RED IN 13
int16_t adc0; // Resulting 16 bit integer

//Setup ADS1115
Adafruit_ADS1115 ads;

float Voltage = 0.0;
float range = 32767; // 16 bit ADC (15 bits of range minus one)
float gain = 0.256; // +/- V
float bits2mv = gain / range;

//Signal flags
bool first_led = false; // Bool to alternate LEDS
bool badSignal = false;
bool signalDetermined = false;

//Counters
int ticks0 = 0;
int ticks1 = 0;
int ticks2 = 0;

//Scoring variables
long redValue = 0;
long irValue = 0;
float redavg = 0;
float iravg = 0;
float ratio = 0;
float baseline = 0;
float score = 0;

//Timing variables
unsigned long startMillis;
unsigned long currentMillis;
unsigned long ledMillis;
unsigned long BLEMillis;

//Make sure these divide without remainders for best results
const unsigned long ledRate = 500; // LED flash rate (ms)
const unsigned long sampleRate = 2; // ADC read rate (ms). ADS1115 has a max of 860sps or 1/860 * 1000 ms


// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"


class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {

        Serial.println("*********");
        Serial.print("Received Value: ");
        for(int i=0; i<rxValue.length(); i++) {
            Serial.print(rxValue[i]);
        }

        Serial.println();
        Serial.println("*********");
      }
      
    }
};

void StartADS() {
  // Begin ADS
  ads.begin();
  ads.setGain(GAIN_SIXTEEN);

  //ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV (default)
  //ads.setGain(GAIN_ONE);     // 1x gain   +/- 4.096V  1 bit = 2mV
  //ads.setGain(GAIN_TWO);     // 2x gain   +/- 2.048V  1 bit = 1mV
  //ads.setGain(GAIN_FOUR);    // 4x gain   +/- 1.024V  1 bit = 0.5mV
  //ads.setGain(GAIN_EIGHT);   // 8x gain   +/- 0.512V  1 bit = 0.25mV
  //ads.setGain(GAIN_SIXTEEN); // 16x gain  +/- 0.256V  1 bit = 0.125mV
  
  //Start timers
  startMillis = millis();
  ledMillis = millis();
  BLEMillis = millis();
}



void setup() {
  Serial.begin(115200);
  
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  
  Serial.println("Starting BLE work!");
  
  BLEDevice::init("ESP32 HEG");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
										CHARACTERISTIC_UUID_TX,
										BLECharacteristic::PROPERTY_NOTIFY
									);
                      
  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
											 CHARACTERISTIC_UUID_RX,
											BLECharacteristic::PROPERTY_WRITE
										);

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");

}

void loop() {

    if (deviceConnected) {
      
        currentMillis = millis();
        if(currentMillis - startMillis >= sampleRate) {
      
          // read the analog in value:
          adc0 = ads.readADC_SingleEnded(0);
          //Voltage = (adc0 * bits2mv);
          
          // print the results to the Serial Monitor:
          if (VIEW_ADC_VALUE == true) {
            Serial.println("ADC Value: ");
            Serial.println(adc0);
            //Serial.println("\tVoltage: "); 
            //Serial.println(Voltage,7);
          }
          if (DEBUG == false) {
            if(adc0 >= 10000) { // The gain is high but anything over 10000 is most likely not a valid signal
              Serial.println("\nBad Read ");
              badSignal = true;
        
              //Temp: reset baseline on bad read
              signalDetermined = false;
              baseline = 0;
        
              ticks0 = 0; // Reset counter
              ticks1 = 0;
              ticks2 = 0;
              redValue = 0; // Reset values
              irValue = 0;
            }
            else {
              badSignal = false;
              if(signalDetermined == false){
                ticks0++;
                if(ticks0 > 100) { // Wait for 100 samples of good signal before getting baseline
                  // IR IN D2, RED IN D3
                  if((ticks1 < 500) && (ticks2 < 500)) { // Accumulate samples for baseline
                    if(first_led == true) { // RED
                      redValue += adc0;
                      ticks1++;
                    }
                    else { // IR
                      irValue += adc0;
                      ticks2++;
                    }
                    Serial.println("\nGetting Baseline. . .");
                  }
                  else {
                    signalDetermined = true;
                    redavg = redValue / ticks1;
                    iravg = irValue / ticks2;
        
                    baseline = redavg / iravg; // Set baseline ratio
                    ticks0 = 0; // Reset counters
                    ticks1 = 0;
                    ticks2 = 0;
                    redValue = 0; // Reset values
                    irValue = 0;
                    
                    //Uncomment this
                    Serial.println("\tBaseline R: ");
                    Serial.print(baseline);
                  }
                }
              }
              else {
                ticks0++;
                if(first_led == true) { // RED
                  redValue += adc0;
                  ticks1++;
                }
                else { // IR
                  irValue += adc0;
                  ticks2++;
                }
                if((ticks2 > 50) && (ticks1 > 50)) { // Accumulate 50 samples per LED before taking reading
                  redavg = redValue / ticks1; // Divide value by number of samples accumulated
                  iravg = irValue / ticks2;
                  ratio = redavg / iravg; // Get ratio
                  score += ratio - baseline; // Simple scoring method
                  
                  Serial.print("\tBaseline R: ");
                  Serial.print(baseline);
                  Serial.print("\tNow: ");
                  Serial.print(ratio);
                  Serial.print("\tScore: ");
                  Serial.print(score);
                  Serial.print("\n");
                  
                  ticks0 = 0; //Reset Counters
                  ticks1 = 0;
                  ticks2 = 0;
                  redValue = 0; //Reset values to get next average
                  irValue = 0;
                  
                }
              }
            }
            
            startMillis = currentMillis;
          }
        }
      
        // Switch LEDs back and forth.
        // PUT IR IN D2, AND RED IN D3
        if(currentMillis - ledMillis >= ledRate) {
          if(first_led == false) {
            digitalWrite(3,HIGH);
            digitalWrite(2,LOW);
            first_led = true;
          }
          else {
            digitalWrite(3,LOW);
            digitalWrite(2,HIGH);
            first_led = false;
          }
          ledMillis = currentMillis;
        }
      
        //End loop


        if(currentMillis - BLEMillis >= 10) { //Delay 10ms to not overwhelm bluetooth packets
          pTxCharacteristic->setValue(&txValue, 1);
          pTxCharacteristic->notify();
          txValue++;

          BLEMillis = currentMillis;
        }
	  }

    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
		// do stuff here on connecting
        StartADS();
        oldDeviceConnected = deviceConnected;
    }
}

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

Re: BLE - Best way to stream several different variables? Also server callback issues.

Postby chegewara » Fri Jul 27, 2018 5:00 am

1. Its not possible to achieve to send data 860 times per second; for ble minimum latency between 2 consecutive data transmissions is 7.5ms; but you can achieve this by packing few samples into one packet (up to 512 bytes)
2. if you could change log level to debug and post logs it would be helpful.

Who is online

Users browsing this forum: No registered users and 94 guests