Go Down

Topic: BLE Central print out values of int characteristic (Read 332 times) previous topic - next topic

russell_roberts

I have run the Arduino BLE central & peripheral example & get them to work using a mar 1010 & nano 33 IOT.

But if I add a BLEIntCharacteristic I cannot get it to output correctly on the central

peripheral code
Code: [Select]



#include <ArduinoBLE.h>

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED
const int buttonPin = 4; // set buttonPin to digital pin 4

BLEService rledService("70083900-6225-4765-a4be-d0f793025c8b");  // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic ledCharacteristic("70083901-6225-4765-a4be-d0f793025c8b", BLERead | BLEWrite);
// create button characteristic and allow remote device to get notifications
BLEByteCharacteristic buttonCharacteristic("70083902-6225-4765-a4be-d0f793025c8b", BLERead | BLENotify);

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(buttonPin, INPUT); // use button pin as an input

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("RussButtonLED");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(rledService);

  // add the characteristics to the service
  rledService.addCharacteristic(ledCharacteristic);
  rledService.addCharacteristic(buttonCharacteristic);

  // add the service
  BLE.addService(rledService);

  ledCharacteristic.writeValue(0);
  buttonCharacteristic.writeValue(0);

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // poll for BLE events
  BLE.poll();

  // read the current button pin state
  char buttonValue = digitalRead(buttonPin);

  // has the value changed since the last read
  boolean buttonChanged = (buttonCharacteristic.value() != buttonValue);

  if (buttonChanged) {
    // button state changed, update characteristics
    ledCharacteristic.writeValue(buttonValue);
    buttonCharacteristic.writeValue(buttonValue);
  }

  if (ledCharacteristic.written() || buttonChanged) {
    // update LED, either central has written to characteristic or button state has changed
    if (ledCharacteristic.value()) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
  }
}



central code
Code: [Select]

