GroupZ - 05012018 1511

main.cpp

Committer:
mslade
Date:
2018-01-09
Revision:
1:84581acd1333
Parent:
0:1c898341428b

File content as of revision 1:84581acd1333:

#include "mbed.h"
#include "lcdClass.h"
#include "math.h"
#include "SDBlockDevice.h"
#include "FATFileSystem.h"
#include "EthernetInterface.h"
#include "TCPServer.h"
#include "TCPSocket.h"
#include "BMP280.h"
#include <string>
#include <iostream>
#define HTTP_STATUS_LINE "HTTP/1.0 200 OK"
#define HTTP_HEADER_FIELDS "Content-Type: text/html; charset=utf-8"
#define HTTP_RESPONSE HTTP_STATUS_LINE "\r\n"   \
                      HTTP_HEADER_FIELDS "\r\n" \
                      "\r\n"                    \
                      HTTP_MESSAGE_BODY "\r\n"

#define IP        "10.0.0.10"
#define NETMASK   "255.0.0.0"
#define GATEWAY   "10.0.0.1"
//********************Variables and Initialisations****************************************//
Serial myserial(USBTX,USBRX); lcdClass mylcd(D9,D8,D7,D6,D5,D4); DigitalOut leds(D11);
InterruptIn SWi1(D1); InterruptIn SWi2(D0); InterruptIn SWi3(D2); AnalogIn ldrin(A0); 
int SW1 = 0; int SW2 = 0; int SW3 = 0; int record = 0; int serialmode = 0; int pcinput = 0;
int lcdmode = 2; int datemode = 1; int y = 2015; int mon = 1; int d = 1; int h = 0; int minu = 0;
Thread thread1, thread2, thread3, thread4, thread5, thread6; int serialcheck = 0; int samplerate = 1000; 
Semaphore mysem(10);  char ldrString[10]; char tempString[10]; char presString[10]; BMP280 BMP(D14, D15);
string database[5][120]; bool togPress = false; bool debugmode = false; bool data120 = false; bool switchactive = false;
struct tm T; bool mainset = false; int SetDateTime(int year, int month, int day, int hour, int min);
bool Pressed, Pressed1, yearPress, monPress, dayPress, hourPress, minPress = false; InterruptIn  onBoardSwitch(USER_BUTTON);
bool EditTimeParam = false; int TimeParam = 0; char Row1[32]; char Row2[32]; 
SDBlockDevice sd(PB_5, D12, D13, D10); FATFileSystem fs("sd", &sd); //set up SD
void serialmenu(); void ratelimiter(); void clockz(); void showrecord();  
//******************Variables and Initialisations*****************************************//

void sensors(void const *name) {
      //This function is used to sample the sensors, control the serial menu and update the 2D array
      while(true) {
        mysem.wait();
        Thread::wait(samplerate); //Set thread wait to the samplerate (default 1000ms)
        if (debugmode) {leds = 1;} //Turn on white LED
        time_t timer = time(NULL); //Set time to 0
        strftime(Row1, 32, "%H:%M:%S", localtime(&timer));//Format Time as string
        strftime(Row2, 32, "%d/%m/%Y", localtime(&timer));  //Format Date as string
        float ldr = floor(ldrin*30000)/100;  //Set ldr to ldr value to 2 decimal points
        float temp = BMP.getTemperature();   //Set temp to the BMP temperature
        float presh = BMP.getPressure() ;    //Set presh to the BMP pressure
        sprintf(ldrString , "%2.2f", ldr);   //Format ldr as string
        sprintf(tempString, "%2.2f", temp);  //Format temp as string
        sprintf(presString, "%3.2f", presh); //Format pressure as string
        
        //Case statment for mode set by serial
        //0: Main, 1: live data, 2: show data, 3: delete data, 4: set samplerate, 5: set Time/date, 6: toggle debug, 7: show IP
        if (serialmode == 0 && mainset == false) {serialmenu(); mainset = true;}
        if (serialmode == 1 && mainset == false) {mainset = true; myserial.printf("ldr=%s temp=%s pres=%s \r\n", ldrString, tempString, presString); }
        if (serialmode == 2 && mainset == false) {showrecord(); mainset = true; }
        if (serialmode == 3 && mainset == false) {mainset = true; myserial.printf("Deleted all temp sensor data \r\n"); memset(database,0,sizeof(database));}
        if (serialmode == 4 && mainset == false) {ratelimiter(); mainset = true;}
        if (serialmode == 5 && mainset == false) {mainset = true; myserial.printf("Set Time/Date \r\n");}
        if (serialmode == 6 && mainset == false) {mainset = true; debugmode = !debugmode; if (debugmode) {myserial.printf("Debug on \r\n");} else {myserial.printf("Debug off \r\n");} }
        if (serialmode == 7 && mainset == false) {mainset = true; myserial.printf("IP: %s \r\n", IP);}
        
        //Update 2D array with data
        database[0][record] = ldrString;   //Column 1: ldr data
        database[1][record] = tempString;  //Column 2: temp data
        database[2][record] = presString; //Column 3: pressure data
        database[3][record] = Row1;
        database[4][record] = Row2;
        if (debugmode) {leds = 0;} //Turn off white led
        if (record > 119) {record = 0; data120 = true; } else { record += 1;} //Increment record counter
        mysem.release(); //Release thread.
    }
}

