/* uhr-os05.c
Betriebssystem für Funk-Uhr
(c) 2004 by Malte Marwedel, www.marwedels.de/malte, m.marwedel@onlinehome.de
Diese Datei darf frei kopiert und compiliert werden.
It's allowed to copy and compile this file freely.
Änderungen an der Datei sind erlaubt, solange kenntlich gemacht wird,
dass es sich dann nicht mehr um die original Datei handelt.
It's allowed to modify this file as long it is mentioned that it isn't the original
file any longer.
Es muss immer erkennbar sein, dass die original Datei von mir stammt
It must always be recognizable that the original file is written by me
Die Benutzung des Programmes erfolgt auf eigene Gefahr, ich hafte nicht für Schäden jeglicher art, falls dieses Programm welche verursachen sollte.
The use of this program it at your own risk, I'm not responsible for damage of any kind, if this program should cause which.
Programm für gcc, MCU: AT90S8535, 4MHZ Quarz
Program for gcc, MCU AT90S8535 with a frequency of 4MHZ
Zum Kompilieren habe ich winavr20030913 verwendet, Optimierung -Os
I've used winavr20030913 for compiling, optimization -Os
Ohne maximale Optimierung durch den Compiler würde das Programm nicht in den MCU passen
The compiler must be set to maximum optimization, otherwise the program would not fit into te MCU


Bedeutung der Status LEDs:
1: RS232 Komunikation aktiv
2: IR Komunikation aktiv
3: DCF77 Empfang aktiv
4: DCF77 Error
5: Display zeigt Datum an
6: Display zeigt nächste Weckzeit an
7: Ein Wecker wird innerhalb der nächsten 24 Std Alarm schlagen
8: Ein Wecker wird innerhalb der nächsten 2 Std Alarm schlagen

Pin Belegung des MCU:
Pin A0 : input, Taster 1
Pin A1 : input, Sensor 1
Pin A2 : input, Taster 2
Pin A3 : input, Sensor 2
Pin A4 : input, Taster 3
Pin A5 : input, nicht belegt
Pin A6 : input, Taster 4
Pin A7 : input, nicht belegt
Pin B0 : output, 1. Ziffer
Pin B1 : output, 2. Ziffer
Pin B2 : output, 3. Ziffer
Pin B3 : output, 4. Ziffer
Pin B4 : output, Status LEDs 5,6,7,8
Pin B5 : input, MOSI
Pin B6 : input, MISO
Pin B7 : input, SCK
Pin C0 : output, Segment a
Pin C1 : output, Segment f
Pin C2 : output, Segment e
Pin C3 : output, Segment b
Pin C4 : output, Segment g
Pin C5 : output, Segment c
Pin C6 : output, Segment d
Pin C7 : output, Status LEDs 1,2,3,4
Pin D0 : input, RS232 empfangen
Pin D1 : output, RS232 senden
Pin D2 : input, DCF 77
Pin D3 : input, IR Empfänger, TSOP 1736
Pin D4 : output, IR Sender, Daten Bit
Pin D5 : output, IR Sender, Frequenz für Modulation
Pin D6 : output, Beeper/Lautsprecher (für Wecker)
Pin D7 : output, LEDs für Punkte zwischen Std und Min Anzeige

Belegung der Tasten:
Taster 1: Nächste Weckzeit anzeigen
Taster 2: Datum Anzeigen
Taster 3: IR oder Rs232 Modus verlassen
Taster 4: Zuerst Taster 4 gedrückt halten, dann gleichzeitig Taster 1 drücken, Taster 4 loslassen und dann Taster 1 loslassen: Der nächse in 24 Std auftretene Wecker wird ignoriert
Beliebige Taste: Wenn ein Wecker gerade klingelt, wird er ausgeschaltet

Genauigkeit des Weckers ohne DCF Syncronisation:
Die Unr benutzt Timer2, um ohne DCF77 Syncronisation weiter zu zählen
Der Prescaler beträgt 64, der Comparewert 244, beim erreichen wird der Timer automatisch zurückgesetzt
Bei 4MHZ Takt ergibt sich daraus:
4000000:64:244 = 256,1475409
Der Timer2 wird also 256,1475409 mal pro Sekunde aufgerufen. Die Uhr geht jedoch davon aus, dass der Timer2 genau 256 mal
pro Sekunde aufgerufen wird. Somit geht die Uhr prinzip-bedingt schon mal vor. Diese Abweichung beträgt genau:
1/256*256,1475409=1,000576332 -> Die Uhr zählt pro Sekunde 0,000576332 Sekunden zuviel. Über 24 Std macht dies:
0,000576332*60*60*24 = 49,79 Sekunden. Rechnerisch müsste die Uhr also ungefähr 50 Sekunden pro Tag zu schnell gehen.
Hinzu kommen noch mögliche Abweichungen des Quarzes nach oben und unten von der Idealfrequenz.
Mein Praxistest zeigte, dass die Uhr mal etwas zu schnell und mal etwas zu langsam gint.
So ging meine Uhr nach 24 Std ohne DCF Signal 16 Sec nach, nach 48 Std waren es 17 Sec. Zwischenzeitlich ging die Uhr jedoch bis zu 27 Sec vor!
Wahrscheinlich ist der von mir verwendete Quarz etwas temperaturabhängig.
Abschließend muss noch darauf hingewiesen werden, dass während des IR Sendens der Timer2 angehalten wird und sich daraus weitere Abweichungen
ergeben können.
Um die Abweichungen somit nicht zu groß werden zu lassen, wird die IR und RS232 Übertragung nach 15 Minuten automatisch abgeschaltet um das DCF
Signal wieder zu empfangen.

Programm Version 3 ist die erste Version, die alle zu Beginn geplanten Features enthält.
Diese Features sind:
Das RS232 Menu
Anzeigen von Daten auf den LED anzeigen
DCF Empfang
Fehlerkorektur für DCF Empfang (Logische Überprüfung, Checkbits, Zweimaliger Empfang mit Überprüfung, Startbit)
Wecker abfrage
Watchdog (benötigt 12 Byte Flash)
Taster Abfrage
Infrarot Übertragung

Programm Version 4 hat gegenüber der Version 3 folgende Änderungen erhalten:
- 1 Byte mehr RS232 Empfangsbuffer
- Code Optimierung
- Auslagerung einiger constanten Strings vom Flash in den EEprom
- Beheben einiger Bugs
- Nachts sind die LEDs nicht so hell wie tagsüber
- einige kleine Verbesserungen

Programm Version 5 hat gegenüber der Version 4 folgende Änderungen erhalten:
- Bug korrigiert, einstellen des Weckers beginnt immer mit Weckzeit 1, vorher war es die zuletzt von der SW abgerufene
- Verbessern des DCF Empfangs
- Feature um eine Weckzeit vorher zu deaktivieren
- Code Optimierung
- während des IR sendens bleibten die unteren 4 Status LEDs nicht mehr dunkel
- IR Senden verbessert
- Per IR können die beiden nach außen geführten A/D Ports abgefragt werden

Bekannte Bugs/Probleme:
DCF überträgt nur zweistellige Jahreszahlen. Intern wird jedoch vierstellig gerechnet. In 95 Jahren wird das Jahr somit falsch angezeigt werden :-) (nicht korrigierbar)
Die 7-Segment Anzeigen sind etwas zu hell. Nachts beleuchten sie das halbe Zimmer... (bei Gelegenheit zu korrigieren)
 (bei Gelegenheit zu korrigieren)
Beim PowerUp können zufällig ausgewählte EEprom Adressen überschreiben werden, nur per Hardware zu korrigieren (sollte besser korrigiert derden)

Bugs/Probleme, die nur mit mehr Flash speicher behoben werden können:
Ohne DCF Syncronisation weiß der Wecker nicht, welcher Wochentag ist (am eingeschaltetem Tag ist immer erstmal Monatg)
Ebenso kennt er von sich aus, nicht die Länge eines Monats. Ohne Syncronisation hat jeder Monat 31 Tage

Welcher Programmteil benötigt wieviel Speicher?
Die Size Angaben über jeder Funktion spiegeln das grobe Verhältnis wieder.
"Size" mal zwei ergibt die Ungefähre größe des benötigten Flashspeichers in Byte
Die Initialisierung von globalen Variablen und Konstanten wird hierbei nicht berücksichtigt.

Tasten Daten:
Die Tasten befinden sich am Analog-Eingang. Analoge Werte unter 800 werden als "Taste gedrückt" identifiziert

*/

#include <io.h>
#include <inttypes.h>
#include <interrupt.h>
#include <sig-avr.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

typedef unsigned char  u08;
typedef signed   char  s08;//derzeit unbenutzt
typedef unsigned short u16;
typedef signed   short s16;
typedef unsigned long  u32;
typedef signed   long  s32;//derzeit unbenutzt

