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

Revision:
31:3363c6923beb
Parent:
25:41ec16a87ebd
Child:
32:cdbd7de8ae10
--- a/main.cpp	Wed Apr 22 14:52:37 2020 +0000
+++ b/main.cpp	Wed Apr 22 20:00:57 2020 +0000
@@ -2,10 +2,11 @@
 #include "rtos.h"
 #include "LSM9DS1.h"
 #include "SCP1000.h"
-#include "MSCFileSystem.h"
 #include "PulseSensor.h"
 #include "PinDetect.h"
 #include "uLCD_4DGL.h"
+#include "GPS.h"
+#include "MSCFileSystem.h"
  
 SCP1000 scp1000(p5,p6,p7,p8);
 LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
@@ -18,39 +19,64 @@
 DigitalOut four = LED4;
 AnalogIn pot(p20);
 PinDetect pb(p21);
- 
+GPS gps(p13, p14);
+
 #define FSNAME "msc"
-MSCFileSystem msc(FSNAME);
+MSCFileSystem msc(FSNAME); 
  
-volatile int bpm;
-volatile int steps = 0;
-volatile int flights = 0;
-volatile float distance = 0.0;
-volatile int calories = 0;
-volatile unsigned long pressure;
+int bpm;
+int steps = 0;
+int flights = 0;
+float distance = 0.0;
+float calories = 0;
+int oldSteps = 0;
+const int stepGoal = 100;
+float stride_length = 0.0;
+
+unsigned long pressure;
+float latitude = 0;
+float longitude = 0;
+float old_lat = 0;
+float old_lon = 0;
+#define PI 3.14159
+unsigned long p_buff[4];
+int count = 0;
+
+int mode = 1;
+int oldMode = 1;
  
-volatile int mode = 1;
-volatile int oldMode = 1;
- 
+bool run = true;
+
+int gender;
+int weight;
+int age;
+int screen = 1;
+int oldScreen = 1;
+bool setup_state = true;
+
+Timer usb_timer;
+
 Thread thread1;
 Thread thread2;
 Thread thread3;
 Thread thread4;
 Thread thread5;
- 
-bool run = true;
-Mutex mtx;
+Mutex serial_mtx;
+Mutex usb_mtx;
  
 // 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;
-    thread1.terminate();
-    thread2.terminate();
-    thread3.terminate();
-    thread4.terminate();
-    thread5.terminate();
+}
+
+void next() {
+    oldScreen = screen;
+    screen++;
+    if(screen == 4) {
+        setup_state = false;
+    }
 }
  
 // Reads the value of the potentiometer and averages over 3 readings to get rid 
@@ -60,36 +86,28 @@
     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);