void showrecord(){
    //This function is used to display the last 120 data entries on serial
    
    //Don't display the data until there is 120 data entries. 
    if (data120 == false) {myserial.printf("Not enough records. Please wait %d seconds. \r\n", 120-record); serialmode = 0; mainset = false;}
    else {     
        for(int i=record; i < 120; i++) {  //Displays all the recent values from current record to 120 (FIFO buffer)
            string response;
            response  = "Time:" ; response += database[3][i]; //Add time
            response += " Date:"; response += database[4][i]; //Add date
            response += " LDR:" ; response += database[0][i]; //Add LDR value
            response += " Temp:"; response += database[1][i]; //Add Temp value
            response += " Pres:"; response += database[2][i]; //Add pressure value
            response += "\r\n"; //Line return
            myserial.printf(response.c_str()); //Display Time, LDR, Temp, Press
        }
        for(int i = 0; i < record; i++){ //displays all the recent values from 0 to record (FIFO buffer)
            string response;
            response  = "Time:" ; response += database[3][i]; //Add time
            response += " Date:"; response += database[4][i]; //Add date
            response += " LDR:" ; response += database[0][i]; //Add LDR value
            response += " Temp:"; response += database[1][i]; //Add Temp value
            response += " Pres:"; response += database[2][i]; //Add pressure value
            response += "\r\n"; //Line return
            myserial.printf(response.c_str()); //Display Time, LDR, Temp, Press }
        }
    }
}
void LCDupdate (void const *name){
    //The purpose of this function is to update the LCD screen
    while (true) {
        mysem.wait();
        Thread::wait(50); //Wait 50ms
        if (SW3 == 1) { if (togPress == false) { if (lcdmode == 2) {lcdmode = 1;} else {lcdmode += 1;} togPress = true; mylcd.cls(); }
            } else { togPress = false;} //Toggle mode
        if (lcdmode == 1) { clockz(); } //Display time
        if (lcdmode == 2) {             //Display live sensor data
            mylcd.locate(9,1); mylcd.printf("L:%s ", ldrString);  //Display LDR value
            mylcd.locate(0,1); mylcd.printf("T:%s ", tempString); //Display temp value
            mylcd.locate(4,0); mylcd.printf("P:%s ", presString); //Display pressure value
        }
        mysem.release(); //Release thread
    }
}
    