//Variablen für die Zeit: 13 Byte
u08 minutes, hours;
u08 dayofweek = 1, day = 1, month = 1;
u16 year = 2004;
u08 volatile presec, seconds;
u32 uptimeminutes;    //u32 benötigt gegenüber u08 62 Byte mehr Flash
//Variablen für die Anzeige: 9 Byte
u08 volatile segment[4], statusleds = 0xff;
u08 dispmode; //0 = zeit, 1 = datum, 2 = wecker
u08 punkteblinken;
u08 showwhour,showwminute;
//Variabeln für Kommunikation: 47 Byte
u08 commtype;//0 = keine kommunikation, 1 = RS232 Communikation, 2 = IR Communikation
u08 rs232rausstring[36];
u08 volatile rs232reinstring[6];
u08 submenu232,newmenu;
u08 submenuir;
u08 volatile rs232echo;
//Variablen für die IR kommunikation: 7 Byte
u08 volatile empmode; //0: inaktiv, 1: es wird empfangen, 2: es wird gesendet
u08 volatile empfangir = 0xff;
u08 empdurch,precalc,empfang;
u08 volatile senddurch;
u08 lcdupdatecomplexity;
//Variablen für A/D Wandler: 19 Byte
u16 volatile adwerte[8] = {1023,1023,1023,1023,1023,1023,1023,1023};
u16 cconv; //current convertion
u08 convno;//convertion number
//Variablen für Wecker: 13 Byte
u08 whour,wminute, wdaysofweek, wsettings;
u08 wselected = 1;
u08 volatile wactive = 50;
u08 weckdata[4];
u08 wdisabled;//deaktiviert den Wecker für die laufende Minute
u08 wdisabled24; //deaktiviert den nächsten auftretenden Wecker (deaktivierung geht nur für den nächsten Wecker innerhalb der nächsten 24 Std)
u08 wleds; //0: größer 24 Std 1: innerhalb 24 Std 2: innerhalb 2 Std
//Variablen für Sicherheit: 2 Byte
u08 eepromaway = 10;
u08 commtimeoutminutes;
//Variablen für DCF 77 Empfang: 18 Byte
u08 fastsample;//wird nur in timer2 Interrupt benötigt, daher kein volatile
u08 volatile currentdcfval;
u08 lastuptime,lastdowntime;//zur Bestimmung, ob 0,1 oder neue Minute
u08 dcfposition = 70;   //70 = nicht syncron
u08 rminutes[2],rhours[2],rdayofweek[2],rday[2],rmonth[2],ryear[2];
u08 checkbit;//um die empfangenen Daten zu testen
//Variablen für die Tasten: 1 Byte
u08 lastkeys; //zuletzt gedrückte Tasten
//Variable für Delays: 2 Byte
u16 volatile warteschleife;//temonäre Variable

// Konstanten
#define commtimeup 15      //nach 15 Minuten wird der Kommunikationsmodus automatisch verlassen
#define tastschwelle 800   //je größer der Wert (min: 0; max: 1023), desdo empfindlicher die Taster der Uhr
#define ledsdunkel 22      //ab 22 Uhr sind die LEDs dunkler
#define ledshell 6         //bis 6:59 bleiben die LEDs dunkler
#define maxweck 10         //es gibt maximal 10 Wecker (mindestens: 1, maximal:60);
                           //WICHTIG: weckzeiten[] muss auf jeden Fall mindestens so viele Weckzeiten enthalten, wie durch maxweck eingestellt!!!, sonst überschneidet sich der Speicherbreich mit den im EEProm abgelegten Strings!!!
#define maxweckx maxweck+1 //wird intern häufig benötigt

//Vordefinieren der Wecker: jeder Wecker steht auf 6:30 Uhr und ist an jedem Tag aktiv, der Wecker selbst ist jedoch aus, jeder Wecker benötigt 4 Byte.
u08 weckzeiten[] __attribute__ ((section (".eeprom"))) = {0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0,6,30,0xff,0};

//Prozedur Übersicht:
SIGNAL(SIG_OVERFLOW1);               //Size: 89   Routine zum Überprüfen von IR Daten
SIGNAL(SIG_ADC);                     //Size: 64   Aktualisiert ständig die A/D Werte. Jeder Wert wird c.a 9 mal pro Sek aktualisiert, dabei wir ein Mittelwert aus 32 Messungen verwendet
void strcpyeep(const void *addr);    //Size: 8    Kopiert einen String aus dem EEprom in rs232rausstring
void zumsenden(u16 zeichen);         //Size: 147  Sendet ein zeichen per IR Schnittstelle
void tastentesten(void);             //Size: 86   Führt alle Aktionen aus, die die Tasten der Uhr betreffen
void testallwecker(void);            //Size: 93   Überprüft, ob ein Wecker klingen soll, die LEDs an/aus sein sollen, u.s.w.
u16 getreamingtime(u08 weckno);      //Size: 104  Gibt die Zeit bis zum Klingeln des Weckers in Minuten zurück (bis 24 Std)
void smallnottimecriticalcode(void); //Size: 68   Wird anstelle von "nop" in Warteschleifen ausgeführt. Darf daher selber keine Warteschleifen oder langen Code enthalten
void savewecktime(u08 weckno);       //Size: 45   Speichert die Weckzeit im EEprom unter der angegebenen Nummer
void getwecktime(u08 weckno);        //Size: 37   Liest die unter der Nummer im EEprom gespeicherte Weckzeit
SIGNAL(SIG_OUTPUT_COMPARE2);         //Size: 117  Zählt die Sekunden und steuert das Display, wird 256 mal pro Sekunde aufgerufen
SIGNAL(SIG_UART_RECV);               //Size: 44   Wenn ein Zeichen von der Seriellen Schnittstelle empfangen wurde, je nach Einstellung wird auch ein Echo gesendet
void rs232sendstring(void);          //Size: 23   Eendet den rs232rausstring an die Serielle Schnittstelle
void wordtostr(u32 nummer, u08 digits, u08 strposition); //Size: 64  Schreibt die "nummer" an die "strposition" in rs232rausstring. "digits" gibt die Anzahl der Stellen an
s16 strtoword(void);                 //Size: 53   Convertiert angekommene RS232 Signale in Nummern
void initsystem(void);               //Size: 55   Wird nach einem Reset/ Power On ausgeführt, setzt Register u.s.w.
void setsegments(void);              //Size: 142  Berechnet die anzuzeigenden LEDs des Displays aus integer werten
void updatetime(void);               //Size: 121  Zählt die Uhr manuell weiter, muss mindestens alle 60sec einmal aufgerufen werden
void newscreen(void);                //Size: 118  Sendet an RS232 eine Leerzeile, eine Zeile voll Bindestriche und die aktuelle Uhrzeit mit Datum
void makewstatus(u08 weckno);        //Size: 84   Formatiert rs232rausstring so, dass er den aktuellen Wecker wiedergibt, der wird als Wecker Nummer "weckno" angezeigt
void strcpypandsend(u08 startstring, u08 numofstrings); //Size:19 Ruft mehrfach strcpypshort() und anschließend rs232sendstring() auf.
void strcpypshort (u08 stringno);    //Size: 12   Ruft strcpy_p() auf. Da das eine Argument immer das Gleiche ist, wird so beim Funktionsaufruf die Übergabe eines Argumentes gespart
void show232menu(void);              //Size: 223  Sendet je nach Untermenu die richtigen Texte per RS232
void rs232com(void);                 //Size: 383  Überprüft die RS232 Eingabe, legt das neue Untermenü fest, und reagiert auf die Eingaben (z.B. kann es die Uhrzeit setzen)
void warte(u16 zeit);                //Size: 30   Warteschleife für das IR Senden
void sendirstring(void);             //Size: 129  Sendet einen String per IR
void showirmenu(void);               //Size: 218  Stellt die Daten zusammen, die per IR gesendet werden sollen
void ircom(void);                    //Size: 340  Wie rs232com, jedoch für das IR LCD Interface
void analyzedcf77(void);             //Size: 417  Decodiert die ankommenden DCF77 Signale, überprüft sie auf Richtigkeit und setzt die Uhr
int main( void );                    //Size: 111  Ruft je nach Bedarf die verschiendenen Prozeduren auf


SIGNAL(SIG_OVERFLOW1) {//timer abfrage
//wird 703 mal pro sec ausgeführt
//140,6 mal pro sec gibt es ein neues Bit
//Ausführung erfolgt also alle 11379 Takte (bei8 MHZ Chip Frequenz)
//der timer1 läuft immer, es sei denn, es werden selber von dem Device Daten per IR gesendet
//256² - 11379 = 54157
//bei 4MHZ:
//256² - 7168 = 58368  hat sich as optimaler Wert herausgestellt

if (empmode == 0) { //wenn auf empfang gewartet wird,
if bit_is_clear(PIND,3) {//gehe in Empfangsmodus
empmode = 1;
empdurch = 0;
precalc = 0;
//empfang = 0;
}
}
if (empmode == 1){
if bit_is_clear(PIND,3) {//wenn Eins, dann erhöhen
precalc++;
}
if (empdurch == 5) { //wenn 5 Sampels
//least sicnificant Bit wird zuerst gesendet
empfang = empfang /2;
if (precalc > 2) { //wenn Eins empfangen
empfang = empfang | 0x80;//oberstes Bit setzen
}

precalc = 0;
empdurch = 0;
if (empfang == 0) { //ende der Übertragung
empmode = 0;
}
}//ende wenn 5 Samples
empdurch++;
}//ende wenn Empfangsmode
if (empmode == 2) {
empfang = 0;
}
outp(0xe4,TCNT1H);//Das hohe Bit muss zuerst beschrieben werden
outp(0x00,TCNT1L);//58368
if ((empfang | 0x3c) == 0xbd) { //Überprüfe empfangene Daten auf Richtigkeit
empfangir = empfang;
empfang = 0;
}
}

SIGNAL(SIG_ADC) {
u08 nowconvert;
cconv += ADCW;
convno++;
if (convno == 32) { //Wenn 32 Convertierungen
convno = 0;
nowconvert = inp(ADMUX);      //ermittle, welcher Kanal verwendet wurde
adwerte[nowconvert] = cconv / 32;   //schreibe A/D Wert in Array
nowconvert++;
outp(nowconvert,ADMUX);       //Nächsten A/D Kanal (nur die unteren 3 Bit von ADMUX sind schreibbar)
cconv = 0;
}
sbi(ADCSR,ADSC);              //Setze Bit, um neue Konvertierung zu starten
}

