/*  AVRTel20a.c                            5.5.2007 	
*   Erste Überarbeitetung nach Neuanfang 2007 
*	war vormals AVRTel14.c    Jetzt mit AVR-Dragon-JTAG

*	Bemerkungen:
*	Mit neuem WinAVR (20070122) ließ sich das Programm nach etwas
*	Bereinigung einige Male kompilieren und ausführen.
*	Ergebnis:
*	LCD-Ausgabe fkt. nicht mehr (Schriftzüge überlagern sich, 
*	Ctrl-Befehle (clear Displ., Zeilenanf)  fkt. nicht).
* 	Bei Sprachausgabe nur noch Anfangspuls zu hören; 

*	Wahrscheinlich sind deprecatete Bitmanipulationen enthalten?

*	Nach Versuchen mit einigen älteren WinAVR-Versionen geht nun
* 	auch mit WinAVR20070122 nichts mehr: Fehlermeldungen (multiple
*	Funktionsdefinitionen ...) 
*	


*   AVRTel12.c                       27.7.2004
*	Versuch, das Telefon zu bedienen.
*	Abfrage von echtem RVLC 
*	(das vorher nicht mehr selbst gesetzt wurde),
*	danach LC = 1 (=Abheben), signalisiert durch LED am Testboard. 
*
*	AVRTel11.c
*	Akustische Ausgabe von Text eingerichtet. 
*	ISD-Probleme: 
*	Das Weitertakten dauert ziemlich lange,
*	ohne die Verzögerung durch errorpcf geht es nicht;
*	Für die Sprachausgabe muß CE so lange low sein, wie die 
* 	Ausgabe dauert 
*	Achtung:
*	Es gibt errorpcf's und manchmal sind 2-3 Startversuche nötig.

*	Todo:
*	PCF-Adressen testen
*	globale Variable ersetzen
*	bessere Kontrollroutinen
*	Variablendefinitionen (Zahlen stimmen nicht)
*	Zeitschleifen verschönern   10 100 1000 ms
*	TWIN-Bezeichnungen ändern (TW_MT_SLA_ACK ....)
*	Telefonabfrage
*	akustische Ausgabe
*	Speicherung im EEPROM
*
*	Errors einprägsamer definiert:                  
*	error       LED's 4 und 8 blinken dreimal lang  LED 1
*	errorpcf    LED 8  blinkt 6 mal kurz            LED 8
*	kontrolle   LED 2  blinkt dreimal kurz          LED 2

*   Anschluß der LED's:
*   Angeschlossen an der Knightbridgeleist sind nur vier der 12 LED's:
*	ganz links PORTD0=1, ganz rechts PORTD3=8


* 	PORTC=3 scheint unverzichtbar zu sein, DDRC=3 hilft nicht.
*	PORTD=1-Problem: wird durch errorpcf() verursacht,
*	wenn nicht,dann Abhilfe mit DDRD=1 (Port als Ausgang)
*
*	Notizen:
*	Manipulation einzelner Pins, ohne 
*	den restlichen Port zu beeinflussen:
*	PORTD  |= 4;   Pin 4 wird eingeschaltet,
*	PORTD &= 251;  Pin 4 wird ausgeschaltet,
*	der Rest bleibt unberührt.
*	Funktionierende Abfrage eines Ports:
*	if ( wahr ) dann {...}
*	if ( PINB &= 64) {wird ausgeführt, wenn gesetzt}
*	if ( !(PINB &= 64)) {wird ausgeführt, wenn   n i c h t  gesetzt}


*/

#include <C:/Progr-MCU/WinAVR070122/avr/include/avr/io.h>				 	
#include <C:/Progr-MCU/WinAVR070122/avr/include/util/twi.h>
#include <inttypes.h>  /* io.h ist in twi.h enthalten */
#include <stdio.h>     /* ATmegaspezifische Defin. sind in iom16.h */
                       /* iom16.h muß in io.h eingebunden sein. */
/* #include <stdlib.h> */
/* #include <math.h> */
/* #include <avr/sfr_defs.h> */
/* #include <avr/interrupt.h> */

/* #define debug 0 */ 

unsigned long int k,i,l,n; 
/* unsigned char n=1; */
/* char a; */