void enet(void const *name)
//The purpose of this function is to set up and transmit data via ethernet
{
    EthernetInterface eth; //Configure an ethernet connection
    eth.set_network(IP, NETMASK, GATEWAY); //Configure network
    eth.connect(); //Connect ethernet
    TCPServer srv; //Socket for communication
    SocketAddress clt_addr; //Address of incoming connection
    srv.open(&eth); // Open the server on ethernet stack
    srv.bind(eth.get_ip_address(), 80); // Bind the HTTP port (TCP 80) to the server 
    srv.listen(5);  // Can handle 5 simultaneous connections 
    while (true) {
        mysem.wait();
        using namespace std;
        TCPSocket clt_sock;
        srv.accept(&clt_sock, &clt_addr);
        
        //This code sends the HTML website to the computer.
        string response;
        response =  "<html> \r\n ";
        response += "<meta http-equiv=\"refresh\" content=\"1; url=http://10.0.0.10\">";
        response += "\r\n <h1 style=\"color:black; font-size: 200%; position: fixed; top:17.5%; left:38%;\"> ";
        response += Row1;
        response += "</h1> \r\n <h1 style=\"color:black; font-size: 200%; position: fixed; top:17.5%; left:55.5%;\">";
        response += Row2;
        response += "</h1> \r\n <h1 style=\"color:black; font-size: 400%; position: fixed; top:30%; left:46%;\">";
        response += tempString;
        response += "</h1> \r\n <h1 style=\"color:black; font-size: 400%; position: fixed; top:51%; left:46%;\">";
        response += ldrString;
        response += "</h1> \r\n <h1 style=\"color:black; font-size: 400%; position: fixed; top:72%; left:46%;\">";
        response += presString;
        response += "</h1> \r\n <body style=\"background-image:url(https://image.ibb.co/nyTj9w/pic2.png); background-size: 100% 100%;\"></body> ";
        response += "\r\n </html>";
        clt_sock.send(response.c_str(), response.size()+1);
        Thread::wait(samplerate); //Thread wait 10ms
        mysem.release();  //Release thread
    }
}
void serialin(void const *name){
    //The purpose of this function is to handle the serial communication
    
    while (true) {
        mysem.wait();
        Thread::wait(1000); //Thread wait 1000ms
        myserial.scanf("%d", &serialcheck); //Wait for command from serial
        if (serialmode != 5 && serialcheck == 9) {serialmode = 0; mainset = false;} //if command is 9 return to main menu
        else if (serialmode == 0) {serialmode = serialcheck; mainset = false; myserial.printf("press 9 to return to main menu\r\n");}
        else if (serialmode == 4) { //if the mode is set samplerate:
            if (serialcheck == 1) {samplerate = 100; }  //Set samplerate to 0.1s
            if (serialcheck == 2) {samplerate = 1000;}  //Set samplerate to 1s
            if (serialcheck == 3) {samplerate = 5000;}  //Set samplerate to 5s
            if (serialcheck == 4) {samplerate = 10000;} //Set samplerate to 10s
            if (serialcheck == 5) {samplerate = 15000;} //Set samplerate to 15s
            if (serialcheck == 6) {samplerate = 30000;} //Set samplerate to 30s
            if (serialcheck == 7) {samplerate = 60000;} //Set samplerate to 60s
            if (serialcheck < 8 && serialcheck > 0) {myserial.printf("Sample rate set to %dms \r\n", samplerate); serialmode = 0; mainset = false;}
        }
        if (serialmode == 5) { //if the mode is set date/time
                 if (mainset == false) {datemode = 1; mainset = true; } 
                 if (datemode == 1) { myserial.printf(" Set year: "); datemode++;} //set year
            else if (datemode == 2) { myserial.printf("%d \r\n Set month: ",serialcheck); y = serialcheck; datemode++;} //set month
            else if (datemode == 3) { myserial.printf("%d \r\n Set day: ",serialcheck); mon = serialcheck; datemode++;} //set day
            else if (datemode == 4) { myserial.printf("%d \r\n Set hour: ",serialcheck); d = serialcheck; datemode++;} //set hour
            else if (datemode == 5) { myserial.printf("%d \r\n Set minute: ", serialcheck); h = serialcheck; datemode++;} //set minute
            else {myserial.printf("%d \r\nDate set to: %d/%d/%d %d:%d \r\n", serialcheck,d, mon, y, h, serialcheck); minu = serialcheck; serialmode = 0;set_time(SetDateTime(y, mon, d, h, minu)); mainset = false;}
        }
        mysem.release();
    }
}
    
void interrupts(void const *name){
    //The purpose of this function is to wait for Interrupt-In's
    while (true) {
        mysem.wait(); 
        Thread::wait(40); //Thread wait 40ms
        SW1 = SWi1;  //Set SW1
        SW2 = SWi2;  //Set SW2
        SW3 = SWi3;  //Set SW3
        mysem.release(); //Release thread
    }
}
void SDcard(void const *name){
    while (true) {
        mysem.wait();
        Thread::wait(samplerate);
        FILE* fp = fopen("/sd/test.txt","a");   //edit test.txt file
        string response;
        response = Row1; response += ",";           //Add time
        response += Row2; response += ",";          //Add date
        response += ldrString; response += ",";     //Add ldr value
        response += tempString; response += ",";    //Add temp value
        response += presString; response += "\r\n"; //Add pressure value
        fprintf(fp, response.c_str());              //Print response
        if (onBoardSwitch == 1) {     //if switch is pressed start eject
            switchactive = true;
        }
        if (switchactive == true) {
            sd.deinit();    //eject SD
        }
        fclose(fp); //Close test.txt
        mysem.release();
    }
}
int SetDateTime(int year, int month, int day, int hour, int min)
{  //The purpose of this function is to set the date and time
    T.tm_year = year - 1900; //Set year
    T.tm_mon = month - 1;    //Set month
    T.tm_mday = day;         //Set day
    T.tm_hour = hour;        //Set hour
    T.tm_min = minu;         //Set minute
    T.tm_sec = 0;            //Set second
    return (mktime(&T));
}

