Version beta
Dependencies: BLE_API Definiciones Funciones HeartRate_ Hotboards_rtcc LM_35 MAX_30100 MMA8451Q Pines SDFileSystem mbed nRF51822
Fork of MAX30100_oxullo by
Diff: main.cpp
- Revision:
- 1:5ecac6e368d2
- Parent:
- 0:80ecccd27646
diff -r 80ecccd27646 -r 5ecac6e368d2 main.cpp --- a/main.cpp Fri Nov 25 00:54:29 2016 +0000 +++ b/main.cpp Thu Jan 19 20:26:20 2017 +0000 @@ -1,127 +1,717 @@ -/* -Arduino-MAX30100 oximetry / heart rate integrated sensor library -Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org> -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ +#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 -#include "MAX30100_PulseOximeter.h" +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; + -//#define REPORTING_PERIOD_MS 1000 +/////////////////////////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 -Serial pc(USBTX, USBRX); -Timer t; +#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 -PulseOximeter pox; - -uint32_t tsLastReport = 0; - -// Callback (registered below) fired when a pulse is detected - -void onBeatDetected() -{ - // pc.printf("Beat!\r\n"); -} -bool setup() -{ - pc.baud(115200); - pc.printf("Start program!\r\n"); - //pox = new PulseOximeter (&pc); - - // Initialize the PulseOximeter instance and register a beat-detected callback - if(!pox.begin()) - return false; - pox.setOnBeatDetectedCallback(onBeatDetected); - return true; -} +///////////////////////////Definiciones para sensor OXIMETRIA + +PulseOximeter pox; bool newValueMAX30100 = 0; float heartRate; float finalHeartRate; uint8_t sp02; uint16_t finalSp02; -uint32_t REPORTING_PERIOD_MS = 1000; std::vector<float> valuesHeartRate; std::vector<uint8_t> valuesSp02; + +uint32_t REPORTING_PERIOD_MS = 1000; uint8_t samplesMAX30100 = 10; uint8_t counterMAX30100 = 0;; +///////////////////////////////////////////////////////////////// -void updateMAX30100 (){ +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(); - if (t.read_ms() > REPORTING_PERIOD_MS) { - 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("No finger\r\n"); - } + //<-Get Step Accel + + if(SampleTime){ + //cuando se cumpla el tiempo...obtener 1 muestra y aumentar contador + //getSample ECG + //getSample Respiracion + //getSample Axis - 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; - } - - t.reset(); - } -} + 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 -void loop() -{ - updateMAX30100(); - - if(newValueMAX30100){ - pc.printf("--->New Value\r\n"); - pc.printf("Heart rate: %f",finalHeartRate); - pc.printf(" bpm / SpO2: %d%\r\n",finalSp02); - pc.printf("*************************\r\n"); - newValueMAX30100 = false; + registraSensores(); + RegisterSeconds = 0; } - -} - -int main() -{ - if(setup()) - pc.printf("MAX30100 beginning\r\n"); - else - return 0; - - t.start(); - while(1) - loop(); } \ No newline at end of file