void strcpyeep(const void *addr) {
eeprom_read_block(rs232rausstring,addr,36);
}

void zumsenden(u16 zeichen) { //Sendet die Daten an den Empfänger
u16 sendebuff;
u08 temp01,temp02;
//Variablen, da die Rechenzeit nicht ausreicht, um alles auf einmal zu berechnen
u08 statusledsfast;
u08 nextled,nextziffer,suboper;

if (empmode == 0) {//es wird gerade nicht empfangen
//sendetechnik b10DDDDDDDDDDDD01
sendebuff = (zeichen*4) | 0x8001;
senddurch = 1;
warte(2500);//damit der Empfänger die letzten Daten verarbeiten kann
outp(1,TCCR0); //startet Timer1
statusledsfast = statusleds;
statusledsfast = statusledsfast << 1;
nextled = 0;
nextziffer = 0;
cli();
while (sendebuff > 0) { //schiebt Bit für Bit nach draußen
if ((sendebuff & 1) == 0) { //wenn Bit null, setze Ausgang
cbi(PORTD,PIND5);
}else { //wenn Bit eins
sbi(PORTD,PIND5);
}
sendebuff = sendebuff /2;
while (senddurch != 0) {
senddurch++;
cbi(PORTD,PIND4);//Takte bis zum sbi:14+1
asm volatile("wdr");
outp(0,TCNT0); //Reset Timer0, 1 Takt

suboper = senddurch %32; //3 Takte
temp01 = ((senddurch / 32) % 4); //6 Takte
/* 1+3+6= 10 Takte wegen des obrigen Codes einsparen
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
*/
if (suboper == 3) { //Anzeigen
temp01 = segment[temp01];
temp02 = nextziffer | nextled;
outp(0,PORTB);
outp(temp01,PORTC);//Den Wert der Ziffer, 5 Takte
outp(temp02,PORTB);//Welche Ziffer, 10+x Tage,c.a. +0...15
}
/* Dec Code ist so schon langsam genug
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
*/
sbi(PORTD,PIND4);//Takte bis zum } :64
if (suboper == 1) { //LED berechnen
nextled = (statusledsfast << temp01)& 0x10;
}
if (suboper == 2) { //Ziffer berechnen
nextziffer =  (0x01<<temp01);
}


while (inp(TCNT0) < 70) { //normalerweise 73, jedoch muss der Zeitverlust durch die Routinen zur Anzeigen Berechnung nachgeholt werden
asm volatile("nop");
}
}//Warteschleife
senddurch++;//höhere Transferraten führten zu Fehlern auf Empfängerseite
}//ende Bit für Bit schieben
/*
Die folgende Messung stammt noch aus uhr-0s04.c. Wahrscheinlich ist die Anzahl der benötigten Takte
in dieser Programm Version geringfügig anders!
zwischen cli() und sei() vergehen laut Simulator 381951-381952 Takte (je nachdem ob man cbi()
mitzählt oder nicht).
presec wird alle 15625 Takte weitergezählt
somit wurde 24,44 mal das Weiterzählen vergessen
Da der Timer jedoch selber nicht gestoppt wird, sondern nur das Auslösen des Interrupts, wird nach sei()
in jedem Fall der SIG_OUTPUT_COMPARE2 Interrupt aufgerufen. Im Mittel ist bei cli() bereits die Hälfte
der Zeit bis zu SIG_OUTPUT_COMPARE2 abgelaufen. Also sind 7812,5 Takte abzuziehen.
Somit hätte presec 23,94 -> ~24 mal erhöht werden müssen
Dies soll jetzt nachgeholt werden. Zu beachten sind noch Überläufe, bei denen die Sekunden um eins erhöht werden müssen
prinzieiell würde auch dieser Code wiederum Zeit benötigen. Da presec aber eigentlich nur 23,94 mal erhöht
werden müsste, jedoch 24 mal erhöht wird, reduziert sich dadurch sogar die Ungenauigkeit
*/
if (presec > 231) { //ab 232 werden die Sekunden weiter gezählt; 256-24 = 232; 256 wäre wieder Null
  seconds++;
}
presec += 24;
sei();
sbi(PORTD,PIND4); //nur zur Sicherheit
cbi(PORTD,PIND5);
}//ende nicht beim Empfangen gestört
}//ende Prozedur

void tastentesten(void) {
//Wertet die Tasten der Uhr aus, und fürt die gewünschten Aktionen aus
u08 nowkeys,temp01;
nowkeys = 0;
temp01 = 0;
while (temp01 < 4) { //spart 18 Byte gegenüber 4 Einzelanweisungen
if (adwerte[temp01*2] < tastschwelle) {
  nowkeys += (1<<temp01);
}
temp01++;
}
if (lastkeys != nowkeys) {
lastkeys = nowkeys;
if (lastkeys > 0) {
if (wactive != 0) { //Wecker aus
  wactive = 0;
  wdisabled = 1;
  return;
}
if (lastkeys < 3) { //Datum oder Weckzeit anzeigen
  dispmode = 3-lastkeys;
}
}
if (lastkeys == 0) {//Uhrzeit anzeigen
dispmode = 0;
if (wdisabled24 == 1) {
  wdisabled24 = 0;
}
}
if (lastkeys == 0x04) { //IR / RS232 Mode verlassen
commtype = 0;
statusleds = statusleds & 0x3f;//status LED für RS232 und IR aus
empfangir = 0xff;//damit der Controller den IR Modus nicht sofort wieder aktiviert
}
if (lastkeys == 0x08) { //Nächste Weckzeit deaktivieren, Part 1, oder Deaktivieren rückgängig machen
wdisabled24 = 1;
}
if ((lastkeys == 0x09) && (wdisabled24 = 1)) { //Nächste Weckzeit Deaktivieren, Part 2
wdisabled24 = 2;
}

} //Ende Tastenwechsel
}

void testallwecker(void) {
u16 timetonext,wreamingtime;
u08 wnextsettings,wnextweckno,temp01;
timetonext = 32000;
//Die folgenden Variablen nicht zu initialisieren ist zwar unschön, spart jedoch 4Byte Flash und der ist halt knapp
//wnextsettings = 0; //Warnungen bezüglich dieser Variblen dürfen ignoriert werden. die Variablen werden nur verdendet wenn timetonext = 0 ist
//wnextweckno = 0;   //die Variable timetonext wird nur dann gleich null, wenn auch die beiden Variablen auf einen Wert gesetzt werden.
for(temp01 = 1;temp01<maxweckx;temp01++) {
wreamingtime = getreamingtime(temp01);
if ((wreamingtime >= 0)&&(wreamingtime < timetonext)) {
  timetonext = wreamingtime;
  showwhour = weckdata[0];
  showwminute = weckdata[1];
  wnextsettings = weckdata[3];
  wnextweckno = temp01;
}
}
if (timetonext < 1440) { //Weniger als ein Tag
  wleds = 1;
}else{
  wleds = 0;
  showwhour = 255; //Damit das Display nicht irgendwas anzeigt
  wdisabled24 = 0; //Es kann ein Wecker nicht mehr als 24 Std im Voraus deaktiviert werden
  }
if (timetonext < 120) {
  wleds = 2;
}
if ((timetonext == 0) && (wdisabled == 0)){
  if (wdisabled24 != 2) { //Wenn Wecker nicht vorher per Taster deaktiviert worden ist
  wactive = 70;

  //Deaktivieren des Weckers
  if (wnextsettings == 1) {//Wecker soll nur einmal ausgelöst werden
  wnextweckno *= 4; //Die Variable wird ja nur innerhalb dieser Prozedur verwedet
  temp01 = eeprom_read_byte((unsigned char *)(wnextweckno*1));
  if (temp01 != 0) {//Damit das EEProm nich ständig neu beschrieben wird, das wäre sonst des EEProms Ende
  eeprom_write_byte((unsigned char *)(wnextweckno*1),0);
  }
}//Ende Wecker nur einmal auslösen
} else { //ende Wecker soll nicht auslösen
wdisabled24 = 0;
wdisabled = 1;
}

}//Ende Wecker aktivieren

}

u16 getreamingtime(u08 weckno) {
/*Rückgabe:
es wird der Wert bis zur nächsten Auslösung des WEckers in Minuten zurückgegeben, wenn:
der Wecker aktiv ist, die Auslösung am aktullem oder nächstem Tag erfolgt.
ansonsten wird 32000 zurückgegeben
Berechnung der Differenz:
Wenn Wecker am gleichem Tag auslöst:
(wh-h)*60-(m-wm)
Wenn Wecker erst am nächstem Tag auslöst:
(60*24)+((wh-h)*60-(m-wm);
für das Ergebnis wird s16 benötigt

weckdata[2] = MoDiMiDoFrSaSo--
*/
u08 nextday; //weckdata[0] = whour; [1] = wminute; [2] = wdaysofweek; [3] = wsettings
s16 reamingtime;
weckno *= 4;
weckdata[0] = eeprom_read_byte((unsigned char *)(weckno -3));
weckdata[1] = eeprom_read_byte((unsigned char *)(weckno -2));
weckdata[2] = eeprom_read_byte((unsigned char *)(weckno -1));
weckdata[3] = eeprom_read_byte((unsigned char *)(weckno*1));
if (weckdata[3] == 0) {
return 3200;
}

reamingtime = (weckdata[0]-hours)*60-(minutes-weckdata[1]);
if ((((weckdata[2] << (dayofweek-1))& 0x80)== 0) || (reamingtime < 0)) {//Am aktuellem Tag ist der Wecker NICHT oder war bereits Aktiv, sehe nach, ob dies am nächstem Tag der Fall ist
nextday = dayofweek;
if (nextday == 7) {//7 bedeutet So, es folgt also Mo
  nextday = 0; //Nächster Tag ist ein Montag
}
if (((weckdata[2] << nextday)& 0x80) == 0) {//am nächstem Tag auch nicht aktiv, somit
reamingtime = 32000;
}else{//Ja, am nächstem Tag ist der Wecker aktiv
reamingtime += 1440;
}
}//ende, am aktuellem Tag nicht aktiv
return reamingtime;
}

