ECE 4180 Fitbit Project / Mbed 2 deprecated 4180_Fitness_Tracker

Dependencies:   mbed PulseSensor2 SCP1000 mbed-rtos 4DGL-uLCD-SE LSM9DS1_Library_cal PinDetect FatFileSystemCpp GP-20U7

main.cpp

Committer:
dyu2021
Date:
2020-04-16
Revision:
22:9442c37f793f
Parent:
20:adb9e6e1ad22
Child:
23:1971e5cb6e3f

File content as of revision 22:9442c37f793f:

#include "mbed.h"
#include "rtos.h"
#include "LSM9DS1.h"
#include "SCP1000.h"
#include "MSCFileSystem.h"
#include "PulseSensor.h"
#include "PinDetect.h"
#include "uLCD_4DGL.h"

SCP1000 scp1000(p5,p6,p7,p8);
LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
PulseSensor PPG(p20);
uLCD_4DGL uLCD(p28,p27,p21);
Serial pc(USBTX, USBRX);
DigitalOut myled = LED1;
DigitalOut led2(LED2);
AnalogIn pot(p19);
PinDetect pb(p29);

#define FSNAME "msc"
MSCFileSystem msc(FSNAME);

volatile int bpm;
volatile int steps = 0;
volatile int flights = 0;
volatile float distance = 0.0;
volatile int calories = 0;
//char stat_string[3];

volatile int mode = 1;
volatile int oldMode = 1;

Thread thread1;
Thread thread2;
Thread thread3;
Thread thread4;
Thread thread5;

bool run = true;

// when the pushbotton is pressed the run flag is set to false and the main 
// function while loop exits so that the data file can be closed 
// so press the button when you're ready to be done collecting data
void button (void) {
    run = false;
}

// Reads the value of the potentiometer and averages over 3 readings to get rid 
// of random spikes/zero values. Returns either a 1, 2 or 3 based on which 3rd 
// of its range the potentiometer is in and which screen should be displayed
void read_pot() {
    float m1; 
    float m2;
    float m3;
    while(1) {
        oldMode = mode;
        m1 = pot.read();
        m2 = pot.read();
        m3 = pot.read();
        if(m1 < 0.2 && m2 < 0.2 && m3 < 0.2) {
            mode = 1;
        } else if(m1 >= 0.2 && m1 < 0.4 && m2 >= 0.2 && m2 < 0.4 && m3 >= 0.2 && m3 < 0.4) {
            mode = 2;
        } else if(m1 >= 0.4 && m1 < 0.6 && m2 >= 0.4 && m2 < 0.6 && m3 >= 0.4 && m3 < 0.6) {
            mode = 3;
        } else if(m1 >= 0.6 && m1 < 0.8 && m2 >= 0.6 && m2 < 0.8 && m3 >= 0.6 && m3 < 0.8) {
            mode = 4;
        } else if(m1 >= 0.8 && m2 >= 0.8 && m3 >= 0.8) {
            mode = 5;
        }
        //when the mode changes, clear the screen
        if (oldMode != mode) {
            mtx.lock();
            uLCD.filled_rectangle(0,0, 128, 128, BLACK);
            mtx.unlock();
        }
        Thread::wait(200);
    }
}    

//Display the time on the top
void display_time() {
    while(1) {
        mtx.lock();
        uLCD.locate(1, 1);
        uLCD.color(WHITE);
        uLCD.text_width(2);
        uLCD.text_height(3);
        time_t seconds = time(NULL);
        char timeBuffer[32];
        strftime(timeBuffer, 32, "%I:%M %p\r\n", localtime(&seconds));
        uLCD.printf("%s", timeBuffer);
        mtx.unlock();
        Thread::wait(500);
    }
}

/*
//Make sure program still alive
void blink_led() {
    while(1) {
        led2 = !led2;
        Thread::wait(1000);
    }
}  
*/

