//----------------------------------------------------------------------
// Titel     : WebWecker-Lösung zum myAVR C++ Tutorial www.avr-cpp.de
//----------------------------------------------------------------------
// Funktion  : Wecker mit Echtzeituhr, Temperaturanzeige und PC-Frontend
// Add-On    : myEthernet 128K
// Schaltung : PortD = LCD, PortB.0 = Taste, PortB.1 = LCD-Backlight
//             PortB.2 = Speaker, PortC.0 = Lichtsensor
//             PortC.4 und PortC.5 = I2C (TWI/SCL/SDA)
//----------------------------------------------------------------------
// Prozessor : ATmega8
// Takt      : 3,6864 MHz
// Sprache   : myAVR C++
// Version	 : 1.01
// Datum     : 21.06.2012
// Autor     : Alexander Huwaldt
//----------------------------------------------------------------------
class Application : public Controller
{
	protected: Button 	taste;			// Klicken = Schlummerfunktion, Halten = Alarm aus 
	protected: AnalogDevice lichtsensor;		// Dunkel -> LCD Beleuchtung an 
	protected: LcdMK2 	anzeige;		// Anzeige Uhrzeit, Temperatur und Alarm
	protected: SoundChanelB lautsprecher;		// Wecksignal/-melodie ausgeben
	protected: I2C_LM75 	temperatursensor;       // Raumtemperatur ermitteln
	protected: I2C_DS1307 	echtzeituhr;            // Batteriegestützte Echtzeituhr
	protected: I2C_24Cxx 	myethernet;             // I2C-Schittstelle des myEthernet (shared Ram)
	protected: Uart		konsole;		// Verbindung zum PC-Programm
	protected: String	buffer;			// Zwischenspeicher für Kommandos vom PC-Programm
	protected: bool		neuerAlarm;		// true wenn neue Weckzeit empfangen wurde
	protected: bool		neueZeit;		// true wenn neue Uhrzeit empfangen wurde
	protected: String	text;			// Zwischenspeicher für Texteausgaben
	protected: Eeprom 	eeprom;			// Initialisiert EEPROM-Zugriff
	protected: Eeprom_uint8	weckStunde;		// SRAM gepufferte EEPROM Variable 
	protected: Eeprom_uint8	weckMinute;		// SRAM gepufferte EEPROM Variable
	protected: Eeprom_uint8	weckSekunde;		// SRAM gepufferte EEPROM Variable
	protected: uint8 	alarmDauer;		// Dauer des Weckalarms in Serunden
	protected: uint8	stunden;		// Stunden für TWI -> myEthernet
	protected: uint8	minuten;		// Minuten für TWI -> myEthernet
	protected: uint8	sekunden;		// Sekunden für TWI -> myEthernet
	protected: uint8_t	wait;			// Wartezeit für TWI
 
	// wird einmalig bein Einschalten des Systems ausgeführt    
	public: void onStart()
	{
		// Initialisierungssequenz 
		// weckStunde=weckMinute=weckSekunde=0xFF nach Brennen
		alarmDauer = 0;				// Alarm aus
		neueZeit   = false;			// noch keine neue Uhrzeit vom PC empfangen 
		neuerAlarm = false;			// noch keine neue Weckzeit vom PC empfangen
		taste.config(portB,bit0);		// Taste initialisieren 
		lichtsensor.config(0);			// Lichstsensor initialisieren
		temperatursensor.config(0x90);		// Temperatursensor initialisieren
		echtzeituhr.config(0xD0);		// Echtzeituhr initialisieren
		konsole.config(9600);			// UART initialisieren
		myethernet.config(0xB0);		// wie in config.cfg festgelegt
 
		// Begrüßungssequenz nach Programmieren, Reset oder Power ON
		anzeige.backLightOn();	
		anzeige.writeLine(1,"Willkommen beim");
		anzeige.writeLine(2,"kleinen Projekt");
		// Begrüßungstonfolge
		lautsprecher.play(FLASHSTR("a.a.a.ddd.ccc"));
		// einen Moment fürs Auge stehen lassen
		waitMs(3000);
		anzeige.clear();
		anzeige.backLightOff();
 
 
		wait= 1;				// Wartezeit für TWI
	}
 