void smallnottimecriticalcode(void) {
//Diese Pozedur darf nicht länger als 15000 Takte sein. Demnach dürfen keine Warteschleifen vorhanden sein
//Sie wird unregelmäßig häufig und in untegelmäßigen Abständen aufgerufen.

//Punkte zwischen der Minuten und Stundenanzeige blinken/leuchten lassen
asm volatile("wdr");
if ((punkteblinken == 1)&&(dispmode == 0)) {
if (presec < 128) {
  sbi(PORTD,7);
}else{
  cbi(PORTD,7);
}
}else{ //wenn nicht punkteblinken oder dispmode = 0
  if (dispmode != 1) { //wenn nich Datum
  sbi(PORTD,7);
  }else { //bei Datum Punkte aus
  cbi(PORTD,7);
  }
}
tastentesten();
//LED Anzeigen hell-dunkel, wird mittels DDRC 0..6 gesteuert
if ((hours > ledshell)&&(hours < ledsdunkel)) { //helle LEDs von 7 bis 22 Uhr
outp(0xff,DDRC);//Display Ausgänge
}else{
outp(0x80,DDRC);//Display Ausgänge
}
//LEDs für Wecker Ein-Ausschalten
if (((presec > 128) || (wdisabled24 != 2))&&(wleds != 0)) {
  if (wleds == 1) { //LEDs für 24 Std an
   statusleds = (statusleds | 0x02) & 0xfe; //LED für 2 Std aus, LED für 24 an
  }
  if (wleds == 2) { //LEDs für 2 Std an
   statusleds = statusleds | 0x03;
  }
}else{
statusleds = statusleds & 0xfc;//Status LEDs aus
}
}


void savewecktime(u08 weckno) {//speichert eine Weckzeit
//Die Prozedur darf nicht zu häuftig aufgerufen werden, da der interne EEprom
//maximal 100000 Schreibzyklen garantiert
if ((eepromaway == 0)&&(weckno > 0)&&(weckno<maxweckx)) {
wdisabled24 = 0;
weckno *= 4;
eeprom_write_byte((unsigned char *)(weckno -3),whour);
eeprom_write_byte((unsigned char *)(weckno -2),wminute);
eeprom_write_byte((unsigned char *)(weckno -1),wdaysofweek);
eeprom_write_byte((unsigned char *)(weckno*1),wsettings); //wenn weckno für sich stehen würde, gäbe der Compiler eine Warnung aus
eepromaway = 10;
}
}

void getwecktime(u08 weckno) {//liest eine Weckzeit aus dem EEprom
//der AT90S8535 hat 512 Byte EEporm, jede Weckzeit benötigt 4 Byte
//wir wollen 10 Weckzeiten, also 40 Byte werden benötigt
//irgendwo stand mal, das erste Byte könnte sich bei Resets ändern, daher benutze
//ich es sicherhaltshalber lieber nicht
if ((weckno < maxweckx)&&(weckno>0)) {
wselected = weckno;
weckno *=4;
whour = eeprom_read_byte((unsigned char *)(weckno -3));
wminute = eeprom_read_byte((unsigned char *)(weckno -2));
wdaysofweek = eeprom_read_byte((unsigned char *)(weckno -1));
wsettings = eeprom_read_byte((unsigned char *)(weckno*1));
}
}

SIGNAL(SIG_OUTPUT_COMPARE2) { //Setzen der Uhr, ansteuern der LED Anzeige, ist 256 mal pro Sekunde aufzurufen
u08 temp01;
u08 wacktivenonvolatile; //Spart gegenüber der direkten Verwendung von wactive 16 Byte Flash
//damit die Routine, die IR Empfangs Möglichkeit nicht stört, sollte sie möglichst schnell abzuarbeiten sein
outp(0,PORTB); //so sind die LEDs während der Prozedur aus und erscheinen dunkler/nicht ganz so hell
wacktivenonvolatile = wactive;
if ((wacktivenonvolatile >= presec)&&(wacktivenonvolatile != 0)) {
sbi(PORTD,6);
}else {
  cbi(PORTD,6);
}
outp(0x00,PORTB);//alles aus (!!!Überflüssig, da bereits 7 Zeilen vorher PORTB auf Null gesetzt wird, OPTIMIERBAR !!!)
presec++;
temp01 = (presec % 4);
outp(segment[temp01],PORTC);//Den Wert der Ziffer
if (presec == 0) {
seconds++;
if ((wacktivenonvolatile != 0)&&(wacktivenonvolatile < 251)) {
  wacktivenonvolatile += 5;
}
}
fastsample = fastsample + (inp(PIND)&0x04);
//alle 8 Durchläufe wird fastsample überprüft
if ((presec & 0x07) == 0x07) { //wenn unteren 3 Bits = 1
/* fastsample = 64 wenn alle 8 Messungen 1
fastsample = 0 wenn alle 8 Messungen 0
zu beachten ist, dass der inventierte Eingang verwendet wird,
somit 1-> Low Empfangen; 0-> High Empfangen
geändert in Version 5: fastsample < 13
*/
if (fastsample < 13) { //mindestens 5 der 8 Messungen müssen High sein, um ein High als empfangen zu erkennen
currentdcfval = 2; //High Empfangen
}else{
currentdcfval = 1; //Low empfangen
}
fastsample = 0; //noch nichts empfangen
}
wactive = wacktivenonvolatile;
/*
temp01 = 0 -> Bit3 -> Pin4 -> (statusleds<<1) & 0x10
temp01 = 1 -> Bit2 -> Pin4 -> (statusleds<<2) & 0x10
temp01 = 2 -> Bit1 -> Pin4 -> (statusleds<<3) & 0x10
temp01 = 3 -> Bit0 -> Pin4 -> (statusleds<<4) & 0x10
*/
outp((0x01<<temp01) | ((statusleds <<(temp01+1))& 0x10),PORTB);//Welche Ziffer, + unteren 4 Status LEDs (PinB4)
}

SIGNAL(SIG_UART_RECV) {
rs232reinstring[0] = rs232reinstring[1];
rs232reinstring[1] = rs232reinstring[2];
rs232reinstring[2] = rs232reinstring[3];
rs232reinstring[3] = rs232reinstring[4];
rs232reinstring[4] = rs232reinstring[5];
rs232reinstring[5] = inp(UDR);
if (rs232echo == 1) {
  if (bit_is_set(USR,5)){
    outp(rs232reinstring[5],UDR);
  }
}
}

void rs232sendstring(void) {
u08 temp01;
asm volatile("wdr");
rs232rausstring[33] = 10;
rs232rausstring[34] = 13;
for (temp01 = 0;temp01<35;temp01++) {
loop_until_bit_is_set(USR,5);    //wartet, bis der sende Buffer leer ist
outp(rs232rausstring[temp01],UDR);
rs232rausstring[temp01] = 32;//Leerzeichen
}
}

//Größe vor wordtostr :5220
//mit wordtostr: 5282 -> worddtstr (u16) kostet 62 Byte speicher
//bei einer Convertierung von einer Zahl mit 2 Stellen werden 14 Byte Flash gespart
//ändern der Variable Nummer von u16 auf u32 kostet 186 Byte
//jedoch werden durch die Verwendung der Routine zur Konvertierung der uptime 368Byte gespart
//somit spart u32 insgesamt immer noch 182 Byte gegenüber u16
void wordtostr(u32 nummer, u08 digits, u08 strposition) {
while (digits > 0) {
digits--;
rs232rausstring[strposition+digits] = nummer%10+48;
nummer = nummer / 10;
}
}

s16 strtoword(void) {
u08 nun,temp01,therewasinput;
u16 temp02;
temp02 = 0;
therewasinput = 0;
if (rs232reinstring[5] == 0xd) {//Wenn letztes Zeichen ein Enter
for (nun  = 0;nun <5;nun++){
temp01 = rs232reinstring[nun];
if ((temp01 > 47)&&(temp01 < 58)) {//ist Zahl
if (temp02 > 3200) { //eingegebene Zahl wird bei weiterer Eingabe zu groß
therewasinput = 0;
break;
}
temp02 = (temp02*10)+(temp01-48);
therewasinput = 1;
}
rs232reinstring[nun] = 1;//löschen, damit nicht noch mal erkannt
}
}//Ende wenn letztes Zeichen ein Enter
if (therewasinput == 0) {
  return -1;
}
return temp02;
}

