#include <Adafruit_BMP085_U.h>
#include <Adafruit_GPS.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_10DOF.h>
#include <Adafruit_HTU21DF.h>
#include <Wire.h>
#define mySerial Serial1
#define GPSECHO  true


int x;  // read value
int adcloopctr;
unsigned long values[200];
const int eventtrigger = 49;
boolean eventhappened = false; 
int sampledepth = 10;
int printctr = 0;
int readoutctr;
int eventcounter =0;

const int timeresetpin = 50;

Adafruit_10DOF                dof   = Adafruit_10DOF();
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(30301);
Adafruit_LSM303_Mag_Unified   mag   = Adafruit_LSM303_Mag_Unified(30302);
Adafruit_BMP085_Unified       bmp   = Adafruit_BMP085_Unified(18001);
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
Adafruit_GPS GPS(&mySerial);

char gpstext[ ] = "";
String gpstalk;
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
boolean timereset = false; //has an event been detected?
String lastgpsread;
int deviceid = random(1, 10000);
float temperature;
double temperatureh=0;
double humidity = 0;
double baroaltitude = 0;
double accelx = 0;
double accely = 0;
double accelz = 0;
double magx = 0;
double magy = 0;
double magz = 0;

long exacttime =0;
int uptime = 0;

float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;


void setup()
{
  initSensors();
  GPS.begin(9600);
  mySerial.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  delay(1000);
  Serial.println("GPS online");
  inputString.reserve(200);

  pinMode(timeresetpin, INPUT);
  attachInterrupt(timeresetpin, timeset, RISING);


  
//  analogReference(INTERNAL);
  pinMode(eventtrigger, INPUT);
attachInterrupt(eventtrigger, monkey, FALLING);
  Serial.begin(115200);                           // initialize the serial port:
  REG_ADC_MR = 0x10380180;                       // change from 10380200 to 10380180, 1 is the PREESCALER and 8 means FREERUN
  ADC -> ADC_CHER = 0x03; // enable ADC on pin A6 and A7
eventhappened = false;
adcloopctr=0;
Serial.println("Alive");
}

void loop() {

  exacttime++;

  //unsigned long t = micros();                    // init time an elapsed time, in micro seconds
  
  //for(i = 0; i < 1000; i++) {
    
    // instrucction to measure
    while((ADC->ADC_ISR & 0x3)==0);             // wait for conversion
    values[adcloopctr+100] = ADC->ADC_CDR[0];                         // read value A0
    values[adcloopctr] = ADC->ADC_CDR[1];                         // read value A0
    
if (stringComplete) {
    lastgpsread = inputString;
    lastgpsread.trim();
    //debug printout
    //Serial.println(inputString); 
    // clear the string:
    inputString = "";
    stringComplete = false;
  }

  if (timereset) {

  Serial.println("Timereset Detection on pin 50");
    Serial.println(exacttime);
  exacttime = 0;
  timereset= false;
  }
  
  
if (eventhappened){
    //Serial.println("Event");
    //for (int printctr = adcloopctr+1; printctr+1 < sampledepth+adcloopctr; printctr++) {
    //Serial.print(printctr);
    //Serial.print(", ");
    //if (printctr > sampledepth){
    //Serial.println(values[(printctr)]);
    //Serial.println(values[(printctr)]);
    //}
    //printctr = ++printctr % sampledepth;
readoutctr=10;
  sensorreadout();
eventcounter++;
    printdatajson();
    eventhappened = false;
    //delay(200);
  }
adcloopctr++;
  if (adcloopctr==sampledepth) {
adcloopctr=0;


}

 
}

void serialEvent1() {
  while (Serial1.available()) {
    // get the new byte:
    char inChar = (char)Serial1.read(); 
    // add it to the inputString:
    if (inChar != char(10))
    {
      inputString += inChar;
    }
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    } 
  }
}

void serialEventRun(void)
{
  if (Serial1.available()) 
          serialEvent1();
}


void initSensors()
{
  if (!accel.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println(F("Ooops, no LSM303 detected ... Check your wiring!"));
    while (1);
  }
  if (!mag.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while (1);
  }
  if (!bmp.begin())
  {
    /* There was a problem detecting the BMP180 ... check your connections */
    Serial.println("Ooops, no BMP180 detected ... Check your wiring!");
    while (1);
  }
  if (!htu.begin()) {
    Serial.println("Couldn't find HTU21DF sensor!");
    while (1);
  }
}