/* ++++++++++++++ PCF-Zubehör +++++++++++++++++ */
/* PCF-Adressen:
*	120 = 0x78 auf I/O-Platine 300104 (PCF unten für LCD 8bit) 
*   114                  (oben, z.Zt. nicht bestückt)
*	126 = 0x7E auf Teich-I/O-161099 (für STM-Umschalter HCF4066)
*   114 = 0x72 auf Testboard
*	122 = 0x   auf Teich-I/O-161099 (für Anzeige-LED's)        
*	116		   auf AVR-Basis x0104
*	 76   ??   auf Sound 2
*/
void pause(void)
	{ 
		k=1000;              /* bei 15000 gibt es PCF-Error */
		 for (i=0; i<k; i++)
		 {;
		 };	
	}

void wartezeit(void)
	{
	pause();pause();pause();pause();

	}
	
void lange_warten(void)
	{
	wartezeit(); wartezeit(); wartezeit(); wartezeit(); wartezeit();
	wartezeit(); wartezeit(); wartezeit(); wartezeit(); wartezeit();
	}

/* Errors und Signalisationen */

void error(void)	/* LED's 4 und 8 blinken dreimal lang */
	{   
		DDRD |=12;
		k=50000;
		n=5;
		while (n-- >1)
		{
		PORTD |= 12;               
		 for (i=0; i<k; i++);
		PORTD &=243;	
		 for (i=0; i<k; i++);
		}; 
	}  /* Ende error */

void errorpcf(void)       /* LED 8 blinkt dreimal kurz   */
	 {   
		DDRD |=8;
		k=12000;          /* früher 3000 */
		n=3;               /* früher 2-mal */
		while ( n-- >0)
		{
		PORTD |= 8;                 
		 for (i=0; i<k; i++);
		PORTD &=247;	
		 for (i=0; i<k; i++);
		};
	 }  /* Ende errorpcf */

void kontrolle(void)	   /*  LED 2  blinkt dreimal kurz */
	{	DDRD |=2; 
		k=5000;    /*früher 5000 */
		n=4;
		while (n-- >1)
		{
		PORTD |= 2;              /*geändert: 2-->4 */
		 for (i=0; i<k; i++);
		PORTD &=253;	
		 for (i=0; i<k; i++);
		};
	}  /* Ende kontrolle */


void stop(void)   /* void testweise hineingeschrieben */
	{
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);  /* Stop */
	pause();
	}	
		
void pcfstart(uint8_t pcfadr)   /* steuert alle PCF's an */
                                 /* Achtung! darf nicht "start" heißen! */
	{
	PORTC |= 3;                  /* unverzichtbar! DDRC=3 hilft nicht. */
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);  /* Startbedingung zumPCF */
	while (!(TWCR & _BV(TWINT)))   /* erfolgreicher Start setzt TWINT-Flag */
	pause();      /* Verzögerungsglied vielleicht unverzichtbar? */
/*	kontrolle(); zur Kontrolle */                  
	if ((TWSR & 0xF8) != TW_START)  /* prüft im TW-St.-Reg., ob 0x08 */   
		{	                        /* gesetzt. Dann war Startbefehl ok */ 
									/* hier wird errorpcf  i m m e r ausgelöst! */
		errorpcf();    				/* egal ob & _BV(3), 0xF8(lt.Man.S.184, 0x08   */ 	    
		};                 		    /* wenn wahr, dann nicht ??? 0 */
									/* Notiz: while--> überspringen bei 0 */
									/* Notiz: if-->    überspringen bei 0 */									
    /* Adressierung  */																							
	TWDR=pcfadr;		                /* Adresse in Datenreg. schr.*/			
	TWCR = (1<<TWINT | 1<<TWEN);		/* ab zum PCF */
	while (!(TWCR & _BV(TWINT))) 		/* erfolgreiches zumPCF setzt TWINT-Flag */
	pause();      /* Verzögerungsglied vielleicht unverzichtbar? */
   /* kontrolle(); zur Kontrolle */    
	if (((TWSR & 0xF8))  !=TW_MT_SLA_ACK) /* Antwort des Chips nach Adressierung */	
		errorpcf();		/* spricht nur bei Fehlern an */					
		pause(); 					  /* kontrolle();   */
	}     
 

void zumPCF(unsigned char n)     
	{	
	TWDR = n;					    /* was an PCF gesendet werden soll */
	TWCR = (1<<TWINT | 1<<TWEN);	/* ab zum PCF */
	while (!(TWCR & _BV(TWINT)))    /* versandbereit? TWIN-Flag */ 
	pause(); 
	if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
	errorpcf();       			    /* antwortet der Chip nach Datenempfang ?*/ 
	pause(); 						/*  unnütz? geht sonst zu schnell */
	} /* Ende zumPCF   */			    	


/* #if debug */
/* #endif */
	
	
/* ++++++++++++++ LCD-Zubehör ++++++++++++++++++ */
 