//const char ureboot[] PROGMEM = "Uhr reboot: ";
u08 ureboot[] __attribute__ ((section (".eeprom"))) = "Uhr reboot:                         ";
void initsystem( void) { //Der Code zum Starten des MCU
u08 temp01;
asm volatile("wdr");
outp(0x0f,WDTCR);//Aktiviert den Wachdog mit 1,9sec bis zu einem Reset
//outp(0x00,DDRA);//Taster Eingänge, Analog Eingänge, ist am Anfang eh null -> spart 2 Byte Speicher
outp(0x55,PORTA);//Aktiviert die Pullups für die Taster
outp(0x10,DDRB);//Display Ausgänge (Steuerung erfolgt mittels Pullups), Programmier Stecker Eingänge
outp(0xff,DDRC);//Display Ausgänge
outp(0xf2,DDRD);//IR, DCF 77, Lautsprecher, RS232
outp(244,OCR2);//Compare Wert
outp(0x84,TIMSK);//Aktiviert timer1 overfolw interrupts und timer2 compare interrupt
outp(0x0c,TCCR2);//timer2 Prescaler : 64, automatisches Resetten beim Erreichen des Interrupts
outp(0,TCNT2);//timer2 resetten
outp(0,TCNT1H);  //setzt den Timer1 auf null (reset timer1)
outp(0,TCNT1L);  //setzt den Timer1 auf null (reset timer1)
outp(25,UBRR);//Baudraten:  103 -> 2400 Baud; 25 -> 9600 Baud
outp(0x98,UCR);//RS232 Sender aktiviert, RS 232 Empfänger Interupt aktiviert
outp(0xcf,ADCSR);//A/D Converter initialisieren, ADC Frequenz festlegen unt ADC Interrupt aktivieren
//outp(0x50,UDR);//Test Byte Senden
sei();
//strcpy_P(rs232rausstring,ureboot);
strcpyeep(ureboot);
temp01 = inp(MCUSR);
if ((temp01 & 0x01) == 0x01) { //Power on reset
rs232rausstring[13] = 80; //P
}
if (temp01 == 0x02) { //Externer Reset
rs232rausstring[13] = 69; //E
}
if (temp01 == 0) { //Watchdog Reset
rs232rausstring[13] = 87; //W
}
outp(0,MCUSR);
rs232sendstring();
while (inp(ADCSR) & BV(ADSC));//wartet, bis die erste Konvertierung komplett ist (wait until the first conversion is done)
statusleds = 0;
}

void setsegments(void) {//berechnet die Ziffern
const u08 segcodierung[10] = {0x6f,0x28,0x5d,0x79,0x3a,0x73,0x77,0x29,0x7f,0x7b};
u16 temp01;//zu zeigender Wert
u08 ziffera,zifferb;
u08 segtemp1,segtemp2,segtemp3,segtemp4;
u08 faststatusleds; //weil statusleds selbst volatile und zu viel Speicher für das LDS und STS beim direkten Verwenden verbraucht werden würde
faststatusleds = statusleds;
if (dispmode == 1) { //zeige Datum
  ziffera = day;
  zifferb = month;
  faststatusleds = (faststatusleds & 0xf3 ) | 0x08;
}else
if (dispmode == 2) { //zeige Wecker
  ziffera = showwhour;
  zifferb = showwminute;
  faststatusleds = (faststatusleds & 0xf3 ) | 0x04;
}else { //ansonsten zeige Uhr
  ziffera = hours;
  zifferb = minutes;
  faststatusleds = faststatusleds & 0xf3;
}
//Umrechnen
statusleds = faststatusleds; //Zurückschreiben
segtemp1 = faststatusleds & 0x80;
segtemp2 = (faststatusleds*2) & 0x80;
segtemp3 = (faststatusleds*4) & 0x80;
segtemp4 = (faststatusleds*8) & 0x80;
if (ziffera < 100 ) {
temp01 = segcodierung[ziffera/10];
if ((temp01 == 0x6f)&&(dispmode != 1)){ //vorstehende Null entfernen
  temp01 = 0;
}
segtemp1 |= temp01;
segtemp2 |= segcodierung[ziffera%10];
segtemp3 |= segcodierung[(zifferb/10)%10];
segtemp4 |= segcodierung[zifferb % 10];
} else { //Wenn kein Wecker innerhalb der nächsten 24 Std -> Bindestriche anzeigen
  segtemp1 |= 0x10;
  segtemp2 |= 0x10;
  segtemp3 |= 0x10;
  segtemp4 |= 0x10;
}
segment[0] = segtemp1;
segment[1] = segtemp2;
segment[2] = segtemp3;
segment[3] = segtemp4;
}

void updatetime(void) { //Aktualisiert die Zeit durch den Quarz (ohne DCF77)
if (seconds > 59) {
  minutes++;
  uptimeminutes++;
  commtimeoutminutes++;
  seconds = 0;
  wdisabled = 0;
}
if (commtimeoutminutes > commtimeup) { //IR / RS232 Mode verlassen, wenn länger als 15 Minuten aktiv
commtype = 0;
statusleds = statusleds & 0x3f;//status LED für RS232 und IR aus
empfangir = 0xff;//damit der Controller den IR Modus nicht sofort wieder aktiviert
}
if (commtype == 0) {
  commtimeoutminutes = 0;
}
if (minutes > 59) {
  hours++;
  minutes = 0;
}
if (hours > 23) {
  dayofweek++;
  day++;
  hours = 0;
}
if (day > 31) {
  month++;
  day = 1;
}
if (month > 12) {
  year++;
  month = 1;
}
if (dayofweek > 7) {
  dayofweek = 1;
}
}

//const char linielang[] PROGMEM = "---------------------------------";
//const char zeitmaske[] PROGMEM = "Zeit: xx xx:xx Datum: xx.xx.xxxx";
u08 linielang[] __attribute__ ((section (".eeprom"))) = "---------------------------------";
u08 zeitmaske[] __attribute__ ((section (".eeprom"))) = "Zeit: xx xx:xx Datum: xx.xx.xxxx";
void newscreen(void) {
const char wochentage[] = "MoDiMiDoFrSaSo";
  rs232sendstring();
  //strcpy_P(rs232rausstring,linielang);
  strcpyeep(linielang);
  rs232sendstring();
  //strcpy_P(rs232rausstring,zeitmaske);
  strcpyeep(zeitmaske);
  wordtostr(hours,2,9);
  wordtostr(minutes,2,12);
  wordtostr(day,2,22);
  wordtostr(month,2,25);
  wordtostr(year,4,28);
  rs232rausstring[6] = wochentage[(dayofweek-1)*2];
  rs232rausstring[7] = wochentage[(dayofweek-1)*2+1];
  rs232sendstring();
  rs232sendstring();
}

//const char menu111[] PROGMEM = "Wecker xx xx:xx MoDiMiDoFrSaSo O";
u08 menu111[] __attribute__ ((section (".eeprom"))) = "Wecker xx xx:xx MoDiMiDoFrSaSo O";
void makewstatus(u08 weckno) {
u08 temp01;
//strcpy_P(rs232rausstring,menu111);
strcpyeep(menu111);
wordtostr(weckno,2,7);
wordtostr(whour,2,10);
wordtostr(wminute,2,13);
for (temp01 = 0;temp01<7;temp01++) {       //spart gegenüber 7 Einzelanweistungen 46 Byte
if ((wdaysofweek & (0x80>>temp01)) ==0) {//tage mit -- erstetzen
rs232rausstring[16+temp01*2] = 45;
rs232rausstring[17+temp01*2] = 45;
}
}
if (wsettings == 1) { //Einmalig
rs232rausstring[31] = 69;
}
if (wsettings == 2) { //Multiple/Mehrmalig
rs232rausstring[31] = 77;
}
}

//Menu Variablen müssen leider global sein, sonst wird PROGRMEM ignoriert und das wäre fatal
const char menu500[] PROGMEM = "2.Config";
const char menu501[] PROGMEM = "1 Uhrzeit";
const char menu502[] PROGMEM = "2 Tag";
const char menu503[] PROGMEM = "3 Monat";
const char menu504[] PROGMEM = "4 Jahr";
const char menu505[] PROGMEM = "5 RS232 Echo";
const char menu506[] PROGMEM = "6 Punkte blinken";
const char menu507[] PROGMEM = "9 Hauptmenu";
const char menu510[] PROGMEM = "2.1 Uhrzeit eingeben (hh:mm)";
const char menu520[] PROGMEM = "2.2 Tag(1..31) eingeben";
const char menu530[] PROGMEM = "2.3 Monat(1..12) eingeben";
const char menu540[] PROGMEM = "2.4 Jahr(0..31999) eingeben";
const char menu550[] PROGMEM = "2.5 RS232 Echo (1:An, 2:Aus)";
const char menu560[] PROGMEM = "2.6 Punkte blinken (1:An, 2:Aus)";
const char menu10[] PROGMEM = "Hauptmenu";
const char menu11[] PROGMEM = "1 Wecker";
const char menu12[] PROGMEM = "2 Config";
const char menu13[] PROGMEM = "3 A/D Wandler";
const char menu14[] PROGMEM = "9 Beenden";
const char menu15[] PROGMEM = "Uhr Uptime: xxxxxxxx Minuten";
const char menu01[] PROGMEM = "Well, I suggest you to sleep";
const char menu02[] PROGMEM = "Bye, have a nice day";
const char menu03[] PROGMEM = "Bye Bye, and enjoy the day";
const char menu04[] PROGMEM = "I wish you a nice evening";
const char menu05[] PROGMEM = "You can sleep, I must work";
const char menu1000[] PROGMEM = "3. A/D Wandler";
const char menu1001[] PROGMEM = "1 Werte erneut einlesen";
const char menu1002[] PROGMEM = "9 Hauptmenu";
const char menu1003[] PROGMEM = "Wandler: x Wert: ";//ursprünglich "Wandler: x Wert: xxxx", xxxx wurde jedoch weggenommen um Flash zu sparen
const char menu100[] PROGMEM = "1. Weckzeiten";
const char menu101[] PROGMEM = "1 Wecker uebersicht";
const char menu102[] PROGMEM = "2 Wecker bearbeiten";
const char menu103[] PROGMEM = "9 Hauptmenu";
const char menu110[] PROGMEM = "1.1 Weckzeiten Uebersicht";
const char menu1200[] PROGMEM = "Wecker (1-10) auswaehlen";
const char menu1210[] PROGMEM = "Wecker xx : Zeit eingeben (hh:mm)";
const char menu1220[] PROGMEM = "1-7: Aktiver Wochentag, 9: Weiter";
const char menu1230[] PROGMEM = "Wecker Aktiv Modus";
const char menu1231[] PROGMEM = "1: Einmalig, 2: Merhmals, 3: Aus";
const char menu1232[] PROGMEM = "9: Abbruch, nicht Speichern";
const char menu1240[] PROGMEM = "Neue Weckzeit gesetzt";

