// Visual Micro is in vMicro>General>Tutorial Mode
// 

/*
	Name:       Keerlus.ino
	Created:	25-11-2020 11:00
	Author:     LAPTOP-PETER\peter

*/
#include <EEPROM.h>
#include <stdarg.h>

//
// IO pin definities
//
const byte PIN_LED_TEST_RICHTING_ROOD = 2;		// handmatig richting rood
const byte PIN_LED_TEST_RICHTING_GROEN = 3;		// handmatig richting groen
const byte PIN_LED_INDICATOR_RICHTING_GROEN = 5;	// richting is groen
const byte PIN_LED_INDICATOR_RICHTING_ROOD = 4;		// richting is rood

const byte PIN_LED_MELDING_SECTIE_A = 6;		// Detectie A
const byte PIN_LED_MELDING_SECTIE_B = 7;		// Detectie B
const byte PIN_LED_MELDING_SECTIE_D = 8;		// Detectie D
const byte PIN_LED_MELDING_SECTIE_E = 9;		// Detectie E

// Terugmelding S88 bus
const byte PIN_TERUGMELDING_SECTIE_A = 11;	// Detectie A
const byte PIN_TERUGMELDING_SECTIE_E = 10;	// Detectie E
// Aansturing relais
const byte PIN_RELAIS_AANSTURING = 12;		// Detectie A

const byte PIN_ONBOARD_LED_D13 = 13;

//
// Hall sensor inputs (pullup is ook external) 
//
const byte ANA_DET_A = A0;	// Detectie sectie A
const byte ANA_DET_B = A1;	// Detectie sectie B
const byte ANA_DET_D = A2;	// Detectie sectie D
const byte ANA_DET_E = A3;	// Detectie sectie E
//
// Input voor inversie
//
const byte ANA_INVERTEER_RICHTING = A7;

enum Richting { rood = 0, groen = 1 };
enum Sectie { A, B, D, E};

/*
 We maken timers op basis van millis()
*/
unsigned long CurrentMillis;	// huidige waarde van de millis() timer
unsigned long BasicTimer;	// basis milliseconden countdown teller
unsigned long OnStateTimer;	// timer voor de aantijd van een detectie
unsigned long ActionTimer;	// timer voor afhandeling
unsigned long KnipperTimer;	// timer voor knippereren
int BasicTimerValue;		// in ms
int OnStateTimerValue;		// Count down voor signaal ON state (in basic timer intervals)
int ActionTimerValue;		// in ms
int KnipperTimerValue;		// in ms

// Detectie inputs
bool Detectie_A = false;
bool Detectie_B = false;
bool Detectie_D = false;
bool Detectie_E = false;
// OnState timer (count down)
int TimerOnState_A = 0;
int TimerOnState_B = 0;
int TimerOnState_D = 0;
int TimerOnState_E = 0;
// S88 melding timer voor vaste lengte van de bezetmelding puls
int S88MeldingTimer = 0;
//
bool InverteerRichting;		// met strap mogelijkheid om relais gedrag te inverteren

Richting richting = rood;	// Richting is stand van relais
bool KnipperOn = false;		// toggle voor knipperen On Board LED
int AnaloogIn;			// Waarde van ingelezen analoge ingang

//=================================================

void LeesInverteerRichting()
{
	AnaloogIn = analogRead(ANA_INVERTEER_RICHTING);
	if (AnaloogIn > 512)
	{
		InverteerRichting = true;
	}
	else
	{
		InverteerRichting = false;
	}
}

void LeesDetectieInputs()
{
	// Aktief als input laag is
	// Alleen set van de detectie, reset na afhandeling
	AnaloogIn = analogRead(ANA_DET_A);
	if (AnaloogIn < 512) {Detectie_A = true;}
	AnaloogIn = analogRead(ANA_DET_B);
	if (AnaloogIn < 512) {Detectie_B = true;}
	AnaloogIn = analogRead(ANA_DET_D);
	if (AnaloogIn < 512) { Detectie_D = true; }
	AnaloogIn = analogRead(ANA_DET_E);
	if (AnaloogIn < 512) { Detectie_E = true; }
}