/*  geändert am 20.5.04:
*	E   = PORTB1 	Startpuls  1-->0 zumPCF  0--> lesen
*	R/W = PORTB2 	0-schreiben 1-lesen	
*	RS  = PORTB3 	0-commands  1-characters  
*	command = RS=PB3=0, RW=PB2=0, E=PB1=1  d.h. xxxx 001x ,z.B. 2
*	daten = RS=PB3=1, RW=PB2=0, E=PB1=1  d.h. xxxx 101x ,z.B. 10
*/

/* LCD	function set 56 = 8bit, 2lines, 5x10dot;
*	    display/cursor shift 20
*		display on/of & cursor 15 blink etc
*		character entry mode 6
*		display & cursor home 2
*		clear display 1	
*	also zusammen: 3x 0x38, dann 20 - 14 - 6 - 2 - 1
*/

void kdo(uint8_t dat)  /* LCD-Ansprache (=Kommandomodus) */
	{
    PORTB = 2;		    /* = E high  und RS=RW=0, also Kommandomodus */
                        /* Problem: fkt. nicht mit PORTB |= 2 */
	zumPCF(dat);		
	PORTB &= (~2);
	pause();			        /* pause()zu lang,  10 ns reichen */
	PORTB |=2; 	        /* E wieder high */
	}

void lcdtxt(uint8_t dat)/* Text zum LCD (=Textmodus des LCD) */
	{
    PORTB=10;		     /* RS=1, RW=0 E high   */
    zumPCF(dat);	 	 /* Datenleitungen setzen */	
	PORTB &= (~2);
	;			         /* pause()zu lang, 10 ns reichen */
	PORTB |=2; 	         /* E wieder high */
	}			

int lcdinit(void)      /* uint8_t text,uint8_t mode */
	{
	DDRB=14;             /* PORTB 1-3 werden zu Ausgängen */
	kdo(0x15);
	kdo(0x38);  kdo(0x38); kdo(0x38);
	kdo(20);  kdo(14);  kdo(6); kdo(2); kdo(1);
	return 0;               
	}

/* ------------ Texte ------------ */

void aussen(void)
	{
	lcdtxt(51);    /* 3  */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0xA0);  /*    */	
	lcdtxt(0x61);  /* a  */
	lcdtxt(0x75);  /* u  */
	lcdtxt(0x73);  /* s  */
	lcdtxt(0x73);  /* s  */
	lcdtxt(0x65);  /* e  */
	lcdtxt(0x6E);  /* n  */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0xA0);  /*    */
	}

void Zulauf(void)
	{
	lcdtxt(50);    /* 2  */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0xA0);  /*    */	
	lcdtxt(0x5A);  /* Z  */
	lcdtxt(0x75);  /* u  */
	lcdtxt(0x6C);  /* l  */
	lcdtxt(0x61);  /* a  */
	lcdtxt(0x75);  /* u  */
	lcdtxt(0x66);  /* f  */
	lcdtxt(0xA0);  /*    */	
	lcdtxt(0xA0);  /*    */
	}	

void Teich_unten(void)
	{
	lcdtxt(49);    /* 1  */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0xA0);  /*    */
	lcdtxt(0x54);  /* T  */	
	lcdtxt(0x65);  /* e  */
	lcdtxt(0x69);  /* i  */
	lcdtxt(0x63);  /* c  */
	lcdtxt(0x68);  /* h  */
	lcdtxt(0x77);  /* w  */	
	lcdtxt(0x61);  /* a  */	
	lcdtxt(0x73);  /* s  */
	lcdtxt(0x73);  /* s  */
	lcdtxt(0x65);  /* e  */
	lcdtxt(0x72);  /* r  */	
	lcdtxt(0xA0);  /*    */
	 }
/* +++++++++++++++++++++++++++++++++++++++++ */



/*if debug
*endif */


/* abfragemanagement */
void texte(uint8_t a)
		{
		error();  		  /* als Test */
		pcfstart(116);    /* 116 PCF-Adr für LCD auf AVR-B x0104  */  /*???*/
		kdo(3);
	DDRD |=1;      		 /* zum Test, entn. aus error */
	PORTD |= 1;	  		 /* aus error */
		if      (a==1)   Teich_unten();
		else if (a==2)   Zulauf(); 
		else if (a==4)   aussen(); 
		lange_warten();
	
	lange_warten();
	PORTD &=254;					/* aus error */	
	lange_warten();

		}
		

/* ********************************************************* */
/*  ISD2560                 Wertigkeiten: A0=1, P/R=2, PD=4. */