void clockz() {
        //The purpose of this function is to set the time on the LCD
        if ((SW1 == 1) && (SW2 == 1)) { //If both buttons pressed
            if (Pressed == false) { //if first time:
                EditTimeParam = not EditTimeParam; //Toggle mode
                if (EditTimeParam == false) { set_time(SetDateTime(y, mon, d, h, minu)); } //Set Datetime
                mylcd.cls(); //Clear LCD screen
                Pressed = true;
            }
        }
        else{ Pressed = false; }
        if (EditTimeParam == true) {
            if (SW1 == 1) { //if switch is pressed
                if (Pressed1 == false) {
                    TimeParam++; //increment TimeParam for switch case
                    mylcd.cls(); //Clear LCD screen
                    Pressed1 = true;
                    if (TimeParam > 4) {TimeParam = 0;}
                }
            }
            else {
                Pressed1 = false;
            }
            switch (TimeParam) {
                case 0: //Year
                    if (SW2 == 1) { if (yearPress == false) { y++; yearPress = true; } } else { yearPress = false; } //Increment year
                    if (y > 2030) { y = 2015; mylcd.cls(); } //If upper limit hit, reset to lower limit
                    mylcd.locate(0, 0); mylcd.printf("Year: %d\n", y); //Display year
                    break;
                case 1: //Month
                    if (SW2 == 1) { if (monPress == false) { mon++; monPress = true; } } else { monPress = false; } //Increment month
                    if (mon > 12) { mon = 1; mylcd.cls(); } //if upper limit hit, reset to lower limit
                    mylcd.locate(0, 0); mylcd.printf("Month: %d\n", mon); //Display month
                    break;
                case 2: //Day
                    if (SW2 == 1) { if (dayPress == false) { d++; dayPress = true; } } else { dayPress = false; } //Increment day
                    if ((mon == (4 || 6 || 9 || 11)) && (d > 30)) { d = 1; mylcd.cls(); } else if ((mon == 2) && (d > 28)) { d = 0; mylcd.cls(); } else if (d > 31) { d = 0; mylcd.cls(); }
                    mylcd.locate(0, 0); mylcd.printf("Day: %d\n", d); //Display day
                    break;
                case 3: //Hour
                    if (SW2 == 1) { if (hourPress == false) { h++; hourPress = true; } } else { hourPress = false; } //Increment hour
                    if (h > 23) { h = 0; mylcd.cls(); } //if upper limit hit, reset to lower limit
                    mylcd.locate(0, 0); mylcd.printf("Hour: %d\n", h); //Display hour
                    break;
                case 4: //Minute
                    if (SW2 == 1) { if (minPress == false) { minu++; minPress = true; } } else { minPress = false; } //Increment minute
                    if (minu > 59) { minu = 0; mylcd.cls(); } //if upper limit hit, reset to lower limit
                    mylcd.locate(0, 0); mylcd.printf("Minute: %d\n", minu); //Display minute
                    break;
            }
        }
        else {
            mylcd.locate(0, 0); mylcd.printf("%s", Row1); //Print Time on LCD, row 1
            mylcd.locate(0, 1); mylcd.printf("%s", Row2); //Print Date on LCD, row 2
        }
}

void serialmenu() {            
    //The purpose of this function is to print the serial menu
    myserial.printf("Welcome to Group Z ELEC351 Coursework. Press 9 to start. \r\n");
    myserial.printf("Please select (type in the number) an option: \r\n");
    myserial.printf("1. Show live sensor data \r\n");
    myserial.printf("2. Show old sensor data \r\n");
    myserial.printf("3. delete all sensor data \r\n");
    myserial.printf("4. Select sampling rate \r\n");
    myserial.printf("5. Set time/date \r\n");
    myserial.printf("6. Toggle debug \r\n");
    myserial.printf("7. Show IP address \r\n");
}
void ratelimiter() {       
    //The purpose of this function is to print the samplerate options to the serial     
    myserial.printf("Please select (type in the number) a sample rate: \r\n");
    myserial.printf("1. 0.1s \r\n");
    myserial.printf("2. 1s \r\n");
    myserial.printf("3. 5s \r\n");
    myserial.printf("4. 10s \r\n");
    myserial.printf("5. 15s \r\n");
    myserial.printf("6. 30s \r\n");
    myserial.printf("7. 60s \r\n");
}
int main(){
    //The purpose of this function is to be the main code to run the threads.
    myserial.baud(115200); //Set serial speed to 115200
    mylcd.cls();           //Clear LCD
    thread1.start(callback(enet,    (void *)   "Thread1\r\n"));   // Start Ethernet thread
    thread2.start(callback(sensors, (void *)   "Thread2\r\n"));   // Start sensors thread
    thread3.start(callback(serialin,(void *)   "Thread3\r\n"));   // Start Serialin thread
    thread4.start(callback(interrupts,(void *) "Thread4\r\n"));   // Start interrupts thread
    thread5.start(callback(LCDupdate,(void *)  "Thread5\r\n"));   // Start LCDupdate thread
    thread6.start(callback(SDcard,(void *)     "Thread6\r\n"));   // Start SDcard thread
    set_time(SetDateTime(y, mon, d, h, minu));  //Set DateTime
}