void LeesTestButtons()
{
	if (!digitalRead(PIN_LED_TEST_RICHTING_ROOD)) 
	{ 
		Detectie_A = true;
		Serial.println(F("Druktoets rood"));

	}
	if (!digitalRead(PIN_LED_TEST_RICHTING_GROEN)) 
	{ 
		Detectie_E = true; 
		Serial.println(F("Druktoets groen"));
	}
}

void HandleBasicTimer()
{
	LeesInverteerRichting();
	LeesDetectieInputs();
	LeesTestButtons();
}

void HandleOnStateTimers()
{
	// moet de timer (weer) gestart worden?
	if (Detectie_A) 
	{ 
		TimerOnState_A = OnStateTimerValue; 
		S88MeldingTimer = OnStateTimerValue;
		richting = rood;
		Detectie_A = false; // reset detectie
	}
	if (Detectie_B)
	{
		TimerOnState_B = OnStateTimerValue;
		richting = rood;
		Detectie_B = false; // reset detectie
	}
	if (Detectie_D)
	{
		TimerOnState_D = OnStateTimerValue;
		richting = groen;
		Detectie_D = false; // reset detectie
	}
	if (Detectie_E)
	{
		TimerOnState_E = OnStateTimerValue;
		S88MeldingTimer = OnStateTimerValue;
		richting = groen;
		Detectie_E = false; // reset detectie
	}
	if (TimerOnState_A > 0) { TimerOnState_A = TimerOnState_A - 1; }
	if (TimerOnState_B > 0) { TimerOnState_B = TimerOnState_B - 1; }
	if (TimerOnState_D > 0) { TimerOnState_D = TimerOnState_D - 1; }
	if (TimerOnState_E > 0) { TimerOnState_E = TimerOnState_E - 1; }
	if (S88MeldingTimer > 0) { S88MeldingTimer = S88MeldingTimer - 1; }
}

void HandleActionTimer()
{
	//
	ZetMeldingLed(A, TimerOnState_A);
	ZetMeldingLed(B, TimerOnState_B);
	ZetMeldingLed(D, TimerOnState_D);
	ZetMeldingLed(E, TimerOnState_E);
	//
	ZetS88TerugMelding(S88MeldingTimer);
	//
	ZetRichtingsLed(richting);
	ZetRelais(richting);
}

void HandleKnipperTimer()
{
	if (KnipperOn)
	{
		digitalWrite(PIN_ONBOARD_LED_D13, HIGH);
	}
	else
	{
		digitalWrite(PIN_ONBOARD_LED_D13, LOW);
	}
	KnipperOn = !KnipperOn;

}

void ZetRelais(Richting richting)
{
	bool AanState = true;
	if (InverteerRichting) { AanState = false;  }

	switch (richting)
	{
	case rood:
		digitalWrite(PIN_RELAIS_AANSTURING, AanState);
		break;
	case groen:
		digitalWrite(PIN_RELAIS_AANSTURING, !AanState);
		break;
	default:
		break;
	}
}

void ZetMeldingLed(Sectie sectie,int detectieTimer)
{
	bool OnState = false;
	if (detectieTimer > 0) { OnState = true; }
	switch (sectie)
	{
	case A:
		digitalWrite(PIN_LED_MELDING_SECTIE_A, OnState);
		break;
	case B:
		digitalWrite(PIN_LED_MELDING_SECTIE_B, OnState);
		break;
	case D:
		digitalWrite(PIN_LED_MELDING_SECTIE_D, OnState);
		break;
	case E:
		digitalWrite(PIN_LED_MELDING_SECTIE_E, OnState);
		break;
	default:
		break;
	}
}