void cepulstakt(void)	 /* schnellerer CE-Puls (reicht zum Durchtakten) */
 		{
		DDRD  |= 129;    /* ISD:  CE = D7 = 128 und D0 sind Ausgänge */
		PORTD |= 129;    /* CE = D7  high (und D0 zur Kontrolle) */
		pause();
		PORTD &= 126;	 /* D7 pulse low */	
		pause();
		PORTD |= 129;    /* CE = D7 wieder high */
		}

void cepuls(void)	     /* längerer CE-Puls (bis EOM des ISD2560) */
 		{
		DDRD  |= 129;    /* ISD:  CE = D7 = 128 und D0 sind Ausgänge */
		PORTD |= 129;    /* CE = D7  high (und D0 zur Kontrolle) */
		pause();
		pause();             /* freihändig ergänzt- damit schweigt er ganz!   */
		PORTD &= 126;	 /* D7 pulse low */	
		wartezeit();
		wartezeit();
		PORTD |= 129;    /* CE = D7 wieder high */
		}

void sagen(uint8_t a) 
		{
		pcfstart(76);    /* 76 PCF-Adr für Sound2 (gibt errorpcf) */
		zumPCF(6);       /* ISD auf Adresse 0 stellen: */
		pause();         /* A0=0, P/R=1 (1=play), PD=1 (f. Adresse=0), also 6  */ 
		cepulstakt();			
		a=a+1;			 /* hilfsweise, bis Info über while gefunden wird */
		while (a-- >1)
		{				 /* durchtakten */
		pcfstart(76);    /* 76 PCF-Adr für Sound2 */
		zumPCF(3);       /* A0=1, P/R=1 (1=play), PD=0, also 3  */
		cepulstakt();
		}

						 /* Ausgabe                */
		pcfstart(76);    /* 76 PCF-Adr für Sound2 */
		zumPCF(2);       /* A0=0, P/R=1 (1=play), PD=0, also 2  */
		cepuls();	
		} 
/* ******************************************************* */

int main(void)    					 	    
	 { 
		uint8_t a,i;    /* i vorübergehend unbenutzt */
		pause();		
		DDRD |= 15;
		DDRB=7;
		
		stop();         /* I2C - Startbedingung vorbereiten */
		
		a=1;			/* Startwert für Abfragemanagement */
		while(1)        /* Endlosschleife */
		{

		pcfstart(116);   /* 116 PCF-Adr für LCD auf  AVR-Basis x0104 */
		lcdinit();
		kdo(128);        /* LCD-Startpkt. (kdo=128 + ggf. 4 für 4. Stelle) */
/*		kdo(3);     */
		texte(a);
		a = a*2; 
		if (a==8) a=1;
/*		error();   */   /* Laufkontrolle */
/* 	 Telefon      */    /*    RVLC = PC6 = 64; LC = PC7 = 128 */
						/*  wenn es klingelt, gibt RVLC Impülse mit doppelter */
						/*	Klingelfrequenz ab, also                          */
						/*  wenn DDRC gesetzt. ok, sonst immer high (???) */
		DDRC  |= 134;   /*  Port LC=C7=128  Ausgang! ( und PORTD 2)  */
		DDRC  &= 191;   /*  Port RVLC=C6=64  Eingang!  */
 		PORTC  |= 64;	/*  RVLC an   */
		errorpcf();    /*als Test */
 		pause();
 		pause();
 		PORTC  &= 191; 	/* RVLC aus */
 		wartezeit();	
		PORTC  &= 127;	/* LC low = abgehoben   */		
 		PORTD  |= 4;	/* PORTD2 high - zur Kontrolle  */
 		if ( !(PINB &= 64))  /* wenn es klingelt, dann Impulse an RVLC; */
							  /* mit LC = low wird abgehoben  */
 		{
 		PORTC  &= 127;	/* LC low = abgehoben */
 		PORTD  |= 4;	/* PORTD2 high - zur Kontrolle */		
		wartezeit();		
		wartezeit();
		wartezeit();
		PORTC  |=128;	/* LC high = aufgelegt */
 		PORTD  &=251;	/* PORTD2 low - zur Kontrolle     faul */
 		}
 		else
 		kontrolle();    /* LED's als Tätigkeitsindikator */


 		sagen(5);  /*  ISD2560   ++++++++vorübergehend deaktiviert +++++++++  */          
 		sagen(0);
 		stop();          /* I2C - Startbedingung vorbereiten */
		} /* Ende while   */

		return 0;
	}
 
 
