Full project folder

Dependencies:   GPSLibrary GSM mbed-modifed Storage_Library Temp_Library Wakeup pH_Sensor

Revision:
14:196ed16cd62b
Parent:
13:52fba498c00d
Child:
15:5f366ddcce18
--- a/main.cpp	Wed Dec 02 06:29:20 2015 +0000
+++ b/main.cpp	Sat Dec 05 07:36:48 2015 +0000
@@ -1,438 +1,90 @@
-#include "Adafruit_FONA.h"
+#include "GSM_Wrapper.h"
 #include "WakeUp.h"
-#include "mbed.h"
-#include "MBed_Adafruit_GPS.h"
+#include "main.h"
+#include "pH_Sensor.h"
+#include "storage.h"
+#include "GPS_Wrapper.h"
+#include "Temp_Sensor.h"
 #include <string>
 
-// Cellular communication constants
-#define FONA_TX D8
-#define FONA_RX D2
-#define FONA_RST D3
-#define FONA_RI D4
-#define FONA_KEY D5
-
-// Global Positioning System constants
-#define GPS_TX D6
-#define GPS_RX PB_11
-#define GPS_EN D7
-
-// pH sensor constants
-#define PH_TX PC_10
-#define PH_RX PC_11
-
-#define TMP_ANALOG A0
-#define ADC_CONVERSION 3.3/5.0
-AnalogIn temperature(TMP_ANALOG);
-
-#define READINGSIZE sizeof(struct reading)
-#define URL "http://requestb.in/1ihfre81"
-
-// Cellular communication global variables
-Adafruit_FONA fona(FONA_TX, FONA_RX, FONA_RST, FONA_RI);
+struct reading lastReadingBuffer;
+pH_Sensor pH;
+GPS_Sensor GPS;
+GSM_Sensor GSM;
+Temp_Sensor Temp;
+Storage storage;
 Serial pcSerial(USBTX, USBRX);
-DigitalOut key(FONA_KEY);
-
-struct reading {
-    float temperature;
-    float pH;
-    float latitude;     //Signed positive if N, negative if S
-    float longitude;    //Signed positive if E, negative if W
-    uint8_t day;
-    uint8_t month;
-    uint8_t year;
-    uint8_t hour;
-    uint8_t minutes;
-};
-
-// GPS global variables
-char c; //when read via Adafruit_GPS::read(), the class returns single character stored here
-Timer refresh_Timer; //sets up a timer for use in loop; how often do we print GPS info?
-const int refresh_Time = 2000; //refresh time in ms
-Serial gps_Serial(GPS_TX, GPS_RX); // Serial object for GPS
-Adafruit_GPS myGPS(&gps_Serial);
-DigitalOut gpsEN(GPS_EN);
-
-// pH sensor global variables
-Serial ph_Serial (PH_TX, PH_RX);
-string sensorstring = "";
-bool input_stringcomplete = false;
-bool sensor_stringcomplete = false;
-float pH;
-
-struct reading lastReadingBuffer;
 
 void setupPCSerial() {
+    wait(2);
     pcSerial.baud(115200);
     pcSerial.printf("\n\n PC Serial connection established at 115200 baud.\n");
-}
-
-void disableContinuousMode() {
-    printf("pH sensor will NOT run in continous mode.\n");
-    if(ph_Serial.writeable() <= 0) printf("Not writable\n");
-    // disable continuous mode
-    ph_Serial.printf("C,0");
-    ph_Serial.printf("%c", '\r');
-    printf("Waiting five seconds... ");
-    wait(5);
-}
-
-void setupPH() {
-    ph_Serial.baud(9600);
-    disableContinuousMode();
-}
-
-void setupGPS() {
-    gpsEN.write(1);
-    myGPS.begin(9600);
-    myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //these commands are defined in MBed_Adafruit_GPS.h; a link is provided there for command creation
-    myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
-    myGPS.sendCommand(PGCMD_ANTENNA);
-    wait(1);
-    refresh_Timer.start();  //starts the clock on the timer
-    printf("setupGPS seems to be fine\n");
+    wait(2);
 }
 
 void setup() {
-    wait(2);
     setupPCSerial();
-    wait(2);
-    printf("\n=====\nSetup in Full Project\n");
-    wait(2);
-    setupGPS();
-    wait(2);
-    setupPH();
-    wait(2);
+    GPS.setup();
+    pH.setup();
     wait(20);
+    GSM.changePowerState();
 } 
 
-// Send default message to pH sensor, asking for data.
-void pHRequest() {
-    printf("Sending pH request...\n");
-    if(ph_Serial.writeable() <= 0) printf("Not writable\n");
-    // request one reading
-    ph_Serial.printf("R");
-    ph_Serial.printf("%c", '\r');
-}
 
