Version beta

Dependencies:   BLE_API Definiciones Funciones HeartRate_ Hotboards_rtcc LM_35 MAX_30100 MMA8451Q Pines SDFileSystem mbed nRF51822

Fork of MAX30100_oxullo by Eduardo Avelar

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;
    }
}