/*
  LED Control

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button with pull-up resistor connected to pin 2.

  You can use it with another board that is compatible with this library and the
  Peripherals -> LED example.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForUuid("19B10010-E8F2-537E-4F6C-D104768A1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "ButtonLED") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19B10010-E8F2-537E-4F6C-D104768A1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19B10011-E8F2-537E-4F6C-D104768A1214");
  BLECharacteristic intyCharacteristic = peripheral.characteristic("19B10014-E8F2-537E-4F6C-D104768A1214");
  if (!ledCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  } else if (!ledCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable LED characteristic!");
    peripheral.disconnect();
    return;
  }

  while (peripheral.connected()) {
    // while the peripheral is connected

    // read the button pin
    int buttonState = digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // button changed
      oldButtonState = buttonState;

      if (buttonState) {
        byte value = 0;
        intyCharacteristic.readValue(value);
        Serial.print("inty value");
        Serial.println(value);
        Serial.println("button pressed");

        // button is pressed, write 0x01 to turn the LED on
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // button is released, write 0x00 to turn the LED off
        ledCharacteristic.writeValue((byte)0x00);
      }
    }
  }

  Serial.println("Peripheral disconnected");
}


Would really appreciate some advice

DrGee

I have run the Arduino BLE central & peripheral example & get them to work using a mar 1010 & nano 33 IOT.

But if I add a BLEIntCharacteristic I cannot get it to output correctly on the central

peripheral code
Code: [Select]



#include <ArduinoBLE.h>

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED
const int buttonPin = 4; // set buttonPin to digital pin 4

BLEService rledService("70083900-6225-4765-a4be-d0f793025c8b");  // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic ledCharacteristic("70083901-6225-4765-a4be-d0f793025c8b", BLERead | BLEWrite);
// create button characteristic and allow remote device to get notifications
BLEByteCharacteristic buttonCharacteristic("70083902-6225-4765-a4be-d0f793025c8b", BLERead | BLENotify);

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(buttonPin, INPUT); // use button pin as an input

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("RussButtonLED");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(rledService);

  // add the characteristics to the service
  rledService.addCharacteristic(ledCharacteristic);
  rledService.addCharacteristic(buttonCharacteristic);

  // add the service
  BLE.addService(rledService);

  ledCharacteristic.writeValue(0);
  buttonCharacteristic.writeValue(0);

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // poll for BLE events
  BLE.poll();

  // read the current button pin state
  char buttonValue = digitalRead(buttonPin);

  // has the value changed since the last read
  boolean buttonChanged = (buttonCharacteristic.value() != buttonValue);

  if (buttonChanged) {
    // button state changed, update characteristics
    ledCharacteristic.writeValue(buttonValue);
    buttonCharacteristic.writeValue(buttonValue);
  }

  if (ledCharacteristic.written() || buttonChanged) {
    // update LED, either central has written to characteristic or button state has changed
    if (ledCharacteristic.value()) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
  }
}



central code
Code: [Select]

/*
  LED Control

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button with pull-up resistor connected to pin 2.

  You can use it with another board that is compatible with this library and the
  Peripherals -> LED example.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForUuid("19B10010-E8F2-537E-4F6C-D104768A1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "ButtonLED") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19B10010-E8F2-537E-4F6C-D104768A1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19B10011-E8F2-537E-4F6C-D104768A1214");
  BLECharacteristic intyCharacteristic = peripheral.characteristic("19B10014-E8F2-537E-4F6C-D104768A1214");
  if (!ledCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  } else if (!ledCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable LED characteristic!");
    peripheral.disconnect();
    return;
  }

  while (peripheral.connected()) {
    // while the peripheral is connected

    // read the button pin
    int buttonState = digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // button changed
      oldButtonState = buttonState;

      if (buttonState) {
        byte value = 0;
        intyCharacteristic.readValue(value);
        Serial.print("inty value");
        Serial.println(value);
        Serial.println("button pressed");

        // button is pressed, write 0x01 to turn the LED on
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // button is released, write 0x00 to turn the LED off
        ledCharacteristic.writeValue((byte)0x00);
      }
    }
  }

  Serial.println("Peripheral disconnected");
}


Would really appreciate some advice
I don't have both a 1010 and nano, but taking a look at your code, I think you have several problems going on.

First, I would advise you to get and use something like nRF Master Control panel (or whatever it is called now). You can use this on an android phone or tablet as a central device and it is very helpful to evaluate your peripheral device.

So, for example, when I run your peripheral code, I can see the advertisement for "RussButtonLED" in the NrF master panel and I can see the advertised service UUID "70083900-6225-4765-a4be-d0f793025c8b", and  I can connect to it and see the characteristics and write to the characteristics (if allowed) and verify that the peripheral is doing what it is supposed to be doing.

Now look at your central code (which I did not run).

Note BLE.scanForUuid("19B10010-E8F2-537E-4F6C-D104768A1214"); which is not what the peripheral is advertising.

Also note if (peripheral.localName() != "ButtonLED")  well it is not going to get that name since you have named it RussButtonLED in the peripheral and that is what it advertising.

Then there are the UUID for characteristics that your central is trying to find but will not because the peripheral is not assigning those UUIDs to the characteristics.

If you use something like nRF Master Control panel, it can be very helpful when you are sorting things out.

Hope this helps.

PS:
Please read this thread concerning case sensitivity of UUIDs https://forum.arduino.cc/index.php?topic=634580.0. I believe this has been fixed if you have the latest available version - see the thread for details and where to download if it is before an update that will be pushed through the Arduino IDE.


russell_roberts

ok I take your points I now have a working example

I have a central code file and a peripheral code file.

Apart from the errors stated by DrGee.

When I use the library function BLEUnsignedLongCharacteristic
my experience is when I use this on the peripheral device
I can ready & write to the characteristic using int  for example 1233456
\
But when I access the characteristic on the Central device I access it through the library function

BLECharacteristic and then I need to convert the byte array of the buffer into an int

I did this using an ArrayToInteger union.
I don't really understand this union but copied it from examples and adjusted seemed to do the job

so

Code: [Select]

// create the Characteristic
BLEUnsignedLongCharacteristic intyCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite );

// read the current value of the characteristic on the peripheral
intyCharacteristic.value()

//write to the characteristic to the peripheral
// intyCharacteristic.writeValue(12345);




On the Central device

Code: [Select]

// define the characteristic
BLECharacteristic intyCharacteristic = peripheral.characteristic("19B10014-E8F2-537E-4F6C-D104768A1214");

// get the value from the peripheral
intyCharacteristic.read();
// this arrives in a buffer of bytes which need converting into the integer value
byteArrayToInt(intyCharacteristic.value()

// I created this union to do that

union ArrayToInteger {
  byte array[4];
  uint32_t integer;
};
int byteArrayToInt(const byte data[], int length) {
  byte dataW[length];
  for (int i = 0; i < length; i++) {
       byte b = data[i];
        dataW[i] = data[i];   
  }
  ArrayToInteger converter; //Create a converter
  converter.array[0] = dataW[0];
  converter.array[1] = dataW[1];
  converter.array[2] = dataW[2];
  converter.array[3] = dataW[3];
 
 
   return converter.integer ;
//  Serial.println(dataW[1],HEX);
 // Serial.println(dataW[2],HEX);
  //Serial.println(dataW[3],HEX);
}



 

So the full code of the central

Code: [Select]

/*
  LED Control

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button with pull-up resistor connected to pin 2.

  You can use it with another board that is compatible with this library and the
  Peripherals -> LED example.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForName("RussArduino");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "RussArduino") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);
Serial.println("do we get here?");
    // peripheral disconnected, start scanning again
    BLE.scanForName("RussArduino");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  BLECharacteristic intyCharacteristic = peripheral.characteristic("19B10014-E8F2-537E-4F6C-D104768A1214");

  if (!intyCharacteristic) {
    Serial.println("Peripheral does not have inty characteristic!");
    peripheral.disconnect();
    return;
  } else if (!intyCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable inty characteristic!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
 

  while (peripheral.connected()) {
    // while the peripheral is connected
intyCharacteristic.read();
 
Serial.print("Value ");
Serial.println(byteArrayToInt(intyCharacteristic.value(), intyCharacteristic.valueLength()));
Serial.print("rssi ");
Serial.println (peripheral.rssi());
delay(4000);
    // read the button pin
 
  }

  Serial.println("Peripheral disconnected");
}


union ArrayToInteger {
  byte array[4];
  uint32_t integer;
};
int byteArrayToInt(const byte data[], int length) {
  byte dataW[length];
  for (int i = 0; i < length; i++) {
       byte b = data[i];
        dataW[i] = data[i];   
  }
  ArrayToInteger converter; //Create a converter
  converter.array[0] = dataW[0];
  converter.array[1] = dataW[1];
  converter.array[2] = dataW[2];
  converter.array[3] = dataW[3];
 
 
   return converter.integer ;
//  Serial.println(dataW[1],HEX);
 // Serial.println(dataW[2],HEX);
  //Serial.println(dataW[3],HEX);
}



the full code for the peripheral

Code: [Select]


/*
  Button LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED and another characteristic that
  represents the state of the button.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button connected to pin 4

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

 int inty =1000;

BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service

BLEUnsignedLongCharacteristic intyCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite );
void setup() {
 
int time_now = millis();
  Serial.begin(115200);
  while (!Serial && (millis() < (time_now + 3000) ) ) {
    // wait for serial port to connect. Needed for native USB port only
  }

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("RussArduino");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(ledService);

  // add the characteristics to the service
  ledService.addCharacteristic(intyCharacteristic);
 
  // add the service
  BLE.addService(ledService);

  intyCharacteristic.writeValue(0);
  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // poll for BLE events
  BLE.poll();

  // read the current button pin state
  inty +=1000;

intyCharacteristic.writeValue(inty);

Serial.print("intyCharacteristic value  ");
Serial.println(intyCharacteristic.value());
  delay(1000);

}


DrGee

In your peripheral code, you define the characteristic as an unsigned long which occupies 4 bytes.

Code: [Select]
BLEUnsignedLongCharacteristic intyCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite );

In your peripheral code, you write the value of the characteristic with a signed int, which occupies 2 bytes.

Code: [Select]
int inty =1000;
intyCharacteristic.writeValue(inty);


In your central code, you read the value into an array and then pack it back into a variable.
Code: [Select]
Serial.println(byteArrayToInt(intyCharacteristic.value(), intyCharacteristic.valueLength()));

What happens if you try this:

In your peripheral code...
Code: [Select]
unsigned int inty =1000;
intyCharacteristic.writeValue(inty);


In your central code...
Code: [Select]

  while (peripheral.connected()) {
    // while the peripheral is connected
              
 unsigned int Cval=intyCharacteristic.read();
 
 Serial.print("Value ");
 Serial.println(Cval);
 Serial.print("rssi ");
 Serial.println (peripheral.rssi());
 delay(4000);
    // read the button pin
 
  }


...and get rid of this
Code: [Select]
union ArrayToInteger {
  byte array[4];
  uint32_t integer;
};
int byteArrayToInt(const byte data[], int length) {
  byte dataW[length];
  for (int i = 0; i < length; i++) {
       byte b = data[i];
        dataW[i] = data[i];  
  }
  ArrayToInteger converter; //Create a converter
  converter.array[0] = dataW[0];
  converter.array[1] = dataW[1];
  converter.array[2] = dataW[2];
  converter.array[3] = dataW[3];
 
 
   return converter.integer ;
//  Serial.println(dataW[1],HEX);
 // Serial.println(dataW[2],HEX);
  //Serial.println(dataW[3],HEX);
}




What kind of result does that give you? Note that I have not tested this and it may not preserve the "endianness" but it is worth a try.

edited to add: unsigned int Cval=intyCharacteristic.read(); should have been uint32_t Cval; intyCharacteristic.readValue(Cval);

russell_roberts

How the BLe library defines its functions

https://www.arduino.cc/en/Reference/ArduinoBLEBLECharacteristicread

.read() attempts to read the peripheral characteristic returning true or false depending on success or otherwise

https://www.arduino.cc/en/Reference/ArduinoBLEBLECharacteristicreadValue

.readValue returns number of bytes read but you can also get the bytes as an array hence the joining of the bytes

DrGee

Let me try it this way... (and I edited my last post to correct it)

Your posted question is this:

"I did this using an ArrayToInteger union.
I don't really understand this union but copied it from examples and adjusted seemed to do the job"


The quick answer is that you will read 4 bytes that make up an unsigned long since the characteristic value is an unsigned long (that is how you defined it in the peripheral).

In Arduino, an unsigned long is 4 bytes, little endian, meaning the LSB first (byte 0) and MSB last (byte 3). When the central device reads the characteristic as 4 bytes, it has to pack the 4 bytes into an unsigned long variable and it has to do it in the correct order. The peripheral declared that the characteristic value is an unsigned long and the central has to treat it that way in order to read it correctly. That is the simple answer to your question.

Here is a WORKING example of a code fragment that I use with a SensorTag to read the humidity sensor that might help.

Code: [Select]
void read_HUM(BLEDevice peripheral) {
  uint8_t holdvalues[4]; // hold the characteristic's bytes

  if (peripheral.connected()) {
    // wake up sensor
    HUMConCharacteristic.writeValue(sensorOn);
    delay(1200); // wait for the sensor to do a read
    HUMValCharacteristic.readValue(holdvalues, 4);
    HUMConCharacteristic.writeValue(sensorOff); // sleep sensor
    unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256);
    unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256);
    // calculate final temperature and relative humidity values
    float temp = (rawtem / 65536.0) * 165.0 - 40.0;
    temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
    float hum = ((double)rawhum / 65536.0) * 100.0;
    // save into the structure
    SensorData.tem = temp;
    SensorData.hum = hum;
  }
  else {
    Serial.println(" *not connected* ");
  }
}


In this case, the peripheral (the SensorTag) is going to send the MKR1010 as a central device, 4 bytes. But they are NOT an unsigned long. They are actually temperature values in two bytes and humidity values in the other two bytes.

Since I know (from SensorTag documentation) that I will be getting 4 bytes, I read those values into a byte array - HUMValCharacteristic.readValue(holdvalues, 4);

I could treat those 4 values as an unsigned long, literally packing them into an unsigned long variable (that is what you do in your case), but that would make no sense in this case. Instead, I process them as two variables first:

Code: [Select]
unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256);
    unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256);


and because of the SensorTag documentation I know which bytes are sent first (LSB/MSB wise) so I know how to get the correct value into the variable.

Then I process them further to get the final temperature and humidity values (again,from the SensorTag and the sensor's documentation).

So that is how I would answer your question.

____________

ArduinoBLE is relatively new and I am also learning to use it. What I was trying to get at in my first attempt at answering your question is about using Characteristic.readValue(Val), where Val is a type that matches the characteristic value. As long as the endianess has been preserved then it is the convenient way to get the characteristic value in contrast to reading into a byte array and assembling the variable "by hand" so to speak.

So, if it does, then in your case, defining Val as an unsigned long would mean that .readValue(Val) would get Val all set up with none of the processing that you used from the example.

Here are tested working code fragment examples of what I mean using an unsigned int (which is 2 bytes) characteristic. Both of the code fragments below give the same final value for lux (from a light sensor).

The first code fragment reads the characteristic's value into an array (OPTValCharacteristic.readValue(holdvalues, 2) ); and then sticks the two bytes into a variable and then processes that variable.

The second code fragment reads the characteristic's value directly into a variable (OPTValCharacteristic.readValue(Val) ); that has been declared as an unsigned int (matching the peripheral's declaration), and then processes the variable in the same way as the first code fragment.

Code: [Select]
void read_OPT(BLEDevice peripheral) {
  uint8_t holdvalues[2]; // hold the characteristic's bytes

  if (peripheral.connected()) {
    // wake up the sensor
    OPTConCharacteristic.writeValue(sensorOn);
    delay(1200); // wait for the sensor to do a read
    OPTValCharacteristic.readValue(holdvalues, 2);
    unsigned int rawlux = (holdvalues[0]) + (holdvalues[1] * 256);
    OPTConCharacteristic.writeValue(sensorOff); // sleep sensor
    // calculate lux final value
    unsigned int m = rawlux & 0x0FFF;
    unsigned int e = (rawlux & 0xF000) >> 12;
    float lux = (m * (0.01 * pow(2.0, e)));
    // save into the structure
    SensorData.li = lux;
  }
  else {
    Serial.println(" *not connected* ");
  }
}



Code: [Select]
void read_OPT2(BLEDevice peripheral) {
  //uint8_t holdvalues[2]; // hold the characteristic's bytes
  uint16_t Val; // read the characteristic's bytes into the variable

  if (peripheral.connected()) {
    // wake up the sensor
    OPTConCharacteristic.writeValue(sensorOn);
    delay(1200); // wait for the sensor to do a read
    //OPTValCharacteristic.readValue(holdvalues, 2);
    //unsigned int rawlux = (holdvalues[0]) + (holdvalues[1] * 256);
    OPTValCharacteristic.readValue(Val);
    unsigned int rawlux =Val;
    OPTConCharacteristic.writeValue(sensorOff); // sleep sensor
    // calculate lux final value
    unsigned int m = rawlux & 0x0FFF;
    unsigned int e = (rawlux & 0xF000) >> 12;
    float lux = (m * (0.01 * pow(2.0, e)));
    // save into the structure
    SensorData.li = lux;
  }
  else {
    Serial.println(" *not connected* ");
  }
}


Hope this helps.

russell_roberts

so with your code examples
were you running one bit on the peripheral and another on the central device?

DrGee

so with your code examples
were you running one bit on the peripheral and another on the central device?
No, you are not understanding. The peripheral is the TI SensorTag (http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User%27s_Guide#Gatt_Server) which has been around for a while and runs its own code. There is even an example in the ArduinoBLE library to connect to the SensorTag and read a switch.

ALL of the code fragments in my previous post was for the MKR1010 in the central role.

russell_roberts

so to experience what I am doing is to update a characteristic on the peripheral then once this is done the central requests it thus there is communication over blue tooth this is when I believe I need the buffer & conversion from bytes to a value. Please try setting a value on the peripheral and reading it on the central
 

DrGee

Please try setting a value on the peripheral and reading it on the central
While I have done that in the past with the old Arduino 101 and a few others, I am going to say, "No thanks". I don't have the problem so I don't feel like I should write more code on top of the code and the lengthy posts I have already made trying to help you. Moreover, I don't get a sense that you are understanding what I have been saying. Maybe someone else can come around and do what you want them to do.

I am not sure, but I get the feeling that you may need to do some more background work and especially going through the ArduinoBLE .h and .cpp files as well as some background reading on BLE in general and also data type sizes on C/C++ (e.g., https://learn.sparkfun.com/tutorials/data-types-in-arduino/all). Then, hopefully, these issues will become clearer.

Sorry that I could not be of help more and good luck with your project and education!

russell_roberts

Hi DrGee

Thanks for your sharing. I appreciate you trying to help but I have a working solution and I have found from experience that when sending data between a peripheral device & a central device it does appear on a buffer in a series of bytes. (as per the library).

This solution is posted here as a working example using a "Union" for the benefit of other people who experience similar issues to what I had. They also have the benefit of your suggestions to explore

Personally every thing else I have tried including your suggestions failed, the only thing that has worked when communicating device to device was my solution.

I was not suggesting you did further coding for my benefit but for you to explore your solutions don't work when communicating device to device using the ARDUINO LIBRARY

Thanks once again for your input

russell_roberts

For the benefit of anyone reading this post  DrGee made some good points having spent the last few days exploring BLE types of communication between 2 Arduino's using the ArduinoBLE library

I have come to understand what DrGee was trying to say in relation to Characteristics.

What has worked for me is if I define a BLEUnsignedLongCharacteristic on the peripheral as part of a service when sending data from the peripheral to the client I need to be careful how to define the receiving variable in this case long.

So my final code that works

for the central

Code: [Select]


/*
  LED Control run on Mkr 1010

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button with pull-up resistor connected to pin 2.

  You can use it with another board that is compatible with this library and the
  Peripherals -> LED example.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;
long   value;
void setup() {
  Serial.begin(115200);
  while (!Serial);

  // configure the button pin as input
  pinMode(buttonPin, INPUT_PULLUP);

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - LED control");

  // start scanning for peripherals
  BLE.scanForName("RussArduino");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "RussArduino") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);
    Serial.println("do we get here?");
    // peripheral disconnected, start scanning again
    BLE.scanForName("RussArduino");
  }
}

void controlLed(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }
  
  BLECharacteristic intyCharacteristic = peripheral.characteristic("19B10014-E8F2-537E-4F6C-D104768A1214");
  
  if (!intyCharacteristic) {
    Serial.println("Peripheral does not have inty characteristic!");
    peripheral.disconnect();
    return;
  } else if (!intyCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable inty characteristic!");
    peripheral.disconnect();
    return;
  }

  // retrieve the LED characteristic
 

  while (peripheral.connected()) {
    // while the peripheral is connected
    // intyCharacteristic.read();
    intyCharacteristic.readValue(value);
     Serial.print("Value ");
     Serial.println(value);
     Serial.print("rssi ");
     Serial.println (peripheral.rssi());
     //delay(4000);
    // read the button pin
  
  }

  Serial.println("Peripheral disconnected");
}


union ArrayToInteger {
  byte array[4];
  uint32_t integer;
};
int byteArrayToInt(const byte data[], int length) {
  byte dataW[length];
  for (int i = 0; i < length; i++) {
       byte b = data[i];
        dataW[i] = data[i];    
  }
  ArrayToInteger converter; //Create a converter
  converter.array[0] = dataW[0];
  converter.array[1] = dataW[1];
  converter.array[2] = dataW[2];
  converter.array[3] = dataW[3];
  
  
   return converter.integer ;
//  Serial.println(dataW[1],HEX);
 // Serial.println(dataW[2],HEX);
  //Serial.println(dataW[3],HEX);
}



for the peripheral

Code: [Select]




/*
  Button LED run on nano iot 33

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED and another characteristic that
  represents the state of the button.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button connected to pin 4

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

 int inty =1000;

BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service

BLEUnsignedLongCharacteristic intyCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite );
void setup() {
 
  int time_now = millis();
  Serial.begin(115200);
  while (!Serial && (millis() < (time_now + 3000) ) ) {
    // wait for serial port to connect. Needed for native USB port only
  }

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("RussArduino");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(ledService);

  // add the characteristics to the service
  ledService.addCharacteristic(intyCharacteristic);
 
  // add the service
  BLE.addService(ledService);

  intyCharacteristic.writeValue(0);
  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // poll for BLE events
  BLE.poll();

  // read the current button pin state
  inty +=1000;

  intyCharacteristic.writeValue(inty);
 
  Serial.print("intyCharacteristic value  ");
    Serial.println(intyCharacteristic.value());
  delay(1000);

}



Thanks for your assistance sorry for any misunderstanding. I am sure in time we will both get better at communication. And not only with arduinos

Go Up