Hello,
I have been working on the BLE communication of an Arduino nano BLE sense 33 with a MAX30102 sensor with a Wio Terminal to display for instance the infrared (IR) value. I have no problem for sending the temperature value. My main problem is that the IR value is 122000 so I need a 16bit value at least if I carry a substraction. I have also tried to separate the 16 bit value into 2 8 bit value but I didn't manage to write a proper notify callback function to retrieve it. Does anyone would have an idea how to change my code?
Here are some function from the rpcBLEDevice.h in BLERemoteCharacteristic file
std::string BLERemoteCharacteristic::readValue() {
// Check to see that we are connected.
if (!getRemoteService()->getClient()->isConnected()) {
return std::string();
}
m_semaphoreReadCharEvt.take("readValue");
client_attr_read(m_pRemoteService->getClient()->getConnId(), m_pRemoteService->getClient()->getGattcIf(),getHandle());
// Block waiting for the event that indicates that the read has completed. When it has, the std::string found
// in m_value will contain our data.
m_semaphoreReadCharEvt.wait("readValue");
return m_value;
} // readValue
/**
* @brief Read a byte value
* @return The value as a byte
*/
uint8_t BLERemoteCharacteristic::readUInt8() {
std::string value = readValue();
if (value.length() >= 1) {
return (uint8_t)value[0];
}
return 0;
} // readUInt8
/**
* @brief Read an unsigned 16 bit value
* @return The unsigned 16 bit value.
*/
uint16_t BLERemoteCharacteristic::readUInt16() {
std::string value = readValue();
if (value.length() >= 2) {
return *(uint16_t*)(value.data());
}
return 0;
} // readUInt16
My code on the Arduino Nano that I think is okay:
/*
* Device: Arduino Nano 33 BLE Sense
* Peripheral
* The values of the integrated temperature sensor and
* accelerometer are sent using BLE.
*/
#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h> //accelerometer sensor
#include <Arduino_HTS221.h> // temperature sensor
#include <Wire.h>
#include "MAX30105.h"
MAX30105 particleSensor;
int const d_t=0; //number of decimal to keep for the temperature
int const d_ir=0;
float tSensor=25;
int irSensor=0;
int tBLE=floor(tSensor*pow(10,d_t)+0.5);
int irBLE=irSensor;
int compteur=0;
BLEService SensorService("1101");
BLEUnsignedIntCharacteristic TChar("2104", BLERead | BLENotify);
BLEUnsignedIntCharacteristic IRChar("2107", BLERead | BLENotify);
void setup() {
IMU.begin();
HTS.begin();
Serial.begin(9600);
while (!Serial);
pinMode(LED_BUILTIN, OUTPUT);
if (!BLE.begin()) {
Serial.println("BLE failed to Initiate");
//delay(500);
while (1);
}
BLE.setLocalName("Arduino XYZT (peripheral)");
BLE.setAdvertisedService(SensorService);
SensorService.addCharacteristic(TChar);
SensorService.addCharacteristic(IRChar);
BLE.addService(SensorService);
TChar.writeValue(tBLE);
IRChar.writeValue(irBLE);
BLE.advertise();
Serial.println("Arduino XYZT peripheral device is now active, waiting for connections...");
//initialisation from Example4_HeartBeatPlotter
Serial.begin(115200);
Serial.println("Initializing...");
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
//Setup to sense a nice looking saw tooth on the plotter
byte ledBrightness = 0x1F; //Options: 0=Off to 255=50mA
byte sampleAverage = 8; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 3; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
int sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; //Options: 69, 118, 215, 411
int adcRange = 4096; //Options: 2048, 4096, 8192, 16384
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
//Arduino plotter auto-scales annoyingly. To get around this, pre-populate
//the plotter with 500 of an average reading from the sensor
//Take an average of IR readings at power up
const byte avgAmount = 64;
long baseValue = 0;
for (byte x = 0 ; x < avgAmount ; x++)
{
baseValue += particleSensor.getIR(); //Read the IR value
}
baseValue /= avgAmount;
//Pre-populate the plotter so that the Y scale is close to IR values
for (int x = 0 ; x < 500 ; x++)
Serial.println(baseValue);
}
void loop() {
Serial.print("inside the void loop \t");
compteur++;
Serial.print("compteur void loop \t");
Serial.println(compteur);
tSensor=HTS.readTemperature();
Serial.print(" tSensor \t");
Serial.println(tSensor);
irSensor=particleSensor.getIR();
Serial.print(" irSensor \t");
Serial.println(irSensor); //Send raw data to plotter
BLEDevice central = BLE.central();
BLE.advertise();
if (central) {
Serial.print("Connected to central: ");
Serial.print("* Device MAC address: ");
Serial.println(central.address());
digitalWrite(LED_BUILTIN, HIGH);
if (central.connected()) { // doesn't work if it is a while loop
tBLE=floor(tSensor*pow(10,d_t)+0.5);
Serial.print(" tBLE \t");
Serial.println(tBLE);
TChar.writeValue(tBLE);
Serial.print(" TChar ");
Serial.println(TChar.value());
int irBLE=floor(irSensor*pow(10,d_ir)+0.5);
Serial.print(" irBLE \t");
Serial.println(irBLE);
IRChar.writeValue(irBLE);
Serial.print(" IRChar ");
Serial.println(IRChar.value());
}
}
Serial.println("");
digitalWrite(LED_BUILTIN, LOW);
//Serial.print("Disconnected from central: ");
//Serial.println(central.address());
delay(1000);
}
Here is one of my attempt (the temperature part is okay), i get the error message
exit status 1
invalid conversion from 'void (*)(BLERemoteCharacteristic*, uint16_t*, size_t, bool) {aka void (*)(BLERemoteCharacteristic*, short unsigned int*, unsigned int, bool)}' to 'notify_callback {aka void (*)(BLERemoteCharacteristic*, unsigned char*, unsigned int, bool)}' [-fpermissive]
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara
*/
#include "rpcBLEDevice.h"
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include"TFT_eSPI.h"
TFT_eSPI tft;
// The remote service we wish to connect to.
//static BLEUUID serviceUUID(0xFEE0);
static BLEUUID serviceUUID(0x1101);
// The characteristic of the remote service we are interested in.
//static BLEUUID charUUID(0x2A2B);
static BLEUUID TcharUUID(0x2104);
static BLEUUID IRcharUUID(0x2107);
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pTChar;
static BLERemoteCharacteristic* pIRChar;
static BLEAdvertisedDevice* myDevice;
uint8_t bd_addr[6] = {0xD9, 0x91, 0xC0, 0x66, 0xAD, 0xF9};
BLEAddress BattServer(bd_addr);
//float tmp_T(0),deltaTmp_T(0);
int compteur=0;
int compteur2=0;
int compteur3=0;
int const d_ir=-2;
static void temperatureNotifyCallback(
BLERemoteCharacteristic* pTChar,
uint8_t* pTData,
size_t length,
bool isNotify) {
Serial.print("Notify callback for temperature characteristic ");
Serial.print(pTChar->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
Serial.print("data: ");
Serial.println(*(uint8_t *)pTData);
compteur3++;
Serial.print("compteur temperatureNotifyCallback \t");
Serial.println(compteur3);
//Serial.println(*pTData);
//Serial.println(pTData[0]);
tft.fillRect(200, 10, 100, 30, TFT_WHITE);
tft.drawString(String(*pTData), 200, 10);
}
static void irNotifyCallback(
BLERemoteCharacteristic* pIRChar,
uint16_t* pIRData,
size_t length,
bool isNotify) {
Serial.println("Notify callback for IR characteristic ");
Serial.print("IR_1 \t");
Serial.println(pIRChar->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
Serial.print("data: ");
Serial.println(*(uint16_t *)pIRData);
tft.fillRect(200, 40, 100, 30, TFT_WHITE);
tft.drawString(String(*pIRData), 200, 40);
}
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected = false;
Serial.println("onDisconnect");
}
};
bool connectToServer() {
Serial.println("Inside bool connectToServer ");
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
Serial.println(serviceUUID.toString().c_str());
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
//pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
pTChar = pRemoteService->getCharacteristic(TcharUUID);
pIRChar = pRemoteService->getCharacteristic(IRcharUUID);
if (pTChar == nullptr || pIRChar == nullptr) {
//if (pTChar == nullptr) {
Serial.print("Failed to find our characteristic UUID ");
// Serial.println(TcharUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our characteristic");
// Read the temperature characteristic value
if(pTChar->canRead()) {
Serial.println(" - can read start");
std::string value = pTChar->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
if(pTChar->canNotify())
pTChar->registerForNotify(temperatureNotifyCallback); // registerForNotify: function from BLERemoteCharacteristic (rpcBLE)
//Read the ir characteristic value
if(pIRChar->canRead()) {
Serial.println(" - can read start");
uint16_t IRvalue = pIRChar->readUInt16();
Serial.print("The characteristic value was: ");
//Serial.println(value.c_str());
Serial.println(IRvalue);
}
if(pIRChar->canNotify())
pIRChar->registerForNotify(irNotifyCallback);
compteur2 ++;
Serial.print("compteur connect to server");
Serial.println(compteur2);
connected = true;
return true;
Serial.println("End of bool connectToServer ");
}// bool connectToServer
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
* Also in BLEscan example but with a shorter onresult
*/
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { // crée une classe MyAdvertisedDeviceCallbacks qui hérite de la classe BLEAdvertisedDeviceCallbacks
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.println("Inside onResult ");
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are looking for.
//int memcmp ( const void * ptr1, const void * ptr2, size_t num );
//: Compares the first num bytes of the block of memory pointed by ptr1 to the first num bytes pointed by ptr2,
//returning zero if they all match or a value different from zero representing which is greater if they do not.
if (memcmp(advertisedDevice.getAddress().getNative(),BattServer.getNative(), 6) == 0) {
Serial.print("BATT Device found: ");
Serial.println(advertisedDevice.toString().c_str());
BLEDevice::getScan()->stop();
Serial.println("new BLEAdvertisedDevice");
myDevice = new BLEAdvertisedDevice(advertisedDevice);
Serial.println("new BLEAdvertisedDevice done");
doConnect = true;
doScan = true;
}
Serial.print("doConnect status");
Serial.println(doConnect);
}// onResult
}; // MyAdvertisedDeviceCallbacks
void setup() {
//initialisation of the screen
tft.begin();
tft.setRotation(3);//
tft.fillScreen(TFT_WHITE);
tft.setTextSize(2); //sets the size of text
tft.setTextColor(TFT_BLACK); //sets the text colour to black
tft.drawString("Temperature", 0, 10);
tft.drawString("IR", 0, 40);
//initialisation of the serial connection
Serial.begin(115200);
//while(!Serial){};
//delay(2000);
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
} // End of setup.
// This is the Arduino main loop function.
void loop() {
Serial.print("inside the void loop \t");
compteur++;
Serial.print("compteur void loop \t");
Serial.println(compteur);
Serial.print("doConnect status ");
Serial.println(doConnect);
if (doConnect != true) {
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
Serial.println("scanning");
BLEScan* pBLEScan = BLEDevice::getScan(); // get scanner from our client device
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); // behaviour of the scanner each time it find another bluetooth device
//setAdvertisedDeviceCallbacks, setInterval, setWindow, setActiveScan methods from the librairy BLEscan
pBLEScan->setInterval(1349); // period between 2 active scans
pBLEScan->setWindow(449); // active scan time range
pBLEScan->setActiveScan(true);//beginning of the scan
pBLEScan->start(5, false);
}
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {//static boolean initialized as false
Serial.println("inside the if(doConnect==true) loop");
if (connectToServer()) {
Serial.println("inside the ConnectToServer loop");
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
}
Serial.println("end of if connectToServer");
//doConnect = false;
//display time information
}
delay(1000);
Serial.println("");
} // End of loop