#include <Adafruit_NeoPixel.h>
#include <FreqMeasure.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define NUMPIXELS 8   	// Anzahl an Pixel (LEDs)
#define PIN 11     		// Neopixel PIN
#define PMS_PIN 8 		// Drehzahlsignal-Eingang bei Rotax 122  Lima: 100Hz/1000rpm; Pickup: 16.666 Hz/1000rpm
/*-----------------------------------------------------------------*/
//Funktionsprototypen (bekannt machen der unten aufgeführten Funktionen)
void blinkDelay();
void errorPrint();
void inOutMode(); 

/*-----------------------------------------------------------------*/
//Neopixel-Konfiguration
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

/*--------------------FARBEN---------------------------------------*/
//Farbkonfiguration                 // <--- ### HIER FARBEN UND HELLIGKEIT EINSTELLEN ###
uint32_t green    = pixels.Color(0, 100, 0);    //1. Wert rot, 2. Wert gruen, 1. Wert blau - Helligkeit von 0 (dunkel) bis 255 (hell)
uint32_t yellow   = pixels.Color(100, 100, 0);
uint32_t orange   = pixels.Color(200, 100, 0);
uint32_t red      = pixels.Color(100, 0, 0);
uint32_t white    = pixels.Color(100, 100, 100);
uint32_t blue     = pixels.Color(0, 0, 100);
uint32_t black    = pixels.Color(0, 0, 0);
uint32_t violet   = pixels.Color(68, 50, 127);
uint32_t darkblue   = pixels.Color(0, 0, 68);
uint32_t lightblue  = pixels.Color(0, 68, 127);

/*--------------------DREHZAHL-------------------------------------*/
//Motorrad-/Drehzahl-Paramteter 
struct bikeParameters{
  float min_revs = 0.;    	// Minimalwert (um Fehler auszuschließen) 
  float max_revs = 14000.;  // Maximalwert (um Fehler auszuschließen) 
  //(Drehzahlschwellen - genutzt fuer Funktion: inOutMode())
  float threshold_1 = 9500., threshold_2 = 10000., threshold_3 = 10500., threshold_4 = 11000., threshold_5 = 11300.;  // <--- ### HIER DREHZAHL EINSTELLEN ### 
} RS125;                  
                          
/*--------------------VARIABLEN---------------------------------------*/
unsigned long data_unavailable = 0;
unsigned long data_available = 0;
const long interval = 1000;
int blink_interval = 15;        // Blinkintervall des Schaltblitzes <--- ### HIER INTERVALL EINSTELLEN ###
double sum = 0;
int count = 0;
int total_counts = 30;          // Anzahl Messungen, bevor der Mittelwert ausgerechnet wird <--- ### HIER ANZAHL EINSTELLEN ### (standard = 30)
float frequency = 0.;

/*##########################_SETUP_################################*/
void setup() {
	
	#if defined (__AVR_ATtiny85__)
		if (F_CPU == 16000000) clock_prescale_set(clock_div_1);	// Frequenz des Mikrocontrollers
	#endif
	
  pixels.begin();     				// Initialisiere NEOPIXEL.
  pixels.show(); 
  
  pinMode (PMS_PIN, INPUT_PULLUP); 	// Pullup muss hier stehen
    
  Serial.begin(9600);   			// braucht man nicht (fuer seriellen Monitor, Kontrollausgabe)
  FreqMeasure.begin();
}
/*##########################_LOOP_#################################*/
void loop() {

	if (FreqMeasure.available()) {
		sum = sum + FreqMeasure.read();
		count = count + 1;
		if (count > total_counts) {		// Anzahl Messungen erreicht
			frequency = FreqMeasure.countToFrequency(sum / count); // berechne Mittelwert
			frequency = frequency*60;	// rpm
			
			Serial.print("Rpm=");
			Serial.println(frequency);
			
			data_available = millis();	// Zeitpunkt zu dem Daten zur Verfuegung standen
			sum = 0;
			count = 0;

			if (frequency < RS125.min_revs || frequency >  RS125.max_revs){  //Sicherheitsabfrage, ob rpm innerhalb min<->max
				  Serial.println("Error, frequency out of range or no signal available.");
				  Serial.println(frequency);
				  pixels.clear(); 
				  pixels.show();
				  frequency = 0.;     
			}
			else{
				inOutMode();			// gehe zur Funktion "inOutMode()" und setze entsprechende Pixel, je nach Drehzahl
				pixels.show();			// gesetzte Pixel ausgeben, nach der fertigen/nach dem Verlassen der Funktion
			} 			
		}
	}
	else{								// Logik um bei Signalausfall alles auf 0 zu setzen
		data_unavailable = millis(); 	// Zeitpunkt zu dem keine Daten mehr zur Verfuegung standen
		
		if (data_unavailable - data_available >= interval){ // wenn seit dem letzten Datenverlust mehr als ein Intervall (1 Sek. [1000 millis]) vergangen ist, alles ausschalten
			Serial.print ("Rpm=");
			Serial.println("0");
			
			frequency = 0.; 
			
			pixels.clear();
			pixels.show();
		}
	}
]
/*+++++++++++++++++++BLINK DELAY++++++++++++++++++++++++++++++++++++*/
void blinkDelay(){    // Pixel blinken lassen
  
  pixels.show();
  delay(blink_interval);
  pixels.clear();
  pixels.show();
  delay(blink_interval);
}
/*+++++++++++++++++++ERROR PRINT++++++++++++++++++++++++++++++++++++*/
void errorPrint(){    // etwas schief gelaufen
  
  Serial.print ("Error!\n");
}
/*+++++++++++++++++++inOut MODE+++++++++++++++++++++++++++++++++++++*/
void inOutMode(){   
  
  if (frequency >= RS125.threshold_1 && frequency < RS125.threshold_2) {   		// gruen
    for (int i = 3; i < 5; i++) {pixels.setPixelColor(i, green);} 		// setze Pixel 3 und 4 auf gruen
  }
  else if (frequency >= RS125.threshold_2 && frequency < RS125.threshold_3) {   // gelb
    for (int i = 2; i < 6; i++) {pixels.setPixelColor(i, yellow);} 		// setze Pixel 2 bis 5 auf gelb
  }
  else if (frequency >= RS125.threshold_3 && frequency < RS125.threshold_4) {   // orange
    for (int i = 1; i < 7; i++) {pixels.setPixelColor(i, orange);} 		// setze Pixel 1 bis 6 auf orange 
  }     
  else if (frequency >= RS125.threshold_4 && frequency < RS125.threshold_5) {   // rot
    for (int i = 0; i < NUMPIXELS; i++) {pixels.setPixelColor(i, red);} // setze Pixel 0 bis 7 auf rot (alle 8)
  }
  else if (frequency >= RS125.threshold_5 && frequency <= RS125.max_revs) {  	// rot blinkend, ab/ueber diesem Wert geht das Schaltlicht an
    for (int i = 0; i < NUMPIXELS; i++) {pixels.setPixelColor(i, red);} // setze Pixel 0 bis 7 auf rot (alle 8)
    blinkDelay();	// rufe Funktion zum Blinken auf
  }
  else {			// Sicherheitsabfrage
    errorPrint();
  }
}