I've set up a Nano 33 IOT as a central device and I'm attempting to read the data from a Cycling speed and cadence BLE device.
The spec for the CSC Gatt service I want is: https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.cycling_speed_and_cadence.xml
And the characteristic: https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.csc_measurement.xml
I've tried a few different approaches, this one seems like it should get me the closest. I'm afraid I'm feeling around in the dark and hope someone can give me a definitive answer of how to read these values because I'm not even sure what they SHOULD look like even if I do somehow manage to read them correctly!
I initially tried using this code to read the values, which seemed to get me reasonably close, but seeing as there are different data types and I could just as easily read 32 values, I don't believe it to be correct.
uint16_t cscValues[16];
cscCharacteristic.readValue(cscValues, 16);
for(int i = 0; i < 16; i++){
Serial.print(i);
Serial.print(":");
Serial.print(cscValues[i]);
Serial.print(" ");
}
Serial.println("");
this gives the output:
//not moving:
10:50:49.401 -> 0:21249 1:0 2:11008 3:8314 4:556 5:8192 6:25637 7:0 8:0 9:0 10:704 11:8192 12:568 13:8192 14:22485 15:0
10:50:50.409 -> 0:21249 1:0 2:11008 3:8314 4:556 5:8192 6:25637 7:0 8:0 9:0 10:704 11:8192 12:568 13:8192 14:22485 15:0
//moving:
10:51:07.518 -> 0:24577 1:0 2:8448 3:8338 4:556 5:8192 6:25637 7:0 8:0 9:0 10:704 11:8192 12:568 13:8192 14:22485 15:0
10:51:08.513 -> 0:25345 1:0 2:36864 3:8342 4:556 5:8192 6:25637 7:0 8:0 9:0 10:704 11:8192 12:568 13:8192 14:22485 15:0
10:51:09.490 -> 0:26113 1:0 2:6144 3:8347 4:556 5:8192 6:25637 7:0 8:0 9:0 10:704 11:8192 12:568 13:8192 14:22485 15:0
The method I'm currently using is based off of a Arduino forum post I found: https://forum.arduino.cc/index.php?topic=711228.0
My full sketch:
#include <ArduinoBLE.h>
#define CSC_DATA_SIZE 16
typedef struct __attribute__( ( packed ) )
{
int32_t cum_wheel_rev;
int16_t last_wheel_event;
int16_t cum_cranks;
int16_t last_crank_event;
} csc_data_t;
typedef union
{
csc_data_t values;
uint8_t bytes[ CSC_DATA_SIZE ];
} csc_data_ut;
csc_data_ut cscData;
void setup() {
Serial.begin(9600);
//wait until the serial port is connected for debugging
while (!Serial);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
Serial.println("BLE Central scan");
// start scanning for peripheral
BLE.scanForUuid("1816"); // Cycle speed and cadence UUID
}
void loop() {
//Read BLE devices
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral
Serial.println("Discovered a peripheral");
Serial.println("-----------------------");
// print address
Serial.print("Address: ");
Serial.println(peripheral.address());
// print the local name, if present
if (peripheral.hasLocalName()) {
Serial.print("Local Name: ");
Serial.println(peripheral.localName());
}
// print the advertised service UUIDs, if present
if (peripheral.hasAdvertisedServiceUuid()) {
Serial.print("Service UUIDs: ");
for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {
Serial.print(peripheral.advertisedServiceUuid(i));
Serial.print(" ");
}
Serial.println();
}
// print the RSSI
Serial.print("RSSI: ");
Serial.println(peripheral.rssi());
Serial.println();
// stop scanning
BLE.stopScan();
getSpeed(peripheral);
// peripheral disconnected, start scanning again
BLE.scanForUuid("1816"); // Cycle speed and cadence UUID
}
}
void getSpeed(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 cscCharacteristic = peripheral.characteristic("2A5B");
if (!cscCharacteristic) {
Serial.println("Peripheral does not have CSC characteristic!");
peripheral.disconnect();
return;
}
if (!cscCharacteristic.canSubscribe()) {
Serial.println("canSubscribe False");
} else {
if(!cscCharacteristic.subscribe()) {
Serial.println("subscription Failed");
}else {
Serial.println("subscribed!");
}
}
int totalWheelRevolutions = 0;
int wheelDiameter = 750; // in mm
while (peripheral.connected()) {
//happens every second.
if (cscCharacteristic.valueUpdated()) {
if (cscCharacteristic.valueLength() > 0) {
cscCharacteristic.readValue(m5600Data.bytes, M5600_DATA_SIZE);
Serial.print(" cum_wheel_rev: ");
Serial.print(cscData.values.cum_wheel_rev);
Serial.print(" last_wheel_event: ");
Serial.print(cscData.values.last_wheel_event);
Serial.print(" cum_cranks: ");
Serial.print(cscData.values.cum_cranks);
Serial.print(" last_crank_event: ");
Serial.print(cscData.values.last_crank_event);
Serial.println("");
}
}
}
Serial.println("Peripheral disconnected");
}
The output is:
10:42:15.427 -> BLE Central scan
10:42:16.193 -> Discovered a peripheral
10:42:16.193 -> -----------------------
10:42:16.193 -> Address: df:f4:55:1e:16:27
10:42:16.193 -> Local Name: XOSS S-021477
10:42:16.193 -> Service UUIDs: 1816
10:42:16.193 -> RSSI: -72
10:42:16.193 ->
10:42:16.193 -> Connecting ...
10:42:16.703 -> Connected
10:42:16.703 -> Discovering attributes ...
10:42:17.473 -> Attributes discovered
10:42:17.508 -> subscribed!
//moving:
10:42:18.524 -> cum_wheel_rev: 11009 last_wheel_event: -32256 cum_cranks: 251 last_crank_event: 0
10:42:19.529 -> cum_wheel_rev: 11265 last_wheel_event: -19968 cum_cranks: 7 last_crank_event: 0
10:42:20.511 -> cum_wheel_rev: 11777 last_wheel_event: -10752 cum_cranks: 21 last_crank_event: 0
10:42:21.520 -> cum_wheel_rev: 12033 last_wheel_event: -512 cum_cranks: 26 last_crank_event: 0
10:42:22.636 -> cum_wheel_rev: 12545 last_wheel_event: -6912 cum_cranks: 31 last_crank_event: 0
10:42:23.764 -> cum_wheel_rev: 13057 last_wheel_event: 4608 cum_cranks: 37 last_crank_event: 0
10:42:24.747 -> cum_wheel_rev: 13313 last_wheel_event: -25600 cum_cranks: 39 last_crank_event: 0
10:42:25.615 -> cum_wheel_rev: 13825 last_wheel_event: 2816 cum_cranks: 44 last_crank_event: 0
10:42:26.631 -> cum_wheel_rev: 14337 last_wheel_event: -11264 cum_cranks: 48 last_crank_event: 0
10:42:27.610 -> cum_wheel_rev: 14849 last_wheel_event: -17664 cum_cranks: 53 last_crank_event: 0
10:42:28.635 -> cum_wheel_rev: 15361 last_wheel_event: -12288 cum_cranks: 57 last_crank_event: 0
10:42:29.616 -> cum_wheel_rev: 15873 last_wheel_event: -18432 cum_cranks: 61 last_crank_event: 0
10:42:30.642 -> cum_wheel_rev: 16385 last_wheel_event: -29696 cum_cranks: 65 last_crank_event: 0
10:42:31.619 -> cum_wheel_rev: 16641 last_wheel_event: -21248 cum_cranks: 67 last_crank_event: 0
10:42:32.612 -> cum_wheel_rev: 16897 last_wheel_event: 23040 cum_cranks: 70 last_crank_event: 0
10:42:33.642 -> cum_wheel_rev: 17665 last_wheel_event: -7168 cum_cranks: 77 last_crank_event: 0
10:42:34.619 -> cum_wheel_rev: 18177 last_wheel_event: 18944 cum_cranks: 81 last_crank_event: 0
10:42:35.637 -> cum_wheel_rev: 18945 last_wheel_event: 11264 cum_cranks: 86 last_crank_event: 0
10:42:36.622 -> cum_wheel_rev: 19457 last_wheel_event: -29440 cum_cranks: 89 last_crank_event: 0
10:42:37.616 -> cum_wheel_rev: 19969 last_wheel_event: -5888 cum_cranks: 92 last_crank_event: 0
//not moving:
10:42:38.623 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:39.608 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:40.624 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:41.640 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:42.620 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:43.642 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:44.622 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
10:42:45.638 -> cum_wheel_rev: 20481 last_wheel_event: 20224 cum_cranks: 96 last_crank_event: 0
I'm well versed in programming, but new to Arduino. Any help would be extremely valuable!
Thank you!