+    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
 }    
  
 //Display the time on the top
 void display_time() {
     while(1) {
-        mtx.lock();
+        serial_mtx.lock();
         uLCD.locate(1, 1);
         uLCD.color(WHITE);
         uLCD.text_width(2);
@@ -98,44 +116,116 @@
         char timeBuffer[32];
         strftime(timeBuffer, 32, "%I:%M %p\r\n", localtime(&seconds));
         uLCD.printf("%s", timeBuffer);
-        mtx.unlock();
-        Thread::wait(500);
+        serial_mtx.unlock();
+        Thread::wait(700);
+    }
+}
+
+void setup_screen(void) {
+    while(1) {
+        serial_mtx.lock();
+        if (oldScreen != screen) {
+            uLCD.filled_rectangle(0,0, 128, 128, BLACK);
+            oldScreen++;
+        }
+        switch(screen) {
+            case 1:
+                //Gender
+                uLCD.locate(2, 1);
+                uLCD.text_width(2);
+                uLCD.text_height(2);
+                uLCD.puts("Gender");
+                uLCD.text_width(3);
+                uLCD.text_height(3);
+                uLCD.locate(1, 3);
+                uLCD.putc('M');
+                uLCD.locate(4, 3);
+                uLCD.putc('F');
+                if(pot.read() > 0.5) {
+                    gender = 0;
+                    uLCD.rectangle(13, 60, 48, 100, BLACK);
+                    uLCD.rectangle(75, 60, 110, 100, GREEN);
+                } else {
+                    gender = 1;
+                    uLCD.rectangle(75, 60, 110, 100, BLACK);
+                    uLCD.rectangle(13, 60, 48, 100, GREEN);
+                }
+                break;
+            case 2:
+                //Weight
+                uLCD.color(WHITE);
+                uLCD.locate(9, 14);
+                uLCD.text_width(1);
+                uLCD.text_height(1);
+                uLCD.puts("lbs");
+                uLCD.locate(2, 1);
+                uLCD.text_width(2);
+                uLCD.text_height(2);
+                uLCD.puts("Weight");
+                weight = 0.45 * (90 + pot.read() * 210);
+                char weight_string[3];
+                if(weight < 100) {
+                    sprintf(weight_string, " %d", weight);
+                } else {
+                    sprintf(weight_string, "%d", weight);
+                }
+                uLCD.text_width(3);
+                uLCD.text_height(3);
+                uLCD.locate(2, 3);
+                uLCD.color(GREEN);
+                uLCD.puts(weight_string);
+                uLCD.line(35, 100, 110, 100, WHITE);
+                break;
+            case 3:
+                //Age
+                uLCD.color(WHITE);
+                uLCD.locate(3, 1);
+                uLCD.text_width(2);
+                uLCD.text_height(2);
+                uLCD.puts("Age");
+                age = (int) (10 + pot.read() * 89);
+                char age_string[2];
+                sprintf(age_string, "%d", age);
+                uLCD.text_width(3);
+                uLCD.text_height(3);
+                uLCD.locate(2, 3);
+                uLCD.color(GREEN);
+                uLCD.puts(age_string);
+                uLCD.line(40, 100, 90, 100, WHITE);
+                break;
+        }
+        serial_mtx.unlock();
+        Thread::wait(100);
     }
 }
  