//Strings für IR Menü

const char* fullmenu[] = {menu01  ,menu02  ,menu03  ,menu04  ,menu05  ,                            //0..4
                          menu10  ,menu11  ,menu12  ,menu13  ,menu14  ,menu15 ,                    //5..10
                          menu100 ,menu101 ,menu102 ,menu103 ,                                     //11..14
                          menu110 ,                                                                //15
                          menu500 ,menu501 ,menu502 ,menu503 ,menu504 ,menu505 ,menu506 ,menu507,  //16..23
                          menu510 ,menu520 ,menu530 ,menu540 ,menu550 ,menu560 ,                   //24..29
                          menu1000,menu1001,menu1002,menu1003,                                     //30..33
                          menu1200,menu1210,menu1220,menu1230,menu1231,menu1232,menu1240};         //34..40


void strcpypandsend(u08 startstring, u08 numofstrings) {
u08 temp;
temp = 0;
while (temp < numofstrings){
strcpypshort(startstring+temp);
//strcpy_P(rs232rausstring,fullmenu[startstring+temp]);
rs232sendstring();
temp++;
}
}

void strcpypshort (u08 stringno) { //Benötigt 24 Byte, jeder Aufruf spart jedoch 6 Byte gegenüber strcpy_P. Ab 5 aufrufen, wurde Platz gespart
strcpy_P(rs232rausstring,fullmenu[stringno]);
}

void show232menu(void) {
u08 temp01;
//Menu anzeigen
if (newmenu == 1){
newmenu = 0;
if (submenu232 == 24) {//Wecker zu ende eingestellt
rs232sendstring();
strcpypandsend(40,1);
getwecktime(wselected);
makewstatus(wselected);
rs232sendstring();
}
if (submenu232 == 23) {//Wecker aktivieren
strcpypandsend(37,3);
}
if (submenu232 == 22) { //Wochentage auswählen
makewstatus(wselected);
rs232sendstring();
strcpypandsend(36,1);
}
if (submenu232 == 21) { //Weckzeit eingeben, Wecker gewählt
strcpypshort(35);
wordtostr(wselected,2,7);
rs232sendstring();
}
if (submenu232 == 20) { //Wecker auswählen
rs232sendstring();
strcpypandsend(34,1);
}

if (submenu232 == 11) { //alle Weckzeiten anzeigen
newscreen();
strcpypandsend(15,1);
rs232sendstring();
//Schleife zum Anzeigen des Weckers
for (temp01=1;temp01<maxweckx;temp01++) {
getwecktime(temp01);
makewstatus(temp01);
rs232sendstring();
}
rs232sendstring();
strcpypandsend(12,3);
}
if (submenu232 == 10) {//Wecker Hauptmenu
newscreen();
strcpypandsend(11,1);
rs232sendstring();
strcpypandsend(12,3);
}
if (submenu232 == 100) {//A/D Werte anzeigen
newscreen();
strcpypandsend(30,1);
rs232sendstring();
for (temp01  = 0;temp01 <8;temp01++){
strcpypshort(33);
rs232rausstring[9] = temp01+48;
wordtostr(adwerte[temp01],4,17);
rs232sendstring();
}
rs232sendstring();
strcpypandsend(31,2);
}//ende A/D Wandler
if (submenu232 == 50) { //config
newscreen();
  strcpypandsend(16,1);
  rs232sendstring();
  strcpypandsend(17,7);
}
if ((submenu232 > 50)&&(submenu232 <57)) { //Wenn config-Untermenu ausgewählt wurde
newscreen();
strcpypandsend(submenu232-27,1);
}
if (submenu232 == 1) {//Hauptmenu
newscreen();
strcpypandsend(5,1);
rs232sendstring();
strcpypandsend(6,4);
rs232sendstring();
strcpypshort(10);
/* die verwendete Anzeige ist 8 stellig, das entspricht ungefähr:
195 Jahre !!!
und der interne Zähler kann noch einiges mehr zählen,
nämlich so ungefähr eine Uptime von 8378 Jahren....
*/
wordtostr(uptimeminutes,8,12);
rs232sendstring();
}
if (submenu232 == 0) {//goodbye
temp01 = 0;
if (hours > 4) {
  temp01++;
}
if (hours > 10) {
  temp01++;
}
if (hours > 16) {
  temp01++;
}
if (hours > 21) {
  temp01++;
}
strcpypandsend(temp01,1);
}
}//ende neues Menu
}

void rs232com(void){
s16 eingabe;
u08 temp01,temp02;
/*Menü Struktur
Passwort: 1234
1 Auswahl
1.1 Wecker
1.1.1 Übersicht anzeigen
1.1.2 Wecker setzen
1.1.2.1 Wecker auswählen
1.1.2.1.1 Zeit setzen
1.1.2.1.2 Wochentage setzen
1.1.2.1.3 Wiederholung setzen/aus
1.1.9 Zurück zum Hauptmenu
1.2 Config
1.2.1 Zeit setzen
1.2.2 Tag setzen
1.2.3 Monat setzen
1.2.4 Jahr setzen
1.2.5 Rs232 Echo
1.2.6 Punkte Blinken
1.2.9 Zurück zum Hauptmenu
1.3 A/D Ports lesen
1.3.1 A/D Werte erneut einlesen
1.3.9 Zurück zum Hauptmenu
1.9 RS232 Sitzung beenden
*/
statusleds = statusleds | 0x80;//RS232 aktiv
eingabe = strtoword();
//Menu Berechnen
if (submenu232 == 24) {
submenu232 = 10;
newmenu = 1;
}
if (submenu232 == 23) {//Wecker aktiv Modus auswählen
if (eingabe == 9) { //Abbruch
eingabe = -1;
submenu232 = 10;
newmenu = 1;
}
if (eingabe == 3) {
eingabe = -1;
submenu232 = 24;
newmenu = 1;
savewecktime(wselected);
}
if ((eingabe == 1)||(eingabe == 2)) {
wsettings = eingabe;
eingabe = -1;
submenu232 = 24;
newmenu = 1;
savewecktime(wselected);
}
}
if (submenu232 == 22) {//Wochentage auswählen
if (eingabe == 9) {
eingabe = -1;
submenu232 = 23;
newmenu = 1;
}
if ((eingabe > 0) && (eingabe < 8)){//Wochentag aktivieren
newmenu = 1;
wdaysofweek = wdaysofweek | (0x80>>(eingabe-1));
}
}
if (submenu232 == 20) { //Auswahl des Weckers
if ((eingabe > 0) && (eingabe < maxweckx)) {
getwecktime(eingabe);
eingabe = -1;
submenu232 = 21;
newmenu = 1;
}
}
if (submenu232 == 21) { //Weckzeit einstellen
if (eingabe > -1) {
temp01 = eingabe/100;
temp02 = eingabe % 100;
eingabe = -1;
submenu232 = 22;
newmenu = 1;
if (temp01 < 24) {
  whour = temp01;
}
if (temp02 <60) {
  wminute = temp02;
}
wdaysofweek = 0;
wsettings = 0;
}
}
if ((submenu232 == 10)||(submenu232 == 11)) { // Wecker
if (eingabe == 2) {//Wecker setzen, Part 1
submenu232 = 20;
newmenu = 1;
}
if (eingabe == 9) {//zurück
  submenu232 = 1;
  newmenu = 1;
}
if (eingabe == 1) { //Übersicht
submenu232 = 11;
newmenu = 1;
}
eingabe = -1;
}

  
if (submenu232 == 1) { //1 Auswahl
if (eingabe == 1) {//Wecker
submenu232 = 10;
newmenu = 1;
}
if (eingabe == 2) {//dann Config
submenu232 = 50;
newmenu = 1;
}
if (eingabe == 3) {//dann A/D Wandler
submenu232 = 100;
newmenu = 1;
}
if (eingabe == 9) {//RS232 verlassen
submenu232 = 0;
newmenu = 1;
commtype = 0;
statusleds = statusleds & 0x7f;//status LED für RS232 aus
}
eingabe = -1;
}//ende auswahl
if (submenu232 == 100) {//A/D Wandler Werte
if (eingabe == 1) {//nochmal anzeigen
newmenu = 1;
}
if (eingabe == 9) {//Zurück
newmenu = 1;
submenu232 = 1;
}
eingabe = -1;
}
if (submenu232 == 50) {// Config
if ((eingabe > 0)&&(eingabe <7)) { // Uhrzeit, Tag,Monat,Jahr,RS232 Echo, Punkte blinken
submenu232 += eingabe;
newmenu = 1;
}
if (eingabe == 9) {//Zurück
submenu232 = 1;
newmenu = 1;
}
eingabe = -1;
}//ende config
if (eingabe > -1) { //Untermenu bei Config ausgewählt, jetzt Eingabe der Werte
if (submenu232 == 51) { //Uhrzeit
temp01 = eingabe/100;
temp02 = eingabe % 100;
if (temp01 < 24) {
  hours = temp01;
}
if (temp02 <60) {
  minutes = temp02;
  wdisabled = 0;
}
}
if (eingabe > 0) { //Damit nicht Tag/Monat Null
if (submenu232 == 52) { //Tag
if (eingabe < 32) {
  day = eingabe;
}
}
if (submenu232 == 53) { //Monat
if (eingabe < 13) {
  month = eingabe;
}
}
if (eingabe < 3) {
if (submenu232 == 55) { //RS232 Echo
  rs232echo = 2-eingabe;
}
if (submenu232 == 56) { //Punkte blinken
punkteblinken = 2-eingabe;
}
}
}//ende damit nicht Tag/Monat Null
if (submenu232 == 54) { //Jahr
year = eingabe;
}

if ((submenu232 > 50)&&(submenu232 < 57)) {
submenu232 = 50;
newmenu = 1;
}
eingabe = -1;
}
show232menu();
}