void update_screen(void) {
        while(1) {
        mtx.lock();
        // print the information to the LCD display
        switch(mode) {
            case 1:
                //Step count
                /*
                uLCD.media_init();
                uLCD.set_sector_address(0x0000, 0x0000);
                uLCD.display_image(0,0);
                */
                uLCD.filled_rectangle(10, 110, 118, 115, BLACK);
                uLCD.locate(3, 11);
                uLCD.text_height(1);
                uLCD.text_width(1);
                uLCD.color(WHITE);
                uLCD.printf("%4d steps",steps);
                uLCD.filled_rectangle(10, 110, 118, 115, WHITE);
                break;
            case 2:
                // Heart rate
                uLCD.locate(5, 11);
                uLCD.text_height(1);
                uLCD.text_width(1);
                uLCD.color(WHITE);
                uLCD.printf("%3d BPM", bpm);
                break;
            case 3:
                //Distance
                uLCD.locate(6, 11);
                uLCD.text_height(1);
                uLCD.text_width(1);
                uLCD.color(WHITE);
                uLCD.printf("%4.2f MI", distance);
                break;
            case 4:
                //Calories
                uLCD.locate(4, 11);
                uLCD.text_height(1);
                uLCD.text_width(1);
                uLCD.color(WHITE);
                uLCD.printf("%4d cal", calories);
                break;
            case 5:
                //Floors
                uLCD.locate(4, 11);
                uLCD.text_height(1);
                uLCD.text_width(1);
                uLCD.color(WHITE);
                uLCD.printf("%2d floors", flights);
                break;
        }
        mtx.unlock();
        Thread::wait(100);
    }
}

//Read heart rate sensor, only want to read it if in heart rate mode
void read_heartRate() {
    while(mode == 2 && run) {
        bpm = PPG.get_BPM();
        Thread::wait(400);
    }
}

//Read barometer and count floors
void read_barameter() {
    unsigned long pressure;
    while(run) {
        pressure = scp1000.readPressure();
        //Floor counting algo here
        Thread::wait(200);
    }
}
        
int main() {
    // Off button
    pb.mode(PullUp);
    pb.attach_deasserted(&button);
    pb.setSampleFrequency();
    
    // set up the display
    uLCD.baudrate(3000000);
    uLCD.background_color(BLACK);
    uLCD.cls();
    
    //Set RTC time
    set_time(1256729737);
    
    // LED indicates whether or not data is being collected
    myled = 0;
    // Start sensors
    int sample_num = 0;
    PPG.start();
    IMU.begin();
    IMU.calibrate(1);
    float ax;
    float ay;
    float az;
    float mag = 0;
    float buffer[2] = {0};
    float avg_buffer[2] = {0};
    float avg;

    // Initialize data file on usb flash drive
    FILE *fp = fopen( "/msc/data.txt", "w");
    if(fp == NULL) {
        error("Could not open file for write\n");
    }
    fprintf(fp, "sample number, pressure (Pa), ax (Gs), ay (Gs), az (Gs), lowpassed magnitude (Gs), heart rate (bpm)\n");
    
    //Start threads
    thread1.start(update_screen);
    thread2.start(display_time);
    thread3.start(read_pot);
    thread4.start(read_heartRate);
    thread5.start(read_barometer);
    
    while(run) {
        // Read Sensors
        //bpm = PPG.get_BPM();
        //pressure = scp1000.readPressure();
        IMU.readAccel();
        ax = IMU.calcAccel(IMU.ax);
        ay = IMU.calcAccel(IMU.ay);
        az = IMU.calcAccel(IMU.az);
        // Calculate the 3 point moving average of the magnitude of the 
        // acceleration vector
        mag = sqrt((ax*ax) + (ay*ay) + (az*az));
        avg = (buffer[0] + buffer[1] + mag) / 3;
        buffer[0] = buffer[1];
        buffer[1] = mag;
        // Count a step if the previous point was a maximum (greater than the 
        // current point and 2 points back) and was greater than the threshold 
        // value of 1.05
        if(sample_num > 1) {
            if((avg_buffer[1] > avg_buffer[0]) && (avg < avg_buffer[1]) && (avg_buffer[1] > 1.05)) {
                steps++;
            }
        }
        avg_buffer[0] = avg_buffer[1];
        avg_buffer[1] = avg;
        // Save the data to the usb flash drive and print to the terminal
        fprintf(fp, "%d, %lu, %f, %f, %f, %f, %d\r\n", sample_num, pressure, ax, ay, az, avg, bpm); 
        pc.printf("%d, %lu, %f, %f, %f, %f, %d\r\n", sample_num, pressure, ax, ay, az, avg, bpm); 
        sample_num++;
        myled = 1;
        // Sampling rate of ~200 Hz
        Thread::wait(50);
    }
    fclose(fp);
    myled = 0;
}