	// wird wiedeholend aus der "MainLoop" des AppKernel aufgerufen
	// hier alles was Zeit hat verarbeiten
	public: void onWork()
	{
		// Anzeigezyklus 
		echtzeituhr.formatTimeToString(text,"%h:%m:%s Uhr");
		anzeige.writeLine(1,text);
		konsole.sendString(text+"|");
 
		stunden = echtzeituhr.hours;	// Stunden TWI
		waitMs(wait);
		myethernet.writeData(2, stunden);
		waitMs(wait);
 
		minuten = echtzeituhr.minutes;	// Minuten TWI
		waitMs(wait);
		myethernet.writeData(3, minuten);
		waitMs(wait);
 
		sekunden = echtzeituhr.seconds;	// Sekunden TWI
		waitMs(wait);
		myethernet.writeData(4, sekunden);
		waitMs(wait);
 
		int16 t = temperatursensor.getValue();  // hole Temperatur
 
		t *= 25;				// Umrechnung auf Zehntel-Temperatur
		t += 10;				// für Übergabe als 16 Bit Zahl
		t /= 20;
 
		text.formatNum(t, 1, 5, ' ');
		anzeige.writeLine(2, text);
		anzeige.write("\xdf" "C");
		text += "°C";
		konsole.sendString(text + "\n");
 
		myethernet.writeData(0, (uint8_t)t);	// Schreibe Byte 1 in SRAM des myEthernets
		waitMs(wait);
		myethernet.writeData(1, (uint8_t)(t/256)); // Schreibe Byte 2 in SRAM des myEthernets
 
		// Beleuchtungslogik
		if (lichtsensor.getValue8()>150)
			anzeige.backLightOff();
		else		
			anzeige.backLightOn();
 
		// Wecklogik		
		if (weckSekunde<60)
		{
			// Weckzyklus starten?
			if ( alarmDauer  == 0 &&
				 weckStunde  == echtzeituhr.hours &&	 
				 weckMinute  == echtzeituhr.minutes &&
				 weckSekunde == echtzeituhr.seconds )
			{
				// Weckzeit 120s
				alarmDauer = 120;
			}
			anzeige.setPos(2,10);
			if (alarmDauer>120)
				anzeige.write("SNOOZE ");
			if (alarmDauer>0)
				anzeige.write("ALARM  ");
			else
				anzeige.write("*      ");
		}
		else
			anzeige.write("       ");
 
		// wenn vom PC neue Uhrzeit empfangen -> Echtzeituhr stellen
		if ( neueZeit )
		{
			// Format: 13:44:00T
			neueZeit = false;
			echtzeituhr.setTime(buffer);
			buffer = "";
		}
 
		// wenn vom PC neue Weckzeit empfangen -> Wecker stellen
		if ( neuerAlarm )
		{
			// Format: 06:30:00A
			neuerAlarm = false;
			echtzeituhr.convertTime(buffer);	
			weckStunde = echtzeituhr.hours;
			weckMinute = echtzeituhr.minutes;
			weckSekunde= echtzeituhr.seconds;
			buffer = "";
		}
 
		// Pause, Zeit fürs Auge //geändert!
		waitMs(900);
	}
 
	// einmal pro Sekunde nachschauen ob Weckmelodie neu gestartet werden muss     
	public: void onTimer1s()
	{
		if (alarmDauer>0)
		{
			alarmDauer--;
			if (alarmDauer<=120 && !lautsprecher.isPlaying())
				lautsprecher.play(FLASHSTR("vfff,,fff,,fff,,dd,a,ff.dd,a,ffff.."
						  "CCC,,CCC,,CCC,,DD,C,ff.dd,a,ffff...") );
		}
	}
 
	// Ereignisbehandlung für Daten vom PC oder Tastenaktivität
	public: void onEvent(const Object& sender, uint8 data)
	{
		if (sender == konsole)
		{
			buffer+=(char)data;
			if (data=='T')
				neueZeit=true;
			else if (data=='A')
				neuerAlarm=true;
		}
		else if (sender == taste)
		{
			lautsprecher.stop();			
			if (data == Button::Click)
				alarmDauer = 120 + 60;    	// 120s Alarmzeit + 60s Snooze
			else if (data==Button::HoldStart)
				alarmDauer = 0;    		// Alarm aus
		}
	}
} app;