void warte(u16 zeit) { //warte 2857~20ms
warteschleife = 0;
while (warteschleife < zeit){
  warteschleife++;
}
}

void sendirstring(void) {
u08 temp01,sendstringpos,sendcursorpos;
warte(60000);
if ((submenuir < 21) || (submenuir > 23)) { //in diesem Fall ist mehr als ein Tastendruck nur störend
empmode = 0;
empfangir = 0xff;
}
if (empmode == 0) {
outp(0,TCCR1B);
sendstringpos = 0;
sendcursorpos = 0;
if (submenuir == 20) {
  sendstringpos = 2;
}
if (submenuir == 21) {
  sendstringpos = 6;
}
if (submenuir == 22) {
  sendstringpos = 9;
}
if (submenuir == 23) {
  sendstringpos = 14;
}
sendcursorpos = sendstringpos;
if ((submenuir > 23)&&(submenuir < 31)) { //Wochentage
  sendstringpos = (submenuir-24)*2+16;
  sendcursorpos = sendstringpos +64-16;//weil 2.Zeile
}

if (lcdupdatecomplexity == 2) {
zumsenden(136);//return home
for (temp01 = 0;temp01<32;temp01++) {
zumsenden(rs232rausstring[temp01]);
if (temp01 == 15) { //zweite Zeile
zumsenden(0xd);
}
}
}
if (lcdupdatecomplexity == 1) { //nur die nötigen zwei Byte senden
zumsenden(rs232rausstring[sendstringpos]);
zumsenden(rs232rausstring[sendstringpos+1]);
}
//Cursor an/aus
if ((submenuir == 31)||(submenuir == 1)) {  //bei submenuir == 31 || 1 -> Cursor aus
zumsenden(129);
}else {
zumsenden (128);
}
//Platziere Cursor, für mehr Übersichtlichkeit
if ((submenuir > 19)&&(submenuir < 31)) {
  zumsenden((256*2)+128+sendcursorpos);
}

outp(1,TCCR1B);
}//Ende empmode == 0
}


//const char uhrzeit[] PROGMEM = "  :     .  .    End Upd.  Wecker";
//const char weckerma[] PROGMEM = "W xx: hh:mm   O MoDiMiDoFrSaSo  ";
//const char saveweck[] PROGMEM = "Wecker xx: Save?Ja Nein   Zurück";
u08 uhrzeit[] __attribute__ ((section (".eeprom"))) =  "  :     .  .    End Upd A/D Weck";
u08 weckerma[] __attribute__ ((section (".eeprom"))) = "W xx: hh:mm   O MoDiMiDoFrSaSo  ";
u08 saveweck[] __attribute__ ((section (".eeprom"))) = "Wecker xx: Save?Ja Nein   Zurück";
u08 showad[] __attribute__ ((section (".eeprom"))) =   "P1:xxxx P2:xxxx Update    Zurück";

void showirmenu(void) {
u08 temp01;
if (submenuir == 1) {//zeige Uhrzeit + Datum und Wochentag
//hh:mm dd.mm.yyyy
strcpyeep(uhrzeit);
//strcpypshort(41);
wordtostr(hours,2,0);
wordtostr(minutes,2,3);
wordtostr(day,2,6);
wordtostr(month,2,9);
wordtostr(year,4,12);
}
if ((submenuir > 19)&&(submenuir < 31)) {//Wecker auswahl
//W xx: hh:mm   0 MoDiMiDoFrSaSo
if (submenuir == 20) {
getwecktime(wselected);
}
strcpyeep(weckerma);
//strcpypshort(42);
wordtostr(wselected,2,2);
wordtostr(whour,2,6);
wordtostr(wminute,2,9);
for (temp01 = 0;temp01<7;temp01++) {       //spart gegenüber 7 Einzelanweistungen 46 Byte
if ((wdaysofweek & (0x80>>temp01)) ==0) {//Tage mit -- erstetzen
rs232rausstring[16+temp01*2] = 45;
rs232rausstring[17+temp01*2] = 45;
}
}
if (wsettings == 1) { //Einmalig
rs232rausstring[14] = 69;
}
if (wsettings == 2) { //Multiple/Mehrmalig
rs232rausstring[14] = 77;
}
}

if (submenuir == 31) { //Weckzeit speichern?
  //strcpypshort(43);
  strcpyeep(saveweck);
wordtostr(wselected,2,7);
}
if (submenuir == 50) { //A/D Wandler anzeigen
strcpyeep(showad);
wordtostr(adwerte[1],4,3);
wordtostr(adwerte[3],4,11);
}
sendirstring();
newmenu = 0;
}

void ircom(void) {
/*Menü Struktur
0. Verlassen
1.Zeit anzeigen
20. Wecker anzeigen/auswählen
21 Std stellen
22 Min stellen
23 Mode stellen
24 Mo stellen
25 Di stellen
26 Mi stellen
27 Do stellen
28 Fr stellen
29 Sa stellen
30 So stellen
31 speichern
50 zeige A/D Wandler
*/
u08 empfangir2; //unterschied: die Variable muss gegenüber empfangir nich volatile sein, so dass die Codeoptimierung besser arbeiten kann
empfangir2 = empfangir;
empfangir = 0xff;
statusleds = statusleds | 0x40;//IR aktiv
if (empfangir2 == 0xff) {
  return;
}
//empmode = 2;
empfangir2 = empfangir2 & 0x3c; //extrahiere Tasten
if (submenuir == 0) { //IR Mode betreten
  submenuir = 1;
  newmenu = 1;
  empfangir2 = 0xff;
  lcdupdatecomplexity = 2;
}
if (submenuir == 1) {
if (empfangir2 == 0x20) {//Verlasse IR Modus
commtype = 0;
statusleds = statusleds & 0x3f;//status LED für RS232 und IR aus
submenuir = 0;
}
if (empfangir2 == 0x10) {//Refresh
newmenu = 1;
lcdupdatecomplexity = 2;
}
if (empfangir2 == 0x08) {//Gehe zu Wecker Menu
submenuir = 20;
newmenu = 1;
lcdupdatecomplexity = 2;
}
if (empfangir2 == 0x04) {// A/D Wandler zeigen
submenuir = 50;
newmenu = 1;
lcdupdatecomplexity = 2;
}
empfangir2 = 0xff;
}
if (submenuir == 50) { // A/D Wandler Menu
  if (empfangir2 == 0x20) { //Update
    newmenu = 1;
    lcdupdatecomplexity = 2;
  }
  if (empfangir2 == 0x08) { //Zurück
    submenuir = 1;
    newmenu = 1;
    lcdupdatecomplexity = 2;
  }
  empfangir2 = 0xff;
  }
if (submenuir == 20) {//Wenn Weckermode
if (empfangir2 == 0x20) {//gehe zurück
submenuir = 1;
newmenu = 1;
lcdupdatecomplexity = 2;
}
if (empfangir2 == 0x10) {//Wecker stellen
submenuir = 21;
newmenu = 1;
lcdupdatecomplexity = 0;
}
if (empfangir2 == 0x08) {//vorherigen Wecker
wselected--;
if (wselected == 0) {
  wselected = maxweck;
}
newmenu = 1;
lcdupdatecomplexity = 2;
}
if (empfangir2 == 0x04) {//nächster Wecker
wselected++;
if (wselected == maxweckx) {
  wselected = 1;
}
newmenu = 1;
lcdupdatecomplexity = 2;
}
empfangir2 = 0xff;
}
if ((submenuir > 20) &&(submenuir < 31)) {
  if (empfangir2 == 0x20) {
    submenuir--;
    lcdupdatecomplexity = 0;
  }
  if (empfangir2 == 0x10) {
    submenuir++;
    lcdupdatecomplexity = 0;
  }
  if (submenuir == 21) {//Studen stellen
  if (empfangir2 == 0x08) {
    whour--;
    lcdupdatecomplexity = 1;
  }
  if (empfangir2 == 0x04) {
    whour++;
    lcdupdatecomplexity = 1;
  }
  }
  if (submenuir == 22) {//Minuten stellen
    if (empfangir2 == 0x08) {
    wminute--;
    lcdupdatecomplexity = 1;
    }
    if (empfangir2 == 0x04) {
    wminute++;
    lcdupdatecomplexity = 1;
    }
  }
  if (submenuir > 22) {//gehe zum Speicher-menu
  if (empfangir2 == 0x08) {
  submenuir = 31;
  lcdupdatecomplexity = 2;
  }
  }
  if (submenuir == 23) { //aus, einfach, mehrfach wählen
  if (empfangir2 == 0x04) {
    wsettings++;
    lcdupdatecomplexity = 1;
  }
  }
  if (submenuir > 23) { //Wochentage an/abwählen
  if (empfangir2 == 0x04) {
    lcdupdatecomplexity = 1;
    wdaysofweek = wdaysofweek ^ (0x1<<(31-submenuir)); //Toggelt das betreffende Bit
    }
  }
  if (whour == 255) {
    whour = 23;
  }
  if(whour == 24) {
    whour = 0;
  }
  if (wminute == 255) {
    wminute = 59;
  }
  if (wminute == 60) {
    wminute = 0;
  }
  if (wsettings > 2) {
    wsettings = 0;
  }
  newmenu = 1;
  empfangir2 = 0xff;
}
if (submenuir == 31) { //Speichern
  if (empfangir2 == 0x20) { //Ja, speichern
    savewecktime(wselected);
    submenuir = 20;
  }
  if (empfangir2 == 0x10) { //Nein, nicht speichern
    submenuir = 20;
  }
  if ((empfangir2 == 0x08)||(empfangir2 == 0x04)) { //zurück
    submenuir = 21;
  }
  empfangir2 = 0xff;
  newmenu = 1;
  lcdupdatecomplexity = 2;
}
    
//empmode = 0;
}