void ZetS88TerugMelding(int detectieTimer)
{
	if (detectieTimer > 0)
	{
		// melding moet aan
		if (richting == rood)
		{
			digitalWrite(PIN_TERUGMELDING_SECTIE_A, HIGH);
			digitalWrite(PIN_TERUGMELDING_SECTIE_E, LOW);
		}
		else
		{
			digitalWrite(PIN_TERUGMELDING_SECTIE_A, LOW);
			digitalWrite(PIN_TERUGMELDING_SECTIE_E, HIGH);
		}
	}
	else
	{
		// melding moet uit
		digitalWrite(PIN_TERUGMELDING_SECTIE_A, LOW);
		digitalWrite(PIN_TERUGMELDING_SECTIE_E, LOW);
	}
}

void ZetRichtingsLed(Richting richting)
{
	switch (richting)
	{
	case rood:
		digitalWrite(PIN_LED_INDICATOR_RICHTING_ROOD, HIGH);
		digitalWrite(PIN_LED_INDICATOR_RICHTING_GROEN, LOW);
		break;
	case groen:
		digitalWrite(PIN_LED_INDICATOR_RICHTING_ROOD, LOW);
		digitalWrite(PIN_LED_INDICATOR_RICHTING_GROEN, HIGH);
		break;
	default:
		break;
	}
}

void loop()
{
	CurrentMillis = millis();	// neem eerst een sample van de millis timer
	if ((CurrentMillis - BasicTimer) > BasicTimerValue)
	{
		BasicTimer = CurrentMillis;	// Restart timer
		HandleBasicTimer();
		HandleOnStateTimers();
	}
	if ((CurrentMillis - ActionTimer) > ActionTimerValue)
	{
		ActionTimer = CurrentMillis;	// Restart timer
		HandleActionTimer();
	}
	
	if ((CurrentMillis - KnipperTimer) > KnipperTimerValue)
	{
		KnipperTimer = CurrentMillis;	// Restart timer
		HandleKnipperTimer();
	}
}

void setup()
{
	// set up reference to LedSignControl in report class instance
	// Start serial interface
	Serial.begin(115200);
	Serial.setTimeout(50); // Time out set to 50ms to get faster resonse
	Serial.println(F("==================== "));
	Serial.println(F("Nano startup"));
	Serial.println(F("Versie 1.2 2021-02-13"));
	Serial.println(F("- Test LED pin assigment corrected"));
	Serial.println(F("- Duration output signal set to 1s (was 2s)"));

	/*
		I/O pinnen moeten nog worden ingesteld
	*/
	{
		pinMode(PIN_LED_TEST_RICHTING_ROOD, INPUT_PULLUP);
		pinMode(PIN_LED_TEST_RICHTING_GROEN, INPUT_PULLUP);
		pinMode(PIN_LED_INDICATOR_RICHTING_GROEN, OUTPUT);
		pinMode(PIN_LED_INDICATOR_RICHTING_ROOD, OUTPUT);

		pinMode(PIN_LED_MELDING_SECTIE_A, OUTPUT);
		pinMode(PIN_LED_MELDING_SECTIE_B, OUTPUT);
		pinMode(PIN_LED_MELDING_SECTIE_D, OUTPUT);
		pinMode(PIN_LED_MELDING_SECTIE_E, OUTPUT);

		pinMode(PIN_TERUGMELDING_SECTIE_A, OUTPUT);
		pinMode(PIN_TERUGMELDING_SECTIE_E, OUTPUT);

		pinMode(PIN_RELAIS_AANSTURING, OUTPUT);
		//
		pinMode(PIN_ONBOARD_LED_D13, OUTPUT);

		// ingangen voor Hall detectors
		pinMode(ANA_DET_A, INPUT_PULLUP);
		pinMode(ANA_DET_B, INPUT_PULLUP);
		pinMode(ANA_DET_D, INPUT_PULLUP);
		pinMode(ANA_DET_E, INPUT_PULLUP);

		pinMode(ANA_INVERTEER_RICHTING, INPUT_PULLUP);
	}
	
	/*
	 * Init de timers
	*/
	// Timer values
	BasicTimerValue = 10;		// in ms
	OnStateTimerValue =100;		// Count down voor signaal ON state (in basic timer intervals)
	ActionTimerValue = 100;		// in ms
	KnipperTimerValue = 500;	// in ms
	//
	LeesInverteerRichting();
}