void printdatajson()
{
    //start the data output on in json format
  Serial.print("{ ");
  Serial.print("    \"gps\":");
  Serial.print("      \"");
  Serial.print(lastgpsread);
  Serial.print("\"");
  Serial.print("    ,");
  
  Serial.print("    \"timing\": ");
  Serial.print(exacttime);
  Serial.print(','); 
  
  Serial.print("    \"energy\": {");
  Serial.print("    \"energy1\": [");
  
       for (int firsthalf=adcloopctr+1; firsthalf<sampledepth; firsthalf++)
    {
      //Serial.print(readoutctr);
      //Serial.print(", ");
      Serial.print(values[firsthalf]);
      //Serial.print(", ");
      //Serial.println(values[firsthalf+100]);
      if (readoutctr != 1) Serial.print(", ");
      readoutctr--;
    }
    for (int secondhalf=0; secondhalf<adcloopctr+1; secondhalf++)
    {
      //Serial.print(readoutctr);
      //Serial.print(", ");
      Serial.print(values[secondhalf]);
       if (readoutctr != 1) Serial.print(", ");
      
      //Serial.print(", ");
      //Serial.println(values[secondhalf+100]);
      readoutctr--;
    }

      Serial.print("    ],");
  Serial.print("    \"energy2\": [");
  readoutctr=10;
  
       for (int firsthalf=adcloopctr+1; firsthalf<sampledepth; firsthalf++)
    {
      //Serial.print(readoutctr);
      //Serial.print(", ");
      //Serial.print(values[firsthalf]);
      //Serial.print(", ");
      Serial.print(values[firsthalf+100]);
       if (readoutctr != 1) Serial.print(", ");
      
      //Serial.print(", ");
      
      
      readoutctr--;
    }
    for (int secondhalf=0; secondhalf<adcloopctr+1; secondhalf++)
    {
      //Serial.print(readoutctr);
      //Serial.print(", ");
      //Serial.print(values[secondhalf]);
      //Serial.print(", ");
      Serial.print(values[secondhalf+100]);
       if (readoutctr != 1) Serial.print(", ");
      
      //Serial.print(", ");
      readoutctr--;
    }

      Serial.print("    ]");
      
      Serial.print("    },");
    
 
  Serial.print("    \"altitude\": "); 
  Serial.print(baroaltitude); 
  Serial.print(",");
 
  Serial.print("    \"humidity\": "); 
  Serial.print(humidity);
  Serial.print(",");
 
  Serial.print("    \"gravitationalOrientation\": {"); 
  Serial.print("     \"x\": ");
  Serial.print(accelx);
  Serial.print(",");
  Serial.print("     \"y\": ");
  Serial.print(accely);
  Serial.print(",");
  Serial.print("     \"z\": ");
  Serial.print(accelz);
  Serial.print("    },");  
 
  Serial.print("    \"magneticOrientation\": {"); 
  Serial.print("     \"x\": ");
  Serial.print(magx);
  Serial.print(",");
  Serial.print("     \"y\": ");
  Serial.print(magy);
  Serial.print(",");
  Serial.print("     \"z\": ");
  Serial.print(magz);
  Serial.print("    },");
 
  Serial.print("    \"temperature\": {"); 
  Serial.print("     \"value1\": ");
  Serial.print(temperatureh); //val1 is from the humidity sensor
  Serial.print(",");
  Serial.print("     \"value2\": ");
  Serial.print(temperature);
  Serial.print("    },");
 
  Serial.print("    \"uptime\": "); 
  Serial.print(uptime);
  Serial.print(",");
  
  Serial.print("    \"id\": "); 
  Serial.print(deviceid);
  Serial.println("}");
}


void monkey()
{
  //Serial.println("trigger");
eventhappened = true;
}

void sensorreadout()
{
  sensors_event_t accel_event;
  sensors_event_t mag_event;
  sensors_event_t bmp_event;
  sensors_vec_t   orientation;

  /* Calculate pitch and roll from the raw accelerometer data */
  accel.getEvent(&accel_event);
  if (dof.accelGetOrientation(&accel_event, &orientation))
  {
    accelx = (accel_event.acceleration.x);
    accely = (accel_event.acceleration.y);
    accelz = (accel_event.acceleration.z);

  }

  /* Calculate the heading using the magnetometer */
  mag.getEvent(&mag_event);
  if (dof.magGetOrientation(SENSOR_AXIS_Z, &mag_event, &orientation))
  {
    magx = (mag_event.magnetic.x);
    magy = (mag_event.magnetic.y);
    magz = (mag_event.magnetic.z);
  }

  /* Calculate the altitude using the barometric pressure sensor */
  bmp.getEvent(&bmp_event);
  if (bmp_event.pressure)
  {
    /* Get ambient temperature in C */
    bmp.getTemperature(&temperature);
    /* Convert atmospheric pressure, SLP and temp to altitude    */
    baroaltitude = (bmp.pressureToAltitude(seaLevelPressure,bmp_event.pressure,temperature));
    
    temperatureh = (htu.readTemperature());
    humidity = (htu.readHumidity());
  }

//  energy1= energy1 + random(-100,100);
//  energy2= energy2 + random(-100,100);
  uptime++;

}

void timeset()
{
  timereset = true;
}