I am trying to make the Pulse Oximeter Service work and I ended up on a problem.
I get my information from here:
https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.pulse_oximeter.xml
https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.plx_spot_check_measurement.xml
And my code looks something like this :
//libraries for SERIAL, MAX30105 and SP02 algorithm
#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"
//init for SP02 algorithm
#define MAX_BRIGHTNESS 255
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100]; //red LED sensor data
int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid
//The default address of the device is 0x57
MAX30105 particleSensor; //Initialize sensor for HR and SP02
//----------------------------------------------------------------------------------------------------------------------
// BLE Sp02 Measurment from MAX30101
//----------------------------------------------------------------------------------------------------------------------
// Constants for flags (8bit) in Spot-Check Sp02 Measurement (last 3 bits reserved)(see XML link) MyFlag=ob11100010
#define PLX_TIMESTAMP_FIELD_NOT_PRESENT 0
#define PLX_TIMESTAMP_FIELD_PRESENT 1
#define PLX_MEASUREMENT_FIELD_NOT_PRESENT (0 << 1)
#define PLX_MEASUREMENT_FIELD_PRESENT (1 << 1)
#define PLX_DEVICE_SENSOR_STATUS_NOT_PRESENT (0 << 2)
#define PLX_DEVICE_SENSOR_STATUS_PRESENT (1 << 2)
#define PLX_PULSE_AMPLITUDE_NOT_PRESENT (0 << 3)
#define PLX_PULSE_AMPLITUDE_PRESENT (1 << 3)
#define PLX_DEVICE_CLOCK_NOT_SET_FALSE (0 << 4)
#define PLX_DEVICE_CLOCK_NOT_SET_TRUE (1 << 4)
//Constants for flags (16bit) for Measurement Status (first 5 bits reserved) My Initial Flag ob1100000000011111
#define MEASUREMENT_STATUS_ONGOING (1 << 5)
#define MEASUREMENT_STATUS_NOT_ONGOING (0 << 5)
#define MEASUREMENT_STATUS_EARLY_ESTIMATED_DATA (1 << 6)
#define MEASUREMENT_STATUS_NOT_EARLY_ESTIMATED_DATA (0 << 6)
#define MEASUREMENT_STATUS_VALIDATED_DATA (1 << 7)
#define MEASUREMENT_STATUS_NOT_VALIDATED_DATA (0 << 7)
#define MEASUREMENT_STATUS_FULLY_QUALIFIED_DATA (1 << 8)
#define MEASUREMENT_STATUS_NOT_FULLY_QUALIFIED_DATA (0 << 8)
#define MEASUREMENT_STATUS_DATA_FROM_MEASUREMENT_STORAGE (1 << 9)
#define MEASUREMENT_STATUS_DATA_NOT_FROM_MEASUREMENT_STORAGE (0 << 9)
#define MEASUREMENT_STATUS_DATA_FOR_DEMONSTATION (1 << 10)
#define MEASUREMENT_STATUS_DATA_NOT_FOR_DEMONSTATION (0 << 10)
#define MEASUREMENT_STATUS_DATA_FOR_TESTING (1 << 11)
#define MEASUREMENT_STATUS_DATA_NOT_FOR_TESTING (0 << 11)
#define MEASUREMENT_STATUS_CALIBRATION_ONGOING (1 << 12)
#define MEASUREMENT_STATUS_CALIBRATION_NOT_ONGOING (0 << 12)
#define MEASUREMENT_STATUS_MEASUREMENT_UNAVAILABLE (1 << 13)
#define MEASUREMENT_STATUS_MEASUREMENT_AVAILABLE (0 << 13)
#define MEASUREMENT_STATUS_QUESTIONABLE_MEASUREMENT_DETECTED (1 << 14)
#define MEASUREMENT_STATUS_NOT_QUESTIONABLE_MEASUREMENT_DETECTED (0 << 14)
#define MEASUREMENT_STATUS_INVALID_MEASUREMENT_DETECTED (1 << 15)
#define MEASUREMENT_STATUS_VALID_MEASUREMENT_DETECTED (0 << 15)
//Constants for flags (24bit) for Measurement Status (last 8 bits reserved)
#define DEVICE_SENSOR_EXT_DISPLAY_UPDATE_ONGOING 1
#define DEVICE_SENSOR_EXT_DISPLAY_UPDATE_NOT_ONGOING 0
#define DEVICE_SENSOR_EQUIPMENT_MALFUNCTION_DETECTED (1 << 1)
#define DEVICE_SENSOR_EQUIPMENT_MALFUNCTION_NOT_DETECTED (0 << 1)
#define DEVICE_SENSOR_SIGNAL_PROCESS_IRREGULARITY_DETECTED (1 << 2)
#define DEVICE_SENSOR_SIGNAL_PROCESS_IRREGULARITY_NOT_DETECTED (0 << 2)
#define DEVICE_SENSOR_INADEQUITE_SIGNAL_DETECTED (1 << 3)
#define DEVICE_SENSOR_INADEQUITE_SIGNAL_NOT_DETECTED (0 << 3)
#define DEVICE_SENSOR_POOR_SIGNAL_DETECTED (1 << 4)
#define DEVICE_SENSOR_NOT_POOR_SIGNAL_DETECTED (0 << 4)
#define DEVICE_SENSOR_LOW_PERFUSION_DETECTED (1 << 5)
#define DEVICE_SENSOR_LOW_PERFUSION_NOT_DETECTED (0 << 5)
#define DEVICE_SENSOR_ERRATIC_SIGNAL_DETECTED (1 << 6)
#define DEVICE_SENSOR_ERRATIC_SIGNAL_NOT_DETECTED (0 << 6)
#define DEVICE_SENSOR_NONPULSATILE_SIGNAL_DETECTED (1 << 7)
#define DEVICE_SENSOR_NONPULSATILE_SIGNAL_NOT_DETECTED (0 << 7)
#define DEVICE_SENSOR_QUESTIONABLE_PULSE_DETECTED (1 << 8)
#define DEVICE_SENSOR_NOT_QUESTIONABLE_PULSE_DETECTED (0 << 8)
#define DEVICE_SENSOR_SIGNAL_ANALYSIS_ONGOING (1 << 9)
#define DEVICE_SENSOR_SIGNAL_ANALYSIS_NOT_ONGOING (0 << 9)
#define DEVICE_SENSOR_INTERFACE_DETECTED (1 << 10)
#define DEVICE_SENSOR_INTERFACE_NOT_DETECTED (0 << 10)
#define DEVICE_SENSOR_UNCONNECTED_TO_USER (1 << 11)
#define DEVICE_SENSOR_CONNECTED_TO_USER (0 << 11)
#define DEVICE_SENSOR_SENSOR_CONNECTED (1 << 12)
#define DEVICE_SENSOR_SENSOR_UNCONNECTED (0 << 12)
#define DEVICE_SENSOR_DISPLACED (1 << 13)
#define DEVICE_SENSOR_NOT_DISPLACED (0 << 13)
#define DEVICE_SENSOR_MALFUNCTIONING (1 << 14)
#define DEVICE_SENSOR_NOT_MALFUNCTIONING (0 << 14)
#define DEVICE_SENSOR_DISCONNECTED (1 << 15)
#define DEVICE_SENSOR_CONNECTED (0 << 15)
//for SP02
typedef struct __attribute__( ( packed ) )
{
uint8_t flags1 ;
float sp02_BLE;
float sp02_PR_BLE;
uint16_t flags_measurement ;
//cant make 24bit flag,wtf do i do _int24 flags2 ;
} sp02_measurment;
union sp02_measurment_u
{
struct __attribute__( ( packed ) )
{
sp02_measurment values;
};
uint8_t bytes1[ sizeof( sp02_measurment ) ];
} ;
union sp02_measurment_u SP02_Mes = { .values = { .flags1 = 0, .sp02_BLE = 0, .sp02_PR_BLE = 0, flags_measurement = 0 } };
float stored_final_sp02; // value that we sent through BLE
float stored_PR_sp02;
uint8_t flags1 = ob11100010;
uint16_t flags_measurement = ob0000000000011111;
void setup()
{
//MAX30101 Init for SP02 algorithm
Serial.begin(115200); // initialize serial communication at 115200 bits per second:
while (!Serial);
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println(F("MAX30105 was not found. Please check wiring/power."));
while (1);
}
///SETUP configuration vars for SP02 ///
//Default is 0x1F which gets us 6.4mA
//powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch
//powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch
//powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch
//powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch
byte ledBrightness = 60; //Options: 0=Off to 255=50mA
byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
//The longer the pulse width the longer range of detection you'll have
//At 69us and 0.4mA it's about 2 inches
//At 411us and 0.4mA it's about 6 inches
int pulseWidth = 411; //Options: 69 get us 15 bit res, 118 get us 16bit res, 215 get us 17 bit res, 411 get us 18bit res
int adcRange = 4096; //Options: 2048, 4096, 8192, 16384
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
//END_SP02//
//BLE
Serial.begin(9600); // initialize serial communication
while (!Serial);
if (!BLE.begin()) { // initialize BLE
Serial.println("starting BLE failed!");
while (1);
}
//set advertised local name and service
BLE.setDeviceName("Arduino Nano 33 BLE device");
BLE.setLocalName("Arduino Nano 33 BLE"); // Set name for connection
BLE.setAdvertisedService(spo2Service); // Advertise service
//BLE and characteristics for spo2Service
spo2Service.addCharacteristic(spo2Characteristic);
//add Services
BLE.addService(spo2Service);
// set the initial value for the SP02 characteristic
SP02_Mes.values.flags1 = flags1;
SP02_Mes.values.flags_measurement = flags_measurement;
spo2Characteristic.writeValue( SP02_Mes.bytes1, sizeof SP02_Mes.bytes1 );
BLE.advertise(); // Start advertising
Serial.print("Peripheral device MAC: ");
Serial.println(BLE.address());
Serial.println("Waiting for connections...");
}
void loop()
{
BLEDevice central = BLE.central(); //Waits for BLE Central device to connect
if (central)
{
Serial.print("Connected to central: ");
Serial.println(central.address());
while(central.connected()){
int count = 0;
int sum_sp02;
SP02_measurement();
//store sp02 in RAM
for (int i = 1; i <= 25; i++)
{
if (stored_sp02[i] > 40 && stored_sp02[i] <= 100) {
count++;
sum_sp02 = (stored_sp02[i] + sum_sp02);
stored_final_sp02 = (sum_sp02 / count); //final measurement of sp02 ,average of max 25 measurements
stored_PR_sp02 = stored_final_sp02 ;
if (i == 25) {
count = 0;
}
}
if (stored_sp02[i] == -999) {
continue;
}
}
Serial.println("Oi stored times einai: ");
Serial.println("Temp, sp02");
Serial.println(stored_temp, 4); Serial.println(stored_final_sp02);
//set the value for charasteristics
spo2Characteristic.writeValue( SP02_Mes.bytes1, sizeof SP02_Mes.bytes1 );
}
}
void SP02_measurement() {
//Sent to BLE that SP02 is ongoing
SP02.Mes.values.flags_measurement = ob0010000000111111;
spo2Characteristic.writeValue( SP02_Mes.bytes1, sizeof SP02_Mes.bytes1 );
bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps
//read the first 100 samples, and determine the signal range
for (byte i = 0 ; i < bufferLength ; i++)
{
if (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
// Serial.print(F("red="));
// Serial.print(redBuffer[i], DEC);
// Serial.print(F(", ir="));
// Serial.println(irBuffer[i], DEC);
}
//calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
//Continuously taking samples from MAX30105. Heart rate and SpO2 are calculated every 1 second
static unsigned long sp02Timer1 = 0;
static unsigned long sp02Timer2 = 0;
sp02Timer1 = millis();
sp02Timer2 = millis();
while (sp02Timer1 < sp02Timer2 + TIMER2_DURATION_MS)
{
//dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
for (byte i = 25; i < 100; i++)
{
redBuffer[i - 25] = redBuffer[i];
irBuffer[i - 25] = irBuffer[i];
}
//take 25 sets of samples before calculating the heart rate.
for (byte i = 75; i < 100; i++)
{
while (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
//PRINTS SP02 until Timer2 stops
Serial.print(F(", SPO2="));
Serial.print(spo2, DEC);
Serial.print(F(", SPO2Valid="));
Serial.println(validSPO2, DEC);
stored_sp02[i - 74] = spo2;
sp02Timer1 = millis(); // timer to exit out of sp02 measurements
}
}
if(validSPO2 == 1){
SP02_Mes.values.flags_measurement = ob0000010010011111;
if( spo2 >= 93 ){
SP02_Mes.values.flags_measurement = ob0000011010011111;
}
else if( spo2 <= 75 ){
SP02_Mes.values.flags_measurement = ob0100010010011111;
}
}else{
SP02_Mes.values.flags_measurement = ob1100000000011111;
}
Serial.println("We got Sp02 boi");
}
My problem is that the PLX service uses 3 flags, one with 8bit, one with 16bit and one with 24bit. I can not make the 24bit work.
How can I give to a variable a 24bit information?
And I keep getting errors when I try to give the 16bit flag the value that I want like this :
flag16bit = ob1010101100110011;
I am using the arduino Nano 33 BLE.