My code is meant to connect to a bluetooth die and read what it has rolled. I originally was using an Arduino Uno Wifi Rev2 and it works perfectly. However, I would like to swap which microcontroller I am using for this project. This is where things go wrong.
The same problem occurs for all of my other three Arduinos:
Arduino Uno R4 Wifi
Arduino Nano 33 BLE Rev2
Arduino Nano 33 BLE Sense Rev2
The code uploads fine to the boards, and they manage to connect to the peripheral, but when they go to discover attributes, they fail and get stuck in "Attribute discovery failed! Trying again...". This does not happen with my Arduino Uno Wifi Rev2.
What's going on?
#include <ArduinoBLE.h>
void setup() {
Serial.begin(9600);
while (!Serial);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy module failed!");
while (1);
}
Serial.println("Bluetooth® Low Energy Central - MRGD Die");
// start scanning for peripherals
BLE.scanForName("MRGD");
}
void loop() {
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();
if (peripheral) {
if (peripheral.localName() == "MRGD") {
// stop scanning
BLE.stopScan();
connectToPeripheral(peripheral);
}
}
}
void connectToPeripheral(BLEDevice peripheral) {
// connect to the peripheral
Serial.println("Connecting ...");
if (peripheral.connect()) {
Serial.println("Connected");
discoverAttributes(peripheral);
} else {
Serial.println("Failed to connect! Trying again...");
connectToPeripheral(peripheral);
return;
}
}
void discoverAttributes(BLEDevice peripheral) {
Serial.println("Discovering attributes ...");
if (peripheral.discoverAttributes()) {
Serial.println("Attributes discovered");
discoverService(peripheral);
} else {
Serial.println("Attribute discovery failed! Trying again...");
discoverAttributes(peripheral);
return;
}
}
void discoverService(BLEDevice peripheral) {
BLEService rollStateService = peripheral.service(2);
if(rollStateService) {
Serial.println("Service discovered");
discoverCharacteristic(peripheral, rollStateService);
} else {
Serial.println("Failed to find Service!");
discoverService(peripheral);
return;
}
}
void discoverCharacteristic(BLEDevice peripheral, BLEService rollStateService) {
BLECharacteristic rollStateCharacteristic = rollStateService.characteristic(1);
if(rollStateCharacteristic) {
Serial.println("Characteristic discovered");
rollStateCharacteristic.subscribe();
while (peripheral.connected()) {
if (rollStateCharacteristic.valueUpdated()) {
byte value[] = {0, 0, 0};
rollStateCharacteristic.readValue(value, 3);
if(value[0] == 3 && value[1] == 1) {
Serial.println(value[2] + 1);
}
}
}
} else {
Serial.println("Failed to find Characteristic!");
discoverCharacteristic(peripheral, rollStateService);
return;
}
}
Enables Bluetooth® Low Energy connectivity on the Arduino MKR WiFi 1010, Arduino UNO WiFi Rev2, Arduino Nano 33 IoT, Arduino Nano 33 BLE, Arduino Portenta H7, Arduino Giga R1 and Arduino UNO R4 WiFi.
Are you saying that because my Arduino Nano 33 BLE Rev 2 and Arduino Nano 33 BLE Sense Rev 2 are Rev 2's that the library doesn't work for them? What would I use instead?
It also doesn't explain why it wouldn't work on my Arduino UNO R4 WiFi.
I don't understand the issues with the attribute discovery and the different platforms.
However, per the communication protocol the information you need to read from the die is in the ManufacturerData field of the advertisement. You should be able to read that without the attributes discovery.
I don't know if you need to read and write to the characteristic, and if so, I don't know how to do that without the attribute discovery.
See what you can find what you need with this.
#include <ArduinoBLE.h>
uint8_t dieManufacturerData[24] = {};
void setup() {
delay(2500);
Serial.begin(9600);
Serial.println("Serial Enabled");
if (!BLE.begin()) {
Serial.println("starting BLE module failed!");
while (1);
}
Serial.println("BLE Central for PixelDie");
BLE.scanForName("MRGD");
}
void loop() {
BLEDevice peripheral = BLE.available();
if (peripheral) {
BLE.stopScan();
Serial.print("MRGD Found @ ");
Serial.print(peripheral.address());
Serial.println();
if (peripheral.hasManufacturerData()) {
peripheral.manufacturerData(dieManufacturerData, 24); //probeManufacturerData is the 24 byte data array the data will get copied into by the function.
Serial.println("Die Data Found");
printData(dieManufacturerData, 24);
Serial.println();
}
BLE.scanForName("MRGD");
}
delay(1000);
}
void printData(uint8_t data[], int length) {
for (int i = 0; i < length; i++) {
uint8_t b = data[i];
if (b < 16) {
Serial.print("0");
}
Serial.print(b, HEX);
Serial.print(' ');
}
Serial.println();
}
Interesting! I can use the manufacturer data to access the current face and roll state from the advertisement rather than having to connect. In a lot of ways this might be better than permanently connecting to the die, although it does mean I can't write to the LEDs.
I never would have thought of that possibility, thanks!