-/*
-//Make sure program still alive
-void blink_led() {
+void update_screen(void) {
     while(1) {
-        led2 = !led2;
-        Thread::wait(1000);
-    }
-}  
-*/
- 
-void update_screen(void) {
-        while(1) {
-        mtx.lock();
+        read_pot();
+        serial_mtx.lock();
+        if (oldMode != mode) {
+            uLCD.filled_rectangle(0,0, 128, 128, BLACK);
+        }
         // print the information to the LCD display
         switch(mode) {
             case 1:
                 //Step count
-                uLCD.media_init();
-                uLCD.set_sector_address(0x0000, 0x0005);
-                uLCD.display_image(50, 45);
+                //uLCD.media_init();
+                //uLCD.set_sector_address(0x0000, 0x0005);
+                //uLCD.display_image(50, 45);
                 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);
+                uLCD.filled_rectangle(10, 110, 10 + int(steps * (110/stepGoal)), 115, WHITE);
                 break;
             case 2:
                 // Heart rate
-                uLCD.media_init();
-                uLCD.set_sector_address(0x0000, 0x000A);
-                uLCD.display_image(50, 45);
+                //uLCD.media_init();
+                //uLCD.set_sector_address(0x0000, 0x000A);
+                //uLCD.display_image(50, 45);
                 uLCD.locate(5, 11);
                 uLCD.text_height(1);
                 uLCD.text_width(1);
@@ -144,31 +234,31 @@
                 break;
             case 3:
                 //Distance
-                uLCD.media_init();
-                uLCD.set_sector_address(0x0000, 0x000F);
-                uLCD.display_image(50, 45);
+                //uLCD.media_init();
+                //uLCD.set_sector_address(0x0000, 0x000F);
+                //uLCD.display_image(50, 45);
                 uLCD.locate(6, 11);
                 uLCD.text_height(1);
                 uLCD.text_width(1);
                 uLCD.color(WHITE);
-                uLCD.printf("%4.2f MI", distance);
+                uLCD.printf("%4.2f ft", distance);
                 break;
             case 4:
                 //Calories
-                uLCD.media_init();
-                uLCD.set_sector_address(0x0000, 0x0000);
-                uLCD.display_image(50, 45);
+                //uLCD.media_init();
+                //uLCD.set_sector_address(0x0000, 0x0000);
+                //uLCD.display_image(50, 45);
                 uLCD.locate(4, 11);
                 uLCD.text_height(1);
                 uLCD.text_width(1);
                 uLCD.color(WHITE);
-                uLCD.printf("%4d cal", calories);
+                uLCD.printf("%4d cal", (int)calories);
                 break;
             case 5:
                 //Floors
-                uLCD.media_init();
-                uLCD.set_sector_address(0x0000, 0x0014);
-                uLCD.display_image(50, 45);
+                //uLCD.media_init();
+                //uLCD.set_sector_address(0x0000, 0x0014);
+                //uLCD.display_image(50, 45);
                 uLCD.locate(4, 11);
                 uLCD.text_height(1);
                 uLCD.text_width(1);
@@ -176,52 +266,127 @@
                 uLCD.printf("%2d floors", flights);
                 break;
         }
-        mtx.unlock();
+        serial_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) {
+
+void readHR(){
+    while(1) {
         bpm = PPG.get_BPM();
-        Thread::wait(400);
+        //calories = calories + (.0083)*.239*(gender*(-55.0969+.6309*bpm+.1988*weight+.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*weight+.074*age));
+        calories = calories + (.0083)*0.239*(gender*(-55.0969+.6309*bpm+.1988*0.453592*weight
+                                             +.2017*age)+(1-gender)*(-20.4022+.4472*bpm-.1263*0.453592*weight+.074*age));
+        //converted weight from lbs to kilograms
+
+        //Alternate way to calculate distance (likely more accurate)
+        //distance = distance + (steps - oldSteps)* stride_length;
+        //oldSteps = steps;
+        Thread::wait(500);
     }
 }
- 
-//Read barometer and count floors
-void read_barometer() {
-    unsigned long pressure_buff[10] = {0};
-    while(run) {
+
+void readBarometer()
+{
+    while(1) {
         pressure = scp1000.readPressure();
-        //Floor counting algo here
-        /*if(pressure != 0 && pressure_buff[0] != 0 && pressure - pressure_buff[0] > 100) {
-            flights++;
+        if(count >= 0) count--;
+        unsigned long dif;
+        if(pressure < p_buff[0]) {
+            dif = p_buff[0] - pressure;
+        } else {
+            dif = 0;
         }
-        for(int i = 0; i < (sizeof pressure_buff) - 1; i++) {
-            pressure_buff[i] = pressure_buff[i + 1];
+        if(pressure != 0 && p_buff[0] != 0 && dif > 40 && dif < 60 && count < 0) {
+            flights++;
+            count = 2;
         }
-        pressure_buff[9] = pressure;*/
-        Thread::wait(200);
+        p_buff[0] = p_buff[1];
+        p_buff[1] = p_buff[2];
+        p_buff[2] = p_buff[3];
+        p_buff[3] = pressure;
+        Thread::wait(2000);
     }
 }
         
+void readGPS(){
+    while(1) {
+        serial_mtx.lock();
+        if(gps.connected()) {
+            if(gps.sample()) {
+                if(gps.ns == 'S') {
+                    longitude = gps.longitude*PI/180;
+                } else {
+                    longitude = -gps.longitude*PI/180;
+                }
+                if(gps.ew == 'W') {
+                    latitude = gps.latitude*PI/180;
+                } else {
+                    latitude = -gps.latitude*PI/180;
+                }
+                if(latitude != 0 && longitude != 0 && old_lat != 0 && old_lon != 0) {
+                    float a = sinf(old_lat)*sinf(latitude)+cosf(old_lat)*cosf(latitude)*cosf(longitude-old_lon);
+                    if(a > 1) a = 1;
+                    distance = distance + (.75*acosf(a));
+                }
+                old_lat = latitude;
+                old_lon = longitude;
+                //pc.printf("%f, %f, %f\r\n", latitude, longitude, distance);
+            }
+        }
+        serial_mtx.unlock();
+        Thread::wait(10000);
+    }
+}
+
+void saveData() {
+    // Save the data to the usb flash drive and print to the terminal
+    FILE *fp = fopen( "/msc/data.txt", "a");
+    if(fp == NULL) {
+        error("Could not open file for write\n");
+    }
+    time_t seconds = time(NULL);
+    char date[32];
+    strftime(date, 32, "%m/%d/%y", localtime(&seconds));
+    fprintf(fp, "%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance);
+    pc.printf("%s\t%d\t%d\t%0.2f\t%0.2f\n\r", date, steps, flights, calories, distance);
+    fclose(fp);
+}
+
+    
 int main() {
-    // Off button
+    //Set RTC time
+    set_time(1256729737);
+    
+    // Next screen button
     pb.mode(PullUp);
-    pb.attach_deasserted(&button);
+    pb.attach_deasserted(&next);
     pb.setSampleFrequency();
     
-    // set up the display
+    //set up the display
     uLCD.baudrate(3000000);
     uLCD.background_color(BLACK);
     uLCD.cls();
+    thread1.start(setup_screen);
     
-    //Set RTC time
-    set_time(1256729737);
+    while(setup_state) {
+        pc.printf("%d\r\n", screen);
+    }
+    thread1.terminate();
+    
+    // Off button
+    pb.attach_deasserted(&button);
+    
+    // set up the display
+    uLCD.cls();
+    thread1.start(update_screen);
+    thread2.start(display_time);
     
     // LED indicates whether or not data is being collected
     one = 0;
+    two = 0;
+    three = 0;
+    four = 0;
     // Start sensors
     int sample_num = 1;
     PPG.start();
@@ -236,23 +401,29 @@
     float avg;
     
     // Initialize data file on usb flash drive
-    FILE *fp = fopen( "/msc/data.txt", "w");
+    usb_mtx.lock();
+    FILE *fp = fopen( "/msc/data.txt", "r+");
     if(fp == NULL) {
         error("Could not open file for write\n");
     }
-    fprintf(fp, "Sample Number, Pressure (Pa), Acceleration Magnitude (Gs), Heart Rate (bpm)\n");
+    //Check to see if file is empty, not working right now
+    fseek (fp, 0, SEEK_END);
+    int size = ftell(fp);
+    if (0 == size) {
+        fprintf(fp, "Date\tSteps\tFloors\tCalories\tDistance (ft)\r\n");
+        pc.printf("Data.txt rewritten\r\n");
+    }
+    fclose(fp);
+    usb_mtx.unlock();
     
-    //Start threads
-    thread1.start(update_screen);
-    thread2.start(display_time);
-    thread3.start(read_pot);
-    thread4.start(read_heartRate);
-    thread5.start(read_barometer);
-    
+    thread3.start(readBarometer);
+    thread4.start(readGPS);
+    thread5.start(readHR);
+
+    usb_timer.start();
+
     while(run) {
         // Read Sensors
-        //bpm = PPG.get_BPM();
-        //pressure = scp1000.readPressure();
         IMU.readAccel();
         ax = IMU.calcAccel(IMU.ax);
         ay = IMU.calcAccel(IMU.ay);
@@ -269,7 +440,7 @@
         if(sample_num > 1) {
             float dif1 = avg_buffer[1] - avg_buffer[0];
             float dif2 = avg_buffer[1] - avg;
-            float peak_prominence = 0.03;
+            float peak_prominence = 0.01;
             if(dif1 > peak_prominence && dif2 > peak_prominence) {
                 steps++;
             }
@@ -277,14 +448,19 @@
         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, %d\r\n", sample_num, pressure, avg, bpm); 
-        pc.printf("%d, %lu, %f, %d\r\n", sample_num, pressure, avg, bpm); 
         sample_num++;
         one = !one;
         // Sampling rate of ~200 Hz
-        Thread::wait(50);
+        if(usb_timer.read() >= 30) {
+            //pc.printf("Starting USB Write\r\n");
+            usb_mtx.lock();
+            saveData();
+            usb_mtx.unlock();
+            usb_timer.stop();
+            usb_timer.reset();
+            usb_timer.start();
+        }
+        Thread::wait(200);
     }
-    fclose(fp);
     one = 0;
 }
\ No newline at end of file