Version beta
Dependencies: BLE_API Definiciones Funciones HeartRate_ Hotboards_rtcc LM_35 MAX_30100 MMA8451Q Pines SDFileSystem mbed nRF51822
Fork of MAX30100_oxullo by
main.cpp
- Committer:
- arturogasca
- Date:
- 2017-01-19
- Revision:
- 1:5ecac6e368d2
- Parent:
- 0:80ecccd27646
File content as of revision 1:5ecac6e368d2:
#include "mbed.h"
#include "pines.h"
#include "ble/BLE.h"
#include "ble/services/UARTService.h"
#include "MMA8451Q.h"
#include "MAX30100_PulseOximeter.h"
#include "SDFileSystem.h"
#include "LM35.h"
#include "Hotboards_rtcc.h"
#include "HeartRate.h"
//////////////////////////////Definiciones BLE
#define WAIT_CONECTION_TIMEOUT 20
const char *bleName = "BIOMETRICOS";
BLEDevice ble;
UARTService *uartServicePtr;
bool BLE_DATA_AVAILABLE = false;
bool BLE_AVAILABLE =true;
bool BLE_TIMEOUT = true;
int BleSeconds = 0;
uint8_t datosBle[20];
#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
* it will have an impact on code-size and power consumption. */
#if NEED_CONSOLE_OUTPUT
#define DEBUG(STR) { if (uartServicePtr) uartServicePtr->write(STR, strlen(STR)); }
#else
#define DEBUG(...) /* nothing */
#endif /* #if NEED_CONSOLE_OUTPUT */
///////////////////////////Definiciones para RTC
const char *week[] = {"Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"};//days of the week
const char *months[] = {"ENE","FEB","MAR","ABR","MAY","JUN", "JUL", "AGO","SEP","OCT","NOV","DIC"};//months of the year
I2C device(I2C_SDA,I2C_SCL); //sda scl
Hotboards_rtcc rtcc(device);
//////////////////Variables de sensores para almacenamiento / envio
float Temperatura;
float RitmoCardiaco;
uint16_t Oxigeno;
uint16_t Pasos;
///////////////////////Definicion para Sensor de temperatura
LM35 SensorTemp(PIN_ADC1); //PIN_ADC
//////////////////////Definicion para Thermistor
AnalogIn thermistor(PIN_ADC2);
///////////////////////////////////////Definicion de SD
SDFileSystem sd(MOSI,MISO,SCLK,CS, "sd"); // // mosi, miso, sclk, cs, name
const char* PathSensores = "/sd/LogSensores/sensores.txt";
const char* PathECG = "/sd/LogSensores/ECG.txt";
const char* PathAxis = "/sd/LogSensores/Axis.txt";
bool archivo = true;
//////////////////////////Definicion de tiempos
#define REGISTER_TIME 30
#define UPDATE_TIME 1
int RegisterSeconds = 0;
int UpdateSeconds = 0;
bool SampleTime = false;
//Ticker t1;
//Ticker t2;
/////////////////////////Definicion de sensor ECG
#define MUESTRAS_ECG 100
bool ECG_SAMPLE_READY = false;
int ecg_idx = 0;
unsigned short ecgSamples[MUESTRAS_ECG];
float ecgSamples_f[MUESTRAS_ECG];
HeartRate HR(ECG_OUT, ECG_LO_PLS, ECG_LO_MIN);
////////////////////Definicion de sensor RESPIRACION
#define MUESTRAS_RESP 100
bool RESP_SAMPLE_READY = false;
int resp_idx = 0;
unsigned short respSamples[MUESTRAS_RESP];
float respSamples_f[MUESTRAS_RESP];
////////////////////Definicion de muestras ACELEROMETRO
#define MMA8451_I2C_ADDRESS (0x1d<<1)
MMA8451Q acc(I2C_SDA, I2C_SCL, MMA8451_I2C_ADDRESS);
#define MUESTRAS_AXIS 100
bool AXIS_SAMPLE_READY = false;
int axis_idx = 0;
float axisSamples[MUESTRAS_AXIS][3]; //100 muestras, 3 ejes
//float axisSamples_f[MUESTRAS_axis];
// PulseOximeter is the higher level interface to the sensor
// it offers:
// * beat detection reporting
// * heart rate calculation
// * SpO2 (oxidation level) calculation
///////////////////////////Definiciones para sensor OXIMETRIA
PulseOximeter pox;
bool newValueMAX30100 = 0;
float heartRate;
float finalHeartRate;
uint8_t sp02;
uint16_t finalSp02;
std::vector<float> valuesHeartRate;
std::vector<uint8_t> valuesSp02;
uint32_t REPORTING_PERIOD_MS = 1000;
uint8_t samplesMAX30100 = 10;
uint8_t counterMAX30100 = 0;;
/////////////////////////////////////////////////////////////////
Serial pc(SERIAL_TX, SERIAL_RX);
DigitalOut led1(LED_R);
DigitalOut led2(LED_N);
FILE *fp;
/////////////////////////////////////////////////////////////////////////////////////
//////////////Declaracion de funciones/////////////////////////
void onBeatDetected();
void CadaSegundo() ;
void TiempoSample();
bool inicia_sd();
bool setup();
void do_remove(const char *fsrc);
void getOxi();
void getTemp();
void registraSamples();
void registraSensores();
void getSample_ECG();
void getSample_RESP();
void getSample_AXIS();
void write_ECG_file();
void write_AXIS_file();
void updateSensors ();
/////////////////////////////////////////////////////
void waitEvent()
{
if(BLE_DATA_AVAILABLE)
{
BLE_DATA_AVAILABLE = false;
switch(datosBle[0])
{
case '1': DEBUG("Recibi 1\r\n");
{
break;
}
case '2': DEBUG("Recibi 2\r\n");
{
break;
}
case '3': DEBUG("Recibi 3\r\n");
{
break;
}
case '4': DEBUG("Recibi 4\r\n");
{
break;
}
}
}
}
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
led2=0;
ble.startAdvertising();
BLE_AVAILABLE = false;
}
void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
BLE_TIMEOUT = false;
led2=1;
}
void onDataWritten(const GattWriteCallbackParams *params)
{
if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getTXCharacteristicHandle())) {
uint16_t bytesRead = params->len;
pc.printf("received %u bytes\r\n", bytesRead);
for(int i=0;i<bytesRead;i++){
datosBle[i] = params->data[i];
}
BLE_DATA_AVAILABLE = true;
}
}
/*
void inicia_ble()
{
t1.attach(&CadaSegundo,1);
t2.attach(&TiempoSample,0.01);
pc.printf("Initialising the nRF51822\n\r");
ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onDataWritten(onDataWritten);
/// setup advertising
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
(const uint8_t *)bleName, strlen(bleName));
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
ble.setAdvertisingInterval(160); // 100ms; in multiples of 0.625ms.
ble.startAdvertising();
UARTService uartService(ble);
uartServicePtr = &uartService;
}
*/
void blink1(int times1, float wait1)
{
for(int b =0; b< times1; b++)
{
led1= 1;
wait(wait1);
led1 =0 ;
wait(wait1);
}
}
void blink2(int times2, float wait2)
{
for(int a =0; a< times2; a++)
{
led2= 1;
wait(wait2);
led2 =0 ;
wait(wait2);
}
}
/////////////////////////////////////////////////////////////////////////////////////
int main()
{
pc.printf("Inicio main\n\r");
blink1(4,0.1);
blink2(8,0.2);
//t1.attach(&CadaSegundo,1);
//t2.attach(&TiempoSample,0.01);
pc.printf("Initialising the nRF51822\n\r");
ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onConnection(connectionCallback);
ble.onDataWritten(onDataWritten);
//setup advertising
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
(const uint8_t *)bleName, strlen(bleName));
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
ble.setAdvertisingInterval(160); // 100ms; in multiples of 0.625ms.
ble.startAdvertising();
UARTService uartService(ble);
uartServicePtr = &uartService;
//inicia_ble();
if(setup())
pc.printf("Sensores Inicializados\r\n");
else
pc.printf("Error en inicializacion\r\n");
pc.printf("Inicio del programa\r\n");
while(BLE_AVAILABLE)
{
ble.waitForEvent();
waitEvent();
}
while(1) {
updateSensors();
led1 = !led1;
wait(0.2);
}
}
// Callback (registered below) fired when a pulse is detected
void onBeatDetected()
{
// pc.printf("Beat!\r\n");
}
void CadaSegundo() //Aumenta dos contadores cada segundo para registro y actualizacion
{
RegisterSeconds++;
UpdateSeconds++;
if(BLE_TIMEOUT){
BleSeconds++;
pc.printf("timeout: %d\r\n",BleSeconds);
if(BleSeconds == WAIT_CONECTION_TIMEOUT){
BLE_AVAILABLE = false;
BLE_TIMEOUT = false;
}
}
}
void TiempoSample() //Timer para samples de Ritmocardiaco,Respiracion y acelerometro
{
SampleTime = true;
}
bool inicia_sd()
{
bool response;
/* fp = fopen(PathSensores, "a"); //Intento abrir el archivo... "append"
if(fp == NULL) {
pc.printf("No pude abrir el archivo\r\n");
archivo = false; //no existe el archivo
}
else
{
fprintf(fp, "Dispositivo reiniciado : \r\n"); //Fue un reinicio, solo se logea
pc.printf("Si existe un archivo\n");
response = true;
}
fclose(fp);
if (!archivo)
{
pc.printf("Creando Carpeta de Logs\r\n");
mkdir("/sd/LogSensores", 0777);
fp = fopen(PathSensores, "w");
if(fp == NULL)
{
pc.printf("No pude abrir el archivo log %s\r\n",PathSensores);
response = false;
}
else
{
fprintf(fp, "LOG %s creado:\r\n",PathSensores);
pc.printf("Archivo %s creado por primera vez!\r\n",PathSensores);
fclose(fp);
wait(0.2);
fp = fopen(PathECG, "w");
if(fp == NULL){
pc.printf("No pude abrir el archivo log %s\r\n",PathECG);
response = false;
}
else
{
fprintf(fp, "LOG %s creado:\r\n",PathECG);
pc.printf("Archivo %s creado por primera vez!\r\n",PathECG);
fclose(fp);
wait(0.2);
fp = fopen(PathAxis, "w");
if(fp == NULL){
pc.printf("No pude abrir el archivo log %s\r\n",PathAxis);
response = false;
}
else
{
fprintf(fp, "LOG %s creado:\r\n",PathAxis);
pc.printf("Archivo %s creado por primera vez!\r\n",PathAxis);
response = true;
}
}
fclose(fp);
}
}*/
return response;
}
bool setup()
{
pc.printf("Start program!\r\n");
//incializacion SD y archivos de log
inicia_sd();
rtcc.begin();
/* set the time (12:30:00) and date 28/nov/2016 */
// rtcc.adjust( DateTime( 2016, 10, 28, 12, 30, 0) ); //year,month,day,hour,min, sec,dow
// Initialize the PulseOximeter instance and register a beat-detected callback
if(!pox.begin())
return false;
pox.setOnBeatDetectedCallback(onBeatDetected);
return true;
}
void do_remove(const char *fsrc)
{
DIR *d = opendir(fsrc);
struct dirent *p;
char path[30] = {0};
while((p = readdir(d)) != NULL) {
strcpy(path, fsrc);
strcat(path, "/");
strcat(path, p->d_name);
remove(path);
}
closedir(d);
remove(fsrc);
}
void getOxi()
{
heartRate = pox.getHeartRate();
sp02 = pox.getSpO2();
if(heartRate != 0 && sp02 != 0) {
pc.printf("Heart rate: %f",heartRate);
pc.printf(" bpm / SpO2: %d%\r\n",sp02);
valuesHeartRate.push_back(heartRate);
valuesSp02.push_back(sp02);
counterMAX30100 ++;
} else {
pc.printf("Valor Oximetria cero\r\n");
Oxigeno = 0;
RitmoCardiaco = 0.00;
pc.printf("No finger\r\n");
}
if(samplesMAX30100 == counterMAX30100) {
finalHeartRate = 0;
finalSp02 = 0;
for(int i=0; i<samplesMAX30100; i++) {
finalHeartRate += valuesHeartRate[i];
finalSp02 += valuesSp02[i];
}
finalHeartRate /= samplesMAX30100;
finalSp02 /= samplesMAX30100;
counterMAX30100 = 0;
valuesHeartRate.clear();
valuesSp02.clear();
newValueMAX30100 = true;
}
if(newValueMAX30100) {
pc.printf("Valor Oximetria valido\r\n");
newValueMAX30100 = false;
RitmoCardiaco = finalHeartRate;
Oxigeno = finalSp02;
}
}
void getTemp()
{
Temperatura = SensorTemp.get();
}
void registraSamples()
{
//return(true);
}
void registraSensores()
{
/* pc.printf("Write sensors file\r\n");
DateTime time = rtcc.now( );
pc.printf("%d:%d:%d,%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
/*fp = fopen("/sd/LogSensores/sensores.txt", "a"); //"a" append
if(fp == NULL) {
pc.printf("No pude abrir! :(\r\n");
return(false);
} else {
DateTime time = rtcc.now( );
fprintf(fp,"T=%.2f,O=%d,RC=%.2f,P=%d,",Temperatura,Oxigeno,RitmoCardiaco,Pasos);
fprintf(fp,"H=%d:%d:%d,F=%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
fclose(fp);
pc.printf("Escribi en SD! :D \r\n");
pc.printf("T=%.2f,O=%d,RC=%.2f,P=%d,",Temperatura,Oxigeno,RitmoCardiaco,Pasos);
pc.printf("H=%d:%d:%d,F=%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
return(true);
}*/
}
void getSample_ECG()
{
if(HR.available())
{
ecgSamples[ecg_idx++] = HR.read();
}
else
{
ecgSamples[ecg_idx++] = 0;
}
if(ecg_idx == MUESTRAS_ECG)
{
ecg_idx =0;
ECG_SAMPLE_READY = true;
}
}
void getSample_RESP()
{
respSamples[resp_idx++] = thermistor.read_u16();
if (resp_idx == MUESTRAS_RESP)
{
resp_idx = 0;
RESP_SAMPLE_READY = true;
}
}
void getSample_AXIS()
{
float x, y, z;
x = abs(acc.getAccX());
y = abs(acc.getAccY());
z = abs(acc.getAccZ());
axisSamples[axis_idx][0] = x;
axisSamples[axis_idx][1] = y;
axisSamples[axis_idx][2] = z;
axis_idx++;
if (axis_idx == MUESTRAS_AXIS)
{
axis_idx = 0;
AXIS_SAMPLE_READY = true;
}
}
void write_ECG_file()
{
bool response;
/*pc.printf("Write ECG file\r\n");
DateTime time = rtcc.now( );
pc.printf("%d:%d:%d,%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
/*if(true)
{
fp = fopen(PathECG, "a"); //"a" append
if(fp == NULL)
{
pc.printf("No pude abrir! :(\r\n");
response =false;
}
else
{
DateTime time = rtcc.now( );
fprintf(fp,"%d:%d:%d,%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
for (int i =0; i< MUESTRAS_ECG; i++)
{
fprintf(fp,"%d",ecgSamples[i]);
}
pc.printf("Escribi en SD! :D \r\n");
response = true;
}
fclose(fp);
}*/
//return response;
}
void write_AXIS_file()
{
bool response;
/* pc.printf("Write axis file\r\n");
DateTime time = rtcc.now( );
pc.printf("%d:%d:%d,%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
/* fp = fopen(PathAxis, "a"); //"a" append
if(fp == NULL)
{
pc.printf("No pude abrir! :(\r\n");
response = false;
}
else
{
DateTime time = rtcc.now( );
fprintf(fp,"%d:%d:%d,%d/%s/%d\r\n",time.hour( ),time.minute( ),time.second( ),
time.day( ),months[time.month( )],time.year());
for (int i =0; i< MUESTRAS_AXIS; i++)
{
fprintf(fp,"%1.2f,%1.2f,%1.2f",axisSamples[0][i],axisSamples[1][i],axisSamples[2][i]);
}
pc.printf("Escribi en SD! :D \r\n");
response = true;
}
fclose(fp);*/
//return response;
}
void updateSensors ()
{
// Make sure to call update as fast as possible
pox.update();
//<-Get Step Accel
if(SampleTime){
//cuando se cumpla el tiempo...obtener 1 muestra y aumentar contador
//getSample ECG
//getSample Respiracion
//getSample Axis
getSample_ECG();
getSample_RESP();
getSample_AXIS();
SampleTime = false;
}
if (ECG_SAMPLE_READY)
{
ECG_SAMPLE_READY = false;
write_ECG_file();
//escribir todas las muestras en SD y borrar contador
}
if (AXIS_SAMPLE_READY)
{
AXIS_SAMPLE_READY = false;
write_AXIS_file();
//escribir todas las muestras en SD y borrar contador
}
if (RESP_SAMPLE_READY);
{
RESP_SAMPLE_READY = false;
//Analisis de datos para deteccion de picos
//escribir todas lasmuestras en SD y borrar contador
}
if (UpdateSeconds >= UPDATE_TIME) { //Si ya paso el tiempo definido en UPDATE_TIME
getOxi();
getTemp();
UpdateSeconds = 0;
}
if (RegisterSeconds >= REGISTER_TIME) { //Si ya paso el tiempo definido en REGISTER_TIME
registraSensores();
RegisterSeconds = 0;
}
}
Arturo Gasca
