#include "CubeCellPlusPins.h"                 // CubeCell Plus pin definitions 
// Includes: 
//   #define windDirectionPinADC3 
//   #define windSpeedPinGPIO8 

const uint16_t reportingPeriod = 10000;       // In milliseconds, but keep it low while testing

uint16_t windCounter = 0;

void setup () { 
  pinMode(Vext,OUTPUT); 
  digitalWrite(Vext,LOW);                     // Turn on power to connected devices 
  
  Serial.begin(115200); 
  delay(200); 
  Serial.println("[setup] Davis Anemometer"); 

// Define the interrupt pin 

  PINMODE_INPUT_PULLUP(windSpeedPin); 
} 

void loop () { 
  measureWind(); 
  delay(reportingPeriod); 
} 

void initialiseWindCount() { 
  windCounter = 0; 
} 

void incrementWindCount() { 
  windCounter++; 
} 

void measureWind() { 
  uint32_t startTime, endTime; 
  uint16_t rotations = 0; 
  uint16_t windSpeed = 0; 
  uint16_t windBearing = 0; 
  uint16_t totalWindBearing = 0; 
//  uint16_t bearingCalibrationOffset = 0;    // See comment below 
  uint8_t averageCount = 5;                   // Number of direction readings to take and average 

  /* 
    For the Davis 6410 anemometer, 1000 revolutions per hour = 1 kilometre per hour 
    Our time interval is measured in milliseconds 
    
        calibrationSpeed= 1// kilometres per hour 
        calibrationRotations= 1000// rotations per hour 
        timeUnits= 3600000// milliseconds per hour 
    
    For wind speed calculations: 
    
        scalingFactor = calibrationSpeed * timeUnits / calibrationRotations 
  */ 

  int scalingFactor = 3600; 
  
  initialiseWindCount(); 
  Serial.println("[measureWind] Begin wind sampling..."); 
  attachInterrupt(windSpeedPin,incrementWindCount,FALLING); 
  startTime = millis(); 
  
  for (int i = 0; i < averageCount; i++) { 
    totalWindBearing = totalWindBearing + readWindBearing(); 
    delay(1000); 
  } 
  windBearing = totalWindBearing / averageCount; 

  /* 
    If the anemometer arm cannot be set pointing true north 
    (see User Manual), a wind bearing calibration offset 
    must be set according to the direction it does point and 
    the above line of code replaced by the following lines: 
    
    windBearing = bearingCalibrationOffset + totalWindBearing / averageCount; 
    if (windBearing > 360) { 
      windBearing = windBearing - 360; 
    } else if (windBearing < 0) { 
      windBearing = windBearing + 360; 
    } 
  */ 
  
  detachInterrupt(windSpeedPin); 
  endTime = millis(); 
  Serial.println("[measureWind] End wind sampling");
  
  rotations = windCounter; 
  windSpeed = (int) (scalingFactor * rotations / (endTime - startTime)); 

  Serial.print("[measureWind] Rotations : "); 
  Serial.println(rotations); 
  Serial.print("          scalingFactor : "); 
  Serial.println(scalingFactor); 
  Serial.print("              startTime : "); 
  Serial.println(startTime); 
  Serial.print("                endTime : "); 
  Serial.println(endTime); 
  Serial.print("             Wind Speed : "); 
  Serial.print(windSpeed); 
  Serial.println(" kph"); 

  Serial.print("[measureWind] Bearing : "); 
  Serial.print(windBearing); 
  Serial.println(" °"); 

  compassDirection(windBearing); 
} 

uint16_t readWindBearing() { 
  //return adc level 0-4095; Need to calibrate to find max value for configuration 
  uint16_t windReading = analogRead(ADC3); 
  // Serial.print("[readWindBearing] Wind Reading "); 
  // Serial.println( windReading ); 
  uint16_t windBearing = myMap(windReading, 0, 3806, 0, 359); 
  return windBearing; 
} 

uint16_t myMap(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) { 
  if ((in_max - in_min) > (out_max - out_min)) { 
    return (x - in_min) * (out_max - out_min+1) / (in_max - in_min + 1) + out_min; 
  } else { 
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 
  } 
} 

void compassDirection( uint16_t windBearing ) { 
  Serial.print("[compassDirection] "); 
  if (windBearing > 169) { 
    if (windBearing > 259) { 
      if (windBearing > 304) { 
        if (windBearing > 326) { 
          if (windBearing > 349) { 
            Serial.print("N"); 
          } else { // 326 < windBearing <= 349 
            Serial.print("NNW"); 
          } 
        } else { // 304 < windBearing <= 326 
          Serial.print("NW"); 
        } 
      } else { //windBearing <= 304 
        if ( windBearing > 281) { 
          Serial.print("WNW"); 
        } else { // 259 < windBearing <= 281 
          Serial.print("W"); 
        } 
      } 
    } else { // windBearing <= 259 
      if ( windBearing > 214) { 
        if ( windBearing > 236) { 
          Serial.print("WSW"); 
        } else { // 214 < windBearing <= 236 
          Serial.print("SW"); 
        } 
      } else { // windBearing <= ? 
        if ( windBearing > 191) { 
          Serial.print("SSW"); 
        } else { // 169 < windBearing <= 191 
          Serial.print("S"); 
        } 
      } 
    } 
  } else { // windBearing <= 169 
    if ( windBearing > 79 ) { 
      if ( windBearing > 124) { 
        if ( windBearing > 146) { 
          Serial.print("SSE"); 
        } else { // 124 < windBearing <= 146 
          Serial.print("SE"); 
        } 
      } else { // 101 < windBearing <= 124 
        if ( windBearing > 101) { 
          Serial.print("ESE"); 
        } else { // 79 < windBearing <= 101 
          Serial.print("E"); 
        } 
      } 
    } else { // windBearing <=79 
      if ( windBearing > 34) { 
        if ( windBearing > 56) { 
          Serial.print("ENE"); 
        } else { // 34 < windBearing <= 56 
          Serial.print("NE"); 
        } 
      } else { // windBearing <= 34 
        if ( windBearing > 11) { 
          Serial.print("NNE"); 
        } else { // 349 < windBearing <= 11 
          Serial.print("N"); 
        } 
      } 
    } 
  } 
  Serial.println(); 
}