void analyzedcf77(void) {
const u08 dcffaktor[8] = {1,2,4,8,10,20,40,80};
/*
Globale Variablen, die in dieser Prozedur besonders wichtig sind
u08 volatile currentdcfval;
u08 lastdcfval; //um festzustellen, ob sich der pegel gändert hat
u08 lastuptime,lastdowntime;//zur bestimmung, ob 0,1 oder neue minute
u08 dcfposition = 70;   //70 = nicht syncron
u08 checkbits;
currentdcfval wird 31 mal pro sec aktualisiert
wenn currentval = 0 -> noch keine neuen Daten
wenn currentval = 1 -> low empfangen
wenn currentval = 2 -> high empfangen
-> 2-4 mal high, so wurde eine Null empfangen
-> 5-8 mal high, so wurde eine Eins empfangen
-> 30-64 mal Null empfangen, es fängt eine neue Minute an

warte darauf, dass currentval = 2 wird, während dieser Warteperiode, wird lastdowntime++ gerechnet
*/
//Warte, bis ein Signal empfangen werden kann
lastdowntime = 0;
while (currentdcfval < 2){ //solange keine 1
lastdowntime++;
currentdcfval = 0;
if (lastdowntime > 64) { //es ist ein Fehler aufgetreten, kein DCF Signal
break;
}
while (currentdcfval == 0) {
  smallnottimecriticalcode();
  
}
}
//nun warte, bis die Eins zu ende empfangen wurde
if (lastdowntime < 65) {//wenn nicht durch Abbruch verlassen wurde
lastuptime = 0;
while (currentdcfval != 1){ //solange keine 0
lastuptime++;
currentdcfval = 0;
if (lastuptime > 8) { //es ist ein Fehler aufgetreten, kein DCF Signal
break;
}
while (currentdcfval == 0) {
  smallnottimecriticalcode();
}
}
if ((lastuptime < 9)&&(lastuptime > 1)) { //weder lastdowntime, noch lastuptime zeigen Anzeichen für Fehler
//beginne Signalauswertung
if (lastdowntime > 30) { //neue Minute
//logische Überprüfung und setze Uhr
if ((checkbit == 0)&&(rminutes[0] < 60)&&(rhours[0] < 24)&&(rdayofweek[0] > 0)&&(rdayofweek[0] < 8)&&(rmonth[0]>0)&&(rmonth[0]<13)&&(rday[0]<32)){
statusleds = statusleds & 0xef; //Fehler LED aus
if (seconds > 30) {
minutes++;
uptimeminutes++;
wdisabled = 0;
}
seconds = 0;
//zuerst wurde nur die zu setzende Variable überprüft, jetzt müssen alle Variablen überprüft werden, dürfte die Wahrscheinlichkeit eines Fehlers nochmal reduzieren
if (rminutes[0]==(rminutes[1]+1))  {
if (rhours[0] == rhours[1]) {
if (rdayofweek[0] == rdayofweek[1]){
if (rday[0] == rday[1]) {
if (rmonth[0] == rmonth[1]){
if (ryear[0] == ryear[1]) {
minutes = rminutes[0];
wdisabled = 0;
hours = rhours[0];
dayofweek = rdayofweek[0];
day = rday[0];
month = rmonth[0];
year = year/100*100+ryear[0];//Da DCF77 Angaben nur zweistellig, Uhr aber 4 Stellige Jahreszahlen hat
}
}
}
}
}
}
// UDR = rminutes[2];
rminutes[1] = rminutes[0];
rhours[1] = rhours[0];
rdayofweek[1] = rdayofweek[0];
rday[1] = rday[0];
rmonth[1] = rmonth[0];
ryear[1] = ryear[0];
}//Ende logische Prüfung bestanden
rminutes[0] = 0;
rhours[0] = 0;
rdayofweek[0] = 0;
rday[0] = 0;
rmonth[0] = 0;
ryear[0] = 0;
dcfposition = 0;
checkbit = 0;
}
//Auswerten der Bits, während einer Minute
if (dcfposition <61) {//wenn dcfposition innerhalb der Toleranzen
dcfposition++;
if (lastuptime > 4) { //Eins empfangen
//mit swich code: 5728 Byte
//mit if code: 5586 Byte  -> 142 Byte gespart
/* Auswertung der Prüfbits
Die getesteten Bits zusammen mit dem Prüfbit ergeben immer eine grade Anzahl von High Bits
dcfposition = 29: 1. Prüfbit, bezieht sich nur auf die Minuten
dcfposition = 36: 2. Prüfbit, bezieht sich nur auf die Stunden
dcfposition = 59: 3. Prüfbit, bezieht sich auf Tage, Wochentage, Monate und Jahre
wenn am Ende des Durchlaufes checkbit gleich null, ist entweder kein oder mehr als ein Fehler aufgetreten
*/
if ((dcfposition > 21) &&(dcfposition < 29)){ //Minuten
rminutes[0] += dcffaktor[dcfposition-22];
}
if ((dcfposition > 21) &&(dcfposition < 30)){ //Checkbit 1
checkbit = 1-checkbit;
}
if ((dcfposition > 29) &&(dcfposition < 36)){ //Stunden
rhours[0] += dcffaktor[dcfposition-30];
}
if ((dcfposition > 29) &&(dcfposition < 37)){ //Checkbit 2
checkbit = 4-checkbit;
}
if ((dcfposition > 36) &&(dcfposition < 43)){ //Tage
rday[0] += dcffaktor[dcfposition-37];
}
if ((dcfposition > 42) &&(dcfposition < 46)){ //Wochentag
rdayofweek[0] += dcffaktor[dcfposition-43];
}
if ((dcfposition > 45) &&(dcfposition < 51)){ //Monat
rmonth[0] += dcffaktor[dcfposition-46];
}
if ((dcfposition > 50) &&(dcfposition < 59)){ //Jahr
ryear[0] += dcffaktor[dcfposition-51];
}
if ((dcfposition > 36) &&(dcfposition < 60)){ //Checkbit 3
checkbit = 16-checkbit;
}
}else{
if (dcfposition == 21) {//Dieses Bit ist normalerweise immer High, wenn dies aufgerufen wird, liegt ein Fehler vor
dcfposition = 70;
}
}
//Statusbit für Fehler setzen
}//ende DCF Position korrekt
}else{
dcfposition = 70;
}  //ende Signale fehlerfrei
}else{//ende downtime fehlerfrei
dcfposition = 70;
}
if (dcfposition > 60) {
statusleds = statusleds | 0x10;//fehlerhaftes Signal
}
}

int main( void ){
u08 temp01;
initsystem();
for (;;) {
asm volatile("wdr");
updatetime();
setsegments();
smallnottimecriticalcode();
testallwecker();
//zumsenden(0xf0);//Sendet ein Test-Zeichen; 72 wäre ein H für Hallo
if (eepromaway > 0) { //Das EEprom kann nur beschrieben werden, wenn die Variable null ist
  eepromaway--;//dies ist eine Sicherheitsvorkehrung
}

if (commtype == 0) {
analyzedcf77();
statusleds = statusleds | 0x20;//DCF Aktiv  (Optimierbar ???)
  if (strtoword() == 1234){
  for (temp01 = 0;temp01<36;temp01++) { //sonst könnten sich in dem String noch Reste vom IR Senden befinden
    rs232rausstring[temp01] = 32;
  }
  statusleds = statusleds & 0xdf;//DCF inaktiv
  commtype = 1;
  submenu232 = 1;
  newmenu = 1;
}
if (empfangir != 0xff){
if (wactive != 0) {
  wactive = 0;
  wdisabled = 1;
  empfangir = 0xff;
} else { //Starte IR Kommunikation
  statusleds = statusleds & 0xdf;//DCF inaktiv
  commtype = 2;
  submenuir = 0;
  newmenu = 1;
  getwecktime(1);
}
}
}

if (commtype == 1) {
outp(0,TCCR1B);  //stopp timer1, IR Empfang
rs232com();
dcfposition = 70;
} else {
  outp(1,TCCR1B);  //startet timer1, IR Empfang aktiv
}
if (commtype == 2) {
  ircom();
  if (newmenu == 1) {
  showirmenu();
  }
dcfposition = 70;
}

}
}

//End of File
