Full project folder
Dependencies: GPSLibrary GSM mbed-modifed Storage_Library Temp_Library Wakeup pH_Sensor
Diff: main.cpp
- 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