Open JavierAder opened 1 week ago
Internally, I2C .h wraps Wire, since it is the only available I2C API provided by the Core.
I don't see any issues in c/p directly to the sensor class omitting the lib itself and extra code it introduces for sketch use-cases. No need to set up Wire, writers and readers are already implemented, big-endian / little-endian code as well. Don't forget the (c) info, obviously.
Hello. Let's see if I understood your approach:
I don't think Wire is used anywhere else.
not using the Oxullo library directly, but a modified version of it (I suppose it would have to be put under code/espurna/libs)
see lib_deps = ...
in platformio .ini. so far I have not implemented any clever code / lib / dep detection, so once added any code can magically use this lib headers
the modified version that does not use Wire, instead using I2C.h
removing begin() and setClock() might be enough, unless you also declare i2c .h funcs manually (since include paths from lib to project is ok, project to lib is not) edit: ...since either way, everything goes through Wire. Lib just loses our abstraction on top of it, everything still should work just fine when reading / writing.
I would still suggest to take a look at a possibility of extracting some code into a single sensor class file, removing the lib dependency. Might be easier to debug in the future.
I would still suggest to take a look at a possibility of extracting some code into a single sensor class file, removing the lib dependency. Might be easier to debug in the future.
Yes, it is probably better; by the way, it seems that the algorithms to calculate sp02 are not so trivial and there are variants (for example, this one seems to be quite a bit more complex than Oxullo's https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/tree/master/src ); a perzonalizaded version should be easier to maintain. As soon as I have a bit more time I'll try something like this.
https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/72d5308df500ae1a64cc9d63e950c68c96dc78d5/examples/Example8_SPO2/Example8_SPO2.ino#L86 also mentions that it takes some time to gather all of the results provide a meaningful output Another question, how do sensor filters fit here since we (sort-of) expect to aggregate them at an upper level to median / average / etc. them. Unless sp02 calc becomes a filter here, shared between these two magnitude readers
https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/72d5308df500ae1a64cc9d63e950c68c96dc78d5/examples/Example8_SPO2/Example8_SPO2.ino#L86 also mentions that it takes some time to gather all of the results provide a meaningful output
The first 100 samples are for the algorithm to work properly (it needs to remove the DC component from the signal among other things); then it recalculates the Spo2 every 25 samples. The Sparkfun example is blocking
while (particleSensor.available() == false)
although I don't see it necessary to do it this way; you should simply update the data buffer progressively and only recalculate the Spo2 every certain amount of new samples. Oxullo does it differently; every time the sensor is accessed, all the samples that it has stored in its internal buffer are read (this is not blocking) and it always recalculates Spo2.
https://github.com/oxullo/Arduino-MAX30100/blob/5754dfe2cfd882b91d5db748d78c4a6ad4cab0d1/src/MAX30100.cpp#L134
Another question, how do sensor filters fit here since we (sort-of) expect to aggregate them at an upper level to median / average / etc. them. Unless sp02 calc becomes a filter here, shared between these two magnitude readers
I don't see the problem with calculating the average, median, etc., in a standard way.
Well, for the moment, I made the sensor code directly using the Sparkfun library, I included it in sensor.cpp and the build at least worked (I don't know if it is using a lot of memory; platformIO showed me
Checking size .pio\build\nodemcu-lolin\firmware.elf Advanced Memory Usage is available via "PlatformIO Home > Project Inspect" RAM: [===== ] 46.7% (used 38248 bytes from 81920 bytes) Flash: [====== ] 58.9% (used 615093 bytes from 1044464 bytes)
I guess the next step should be to migrate the Sparkfun library code into MAX30100Sensor.h MAX30100Sensor.h
#include <Wire.h>
#include "BaseSensor.h"
#include "SparkFun_MAX3010x/MAX30105.h"
#include "SparkFun_MAX3010x/spo2_algorithm.h"
class MAX30100Sensor : public BaseSensor
{
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
unsigned char id() const override
{
return SENSOR_MAX30100_ID;
}
unsigned char count() const override
{
return 2;
}
// Type for slot # index
unsigned char type(unsigned char index) const override
{
if (index == 0)
return MAGNITUDE_HEART_RATE;
if (index == 1)
return MAGNITUDE_SPO2;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) override
{
if (index == 0)
return _rate;
if (index == 1)
return _spO2;
return 0;
}
// Initialization method, must be idempotent
void begin() override
{
// TODO: here?
// Based Sparkfun SPO2 example (setup())
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) // Use default I2C port, 400kHz speed
{
_error = SENSOR_ERROR_I2C;
return;
}
//TODO: get that data from runtime config
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
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
}
//TODO: pre or tick?
// Pre-read hook (usually to populate registers with up-to-date data)
void pre() override {
uint8_t samples = particleSensor.available();
if (samples == false)
{
particleSensor.check(); //Check the sensor for new data
return;
}
//TODO if (samples <25 ) return?
if (samples > bufferLength)
samples = bufferLength;
//Make room in the end of buffers
uint8_t samplesToMove = bufferLength - samples;
for (byte i = 0; i<samplesToMove; i++)
{
redBuffer[i] = redBuffer[i+samples];
irBuffer[i] = irBuffer[i+samples];
}
//update buffers with samples
for (byte i = bufferLength-samples; i<bufferLength;i++)
{
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
}
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
//
//calculate spo2 and heart rate
maxim_heart_rate_and_oxygen_saturation(this->irBuffer, bufferLength, this->redBuffer, &spo2,
&validSPO2, &heartRate, &validHeartRate);
if (validSPO2)
_spO2 = spo2;
if (validHeartRate)
_rate = heartRate;
}
protected:
int32_t _rate;
int32_t _spO2;
// Based Sparkfun SPO2 example
MAX30105 particleSensor;
// Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
// To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
// TODO: 8266 has memory problem?
uint32_t irBuffer[100]; // infrared LED sensor data
uint32_t redBuffer[100]; // red LED sensor data
int32_t bufferLength = 100; // data length
byte i = 0;
};
Description
I've been studying the possibility of giving support to the MAX30100 sensor; from what I've seen it should be very similar to the support given for DHT sensors; instead of temperature and humidity, oxygen percentage and pulses per minute should be reported (I wrote some code, I'll upload it later). My biggest doubt is which library to use. Of those I saw, the most suitable one seemed to me to be this one https://registry.platformio.org/libraries/oxullo/MAX30100lib My doubt is if it can be used as it is under Espurna; this library directly uses Wire and I don't know if it generates any port problems or something similar (from what I've seen, Espurna doesn't use Wire for i2c connections). Could this library be used directly? Or, would I have to use another one? Thanks
Solution
No response
Alternatives
No response
Additional context
No response