-void pHRead() {
-    pHRequest();
-    printf("Reading pH information.\n");
-    if (ph_Serial.readable() > 0) {                     //if we see that the Atlas Scientific product has sent a character.
-        printf("Receiving sensor string... [");
-        char inchar;
-        while((inchar = (char)ph_Serial.getc()) != '\r') {
-            sensorstring += inchar;
-            printf("%c", inchar);
-        }
-        printf("] ...sensor string received!\n");
-        sensor_stringcomplete = true;
-        printf(sensorstring.c_str());
-        // +1 is to get rid of control character
-        pH = atof(sensorstring.c_str()+1);                      //convert the string to a floating point number so it can be evaluated by the Arduino
-
-        if (pH >= 7.0) {                                  //if the pH is greater than or equal to 7.0
-            printf("high\n");                         //print "high" this is demonstrating that the Arduino is evaluating the pH as a number and not as a string
-        }
-
-        if (pH <= 6.999) {                                //if the pH is less than or equal to 6.999
-            printf("low\n");                          //print "low" this is demonstrating that the Arduino is evaluating the pH as a number and not as a string
-        }
-
-        //ph_Serial.printf("SLEEP");
-        //ph_Serial.printf("%c", '\r');
-
-        sensorstring = "";                                //clear the string:
-        sensor_stringcomplete = false;                    //reset the flag used to tell if we have received a completed string from the Atlas Scientific product
-    } else {
-        printf("pH sensor is not readable\n");
-    }
-}
-
-// n_queries is the number of times we query the GPS. We need something like 23000 characters.
-void GPSRead(int n_queries) {
-    for(int i = 0; i < 60; i++){
-        wait(1);
-        if(myGPS.fix) break;
-    }
-    pcSerial.printf("\n");
-    for (int i = 0; i < n_queries; i++) {
-        c = myGPS.read();   //queries the GPS
-        
-        if (c) { pcSerial.printf("%c", c); } //this line will echo the GPS data if not paused
-        
-        //check if we recieved a new message from GPS, if so, attempt to parse it,
-        if ( myGPS.newNMEAreceived() ) {
-            if ( !myGPS.parse(myGPS.lastNMEA()) ) {
-                continue;   
-            }    
-        }
-        
-        //check if enough time has passed to warrant printing GPS info to screen
-        //note if refresh_Time is too low or pcSerial.baud is too low, GPS data may be lost during printing
-        if (refresh_Timer.read_ms() >= refresh_Time) {
-            refresh_Timer.reset();
-            pcSerial.printf("Time: %d:%d:%d.%u\n", myGPS.hour, myGPS.minute, myGPS.seconds, myGPS.milliseconds);   
-            pcSerial.printf("Date: %d/%d/20%d\n", myGPS.day, myGPS.month, myGPS.year);
-            pcSerial.printf("Fix: %d\n", (int) myGPS.fix);
-            pcSerial.printf("Quality: %d\n", (int) myGPS.fixquality);
-            
-            lastReadingBuffer.hour = myGPS.hour;
-            lastReadingBuffer.minutes = myGPS.minute;
-            lastReadingBuffer.day = myGPS.day;
-            lastReadingBuffer.month = myGPS.month;
-            lastReadingBuffer.year = myGPS.year;
-            lastReadingBuffer.latitude = 0.0;
-            lastReadingBuffer.longitude = 0.0;
-            if (myGPS.fix) {
-                float mylatitude = myGPS.latitude;
-                if(myGPS.lat == 'S')
-                    mylatitude *= -1;
-                float mylongitude = myGPS.longitude;
-                if(myGPS.lon == 'W')
-                    mylongitude *= -1;
-                lastReadingBuffer.latitude = mylatitude;
-                lastReadingBuffer.longitude = mylongitude;
-                pcSerial.printf("Location: %5.2f%c, %5.2f%c\n", myGPS.latitude, myGPS.lat, myGPS.longitude, myGPS.lon);
-                pcSerial.printf("Speed: %5.2f knots\n", myGPS.speed);
-                pcSerial.printf("Angle: %5.2f\n", myGPS.angle);
-                pcSerial.printf("Altitude: %5.2f\n", myGPS.altitude);
-                pcSerial.printf("Satellites: %d\n", myGPS.satellites);
-            }
-        }
-    }
-    pcSerial.printf("\n");
-}
-
-void changeGSMPowerState()
+void enterSleep(int sec)
 {
-    key.write(1);
+    GPS.turnOff();
     wait(2);
-    key.write(0);
-    wait(2);
-    key.write(1);
+    WakeUp::set(sec);
+    deepsleep();
+    WakeUp::resetADC();
+    GPS.turnOn();
     wait(2);
 }
 
-void setupGSM()
-{
-    printf("Starting FONA\n");
-    if(!fona.begin(9600)){
-        changeGSMPowerState();
-        printf("Cannot find FONA\n");
-        wait(2);
-    }
-    if(!fona.begin(9600)){
-        changeGSMPowerState(); 
-        return;
-    }
-    printf("After begin\n");
-    fona.setGPRSNetworkSettings("pwg", "", "");
-    printf("After set setting\n");
-    bool enable = false;
-    int i = 0;
-    while(enable != true) {
-        if(i > 5) break;
-        i++;
-        fona.enableGPRS(true);
-        fona.enableGPRS(false);
-        enable = fona.enableGPRS(true);
-    }
-    printf("After enable\n");
-}
-
-//Found this online and it claims that it resets ADC to work after deepsleep \_O_/
-void resetADC()
+void sendData(int& nreadings, bool& toSend)
 {
-    // Enable the HSI (to clock the ADC)
-    RCC_OscInitTypeDef RCC_OscInitStruct;
-    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
-    RCC_OscInitStruct.HSIState       = RCC_HSI_ON;
-    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE;
-    HAL_RCC_OscConfig(&RCC_OscInitStruct);  
-}
-
-void enterSleep(int sec)
-{
-    gpsEN.write(0);
-    wait(2);
-    WakeUp::set(sec);
-    deepsleep();
-    resetADC();
-    gpsEN.write(1);
-    wait(2);
-}
-
-bool sendDataOverHTTP(char* url, uint8_t* data, int dlength)
-{
-    uint16_t statuscode;
-    int16_t length;
-    if (!fona.HTTP_POST_start(url, "text/plain", data, dlength, &statuscode, (uint16_t *)&length)) {
-        pcSerial.printf("Failed!\r\n");
-        return false;
+    struct reading* data = new struct reading[nreadings];
+    storage.read((uint8_t*) data);
+    int sizeofentry = 8+8+10+10+5*sizeof(int)+8+1;
+    size_t bufsize = sizeofentry*nreadings+1;
+    char buffer[bufsize];
+    for(int i = 0; i < nreadings; i++) {
+        int n = sprintf(buffer+sizeofentry*i, "%8f %8f %10f %10f %d %d %d %d %d\t", data[i].temperature, data[i].pH, data[i].latitude, data[i].longitude, data[i].day,
+                        data[i].month, data[i].year, data[i].hour, data[i].minutes);
     }
-    while (length > 0) {
-        while (fona.readable()) {
-            char c = fona.getc();
-            pcSerial.putc(c);
-            length--;
-            if (! length) break;
-        }
+    if(GSM.send((uint8_t*) buffer, bufsize)) {
+        toSend = false;
+        nreadings = 0;
+        storage.reset();
     }
-    pcSerial.printf("\r\n****\r\n");
-    fona.HTTP_POST_end();
-    return true;
+    delete[] data;
 }
 
-//define where the EEPROM begins
-#define stadr 0x08080000
-
-//Our current offset in the EEPROM
-int offset = 0;
-int roffset = 0;
-
-//This function writes a byte of data to the EEPROM at the appropriate location.
-//This is called by my writeEEPROMbytes.
-//Use this if you want to write a single byte.
-HAL_StatusTypeDef writeEEPROMByte(uint8_t data)
- {
-    HAL_StatusTypeDef  status;
-    int address = offset + stadr;
-    offset++;
-    HAL_FLASHEx_DATAEEPROM_Unlock();  //Unprotect the EEPROM to allow writing
-    status = HAL_FLASHEx_DATAEEPROM_Program(TYPEPROGRAMDATA_BYTE, address, data);
-    HAL_FLASHEx_DATAEEPROM_Lock();  // Reprotect the EEPROM
-    return status;
-}
-
-//This function takes an array of bytes and its size and writes them to the EEPROM
-//Use this if you want to write a lot of bytes.
-void writeEEPROMbytes(uint8_t* data, uint8_t size)
+void read()
 {
-    for(int i = 0; i < size; i++)
-    {
-        writeEEPROMByte(data[i]);
-    }
-}
-
-//This function reads a byte of data from the EEPROM at the offset passed in.
-//This is called by my getEEPROM function
-uint8_t readEEPROMByte(uint32_t off) {
-    uint8_t tmp = 0;
-    off = off + stadr;
-    tmp = *(__IO uint32_t*)off;
-    
-    return tmp;
-}
-
-//Call this function when you have sent all the data in the EEPROM through GSM
-//It just resets the offset to 0 so we start writing from the start.
-void resetEEPROM()
-{
-    offset = 0;
+    printf("~~~~~[pH]~~~~~\n");
+    lastReadingBuffer.pH = pH.read();
+    printf("~~~~~[Temperature]~~~~~\n");
+    lastReadingBuffer.temperature = Temp.read();
+    printf("~~~~~[GPS]~~~~~\n");
+    GPS.read(lastReadingBuffer);
+    storage.write((uint8_t *) &lastReadingBuffer, READINGSIZE);
+    GSM.changePowerState();
 }
 
-//This takes an array of bytes an fills it with our entire EEPROM
-//Call this function when you want to send the data over GSM
-void getEEPROM(uint8_t *ptr)
-{
-    int nbytes = offset;
-    printf("The number of bytes in the EEPROM is %d\n", nbytes);
-    for(int i = 0; i < nbytes; i++)
-    {
-        ptr[i] = readEEPROMByte(i);
-    }
-    //printf("WARNING DEBUG CODE BREAKS THINGS");
-    //roffset += nbytes;
-    return;
-}
-
-//function to get both the 
-float AD22100K_AI_value_to_Celsius() {                                               // Convert Analog-input value to temperature
-  //1023 is to scale it up to the arduino read values.
-  float voltage = (int)((temperature.read() * ADC_CONVERSION) * 1023);
-   
-  float temperatureValue = (voltage * 0.217226044) - 61.1111111; // conversion factor simplified.
-  pcSerial.printf("AI_Val: %f\n", temperatureValue);
-  lastReadingBuffer.temperature = temperatureValue;
-  return temperatureValue;       // 22.5 mV / °C; Ratiometric measurement, conversion valid for 5 V!
-}
-
-bool sendDataToURL(uint8_t* data, int size)
-{
-    setupGSM();
-    printf("Setup GSM\n");
-    bool res = sendDataOverHTTP(URL, data, size);
-    if(!res) res = sendDataOverHTTP(URL, data, size);
-    printf("After sent data\n");   
-    return res;
-}
-
-// In the final version of this code:
-// We wake up ten times an hour to record information from our sensors.
-// but we wait until we have accumulated 240 measurements before we 
-// start attempting to send away all our data. Once we successfully send 
-// our information, we clear our memory and begin from the start.
-
-// TODO: Sleep mode. How does the Nucleo enter / exit sleep mode? 
-// How do we power on / power off the other devices:
-//  - GPS?
-//    use the EN pin on the GPS
-//  - pH sensor?
-//    There's a sleep command
-//  - Temperature sensor?
-//    Should automatically switch on / off when the nucleo enters deep sleep mode.
-//  - GSM?
-//    The enable pin is modified by changeGSMPowerStat();
-// TODO: Web communication
-//  - write server
-
 int main()
 {
     setup();
-    changeGSMPowerState();
     int nreadings = 0;
     bool toSend = false;
     while (true) {
-        printf("~~~~~[pH]~~~~~\n");
-        pHRead();
-        lastReadingBuffer.pH = pH;
-        wait(1);
-        printf("~~~~~[GPS]~~~~~\n");
-        GPSRead(300000);
-        wait(1);
-        printf("~~~~~[Temperature]~~~~~\n");
-        AD22100K_AI_value_to_Celsius();
-        wait(1);
-        writeEEPROMbytes((uint8_t *) &lastReadingBuffer, READINGSIZE);
+        read();
         nreadings++;
-        changeGSMPowerState();
-        if(nreadings == 5)
-            toSend = true;
-        if(toSend) {
-            struct reading* data = new struct reading[nreadings];
-            getEEPROM((uint8_t*) data);
-            int sizeofentry = 8+8+10+10+5*sizeof(int)+8+1;
-            char buffer[(sizeofentry*nreadings) + 1];
-            for(int i = 0; i < nreadings; i++)
-            {
-                int n = sprintf(buffer+sizeofentry*i, "%8f %8f %10f %10f %d %d %d %d %d\t", data[i].temperature, data[i].pH, data[i].latitude, data[i].longitude, data[i].day, 
-                                              data[i].month, data[i].year, data[i].hour, data[i].minutes);
-                printf("%s\n", buffer);
-                printf("%d\n", n);
-                printf("%d\n", (sizeof(buffer)));
-                printf("%d\n", data[i].minutes);
-            }
-            printf("HERE\n");
-            bool res = sendDataToURL((uint8_t*) buffer, sizeof(buffer));   
-            if(res) {
-                toSend = false;
-                nreadings = 0;
-                resetEEPROM();
-            }
-            delete[] data;
-        }
-        changeGSMPowerState();
+        if(nreadings == N_READINGS_PER_SEND) toSend = true;
+        if(toSend) sendData(nreadings, toSend);
+        GSM.changePowerState();
         wait(2);
-        enterSleep(60);
+        enterSleep(N_SECONDS_SLEEP);
     }
 }
\ No newline at end of file