/* 	AVRTelx092.c                       3.4.2008
*	AVRTel09a.c                       27.7.2004
*
*	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 (vgl. Sound 1, dort genügt manchmal (!!!)
* 	ein kurzes Antippen.

*	Es gab elektrische (Kontakt-)Probleme mit CE-Puls am ISD.
*	Achtung:
*	Es gibt errorpcf's und manchmal sind 2-3 Startversuche nötig.

*	Unbedeutende Reserveversion.
*
*	Errors einprägsamer definiert:
*	error	    zwei LED's rechts (4 u.8) blinken dreimal
*	errorpcf    LED rechts (8)  blinkt dreimal   
*	kontrolle   LED ganz links (1)  blinkt mehrmals kurz
*   test0       LED's 1-4 aufsteigend, 3 mal 
*	test        LED's 4-1 nacheinander aus, 3 mal 


* 	PORTC=3 scheint unverzichtbar zu sein, DDRC=3 hilft nicht.
*	Gehört wahrscheinlich zu PCF bzw. zu SDA u. SCL.
*	PORTD=1-Problem: wird durch errorpcf() verursacht,
*	wenn nicht,dann Abhilfe mit DDRD=1 (Port als Ausgang)
*
*	Unbedeutende Zwischenversion als Reserve.
*
*	Fest belegte Ports (ohne PCF):
*	PC7 =  LC   des MH8/ 
*	PC6 =  RVLC des MH8/
*	PD7 = CE des ISD2560
*	PORTD D0, D1, D2 und sind via ULN2803 direkt an 4 LED's 
*	der Knightbridge-Leiste und an die Leiste L geführt! 

*	Hardware :   AVR-Basis x0104
*	und Sound2 
*	und Bus1
*/

#include <avr/io.h>				 	
#include <util/twi.h>
#include <stdint.h>    // veraltet: #include <inttypes.h>	
#include <stdio.h>
#include <util/delay.h>	   


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)
	{
	_delay_ms(30);
	return;
	}
	
void lange_warten(void)
	{
	_delay_ms(200);
	return;	
	}



void test0(void)  // LED's 1-4 aufsteigend, 3 mal  
   {
   n=3;
   while(n-- >0)
   {
	DDRD |=15;
	PORTD |=1; 		_delay_ms(30);
	PORTD |=3;		_delay_ms(30);
 	PORTD |=7;		_delay_ms(30);
	PORTD |=15;		_delay_ms(30);
	PORTD &=240;	_delay_ms(80);
	};
	return;
	}            // Ende test0()


void test(void)  // LED's 4-1 nacheinander aus, 3 mal  
   {
   n=3;
   while(n-- >0)
   {
	DDRD |=15; 
	PORTD |=15; 	_delay_ms(30);
	PORTD &=247;	_delay_ms(30);
	PORTD |=7;  	_delay_ms(30);
	PORTD &=243;	_delay_ms(30);	
 	PORTD |=3;  	_delay_ms(30);	
	PORTD &=241;	_delay_ms(30);
	PORTD |=1; 		_delay_ms(30);
	PORTD &=240; 	_delay_ms(80);
	};
	return;
	}   // Ende test()
	

void error(void)	//  alle LED's  blinken dreimal 
	{   
		DDRD |=15;
		PORTD &=240;   // alle LED's aus	
		n=4;
		while (n-- >1)
		{
		PORTD |= 15;               
 		_delay_ms(50);
		PORTD &=240;	
		_delay_ms(50);
		};
	return;	
	}  // Ende error() 

void errorpcf(void)       // LED 8 blinkt dreimal    
	 {   
		DDRD |=8;
		n=3;
		while ( n-- >0)
		{
		PORTD |=8;               //  mit 8 = D3 = 4.bit = auf
		_delay_ms(50);           // Knightbridge ganz rechts  
		PORTD &=247;	            
		_delay_ms(50);
		};
		return;
	 }  // Ende errorpcf() 


void kontrolle(void)  // LED links (PORTD = 2) blinkt
	 {	
		DDRD |=2;
		n=6;
		while(n-- >0)
		{
		PORTD |=2;
		_delay_ms(20);		
		PORTD &=253;
		_delay_ms(20);
		};
		return;
	 }  // Ende kontrolle()


void stop(void)
	{
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); /* Stop */
	pause();
	return;
	}	
		
void pcfstart(uint8_t pcfadr) // 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();   */
	return;
	}     

 

void zumPCF(unsigned char n)      // wozu?
	{	
	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
	return;
	} /* Ende zumPCF   */			    	


	
/* ++++++++++++++ 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 */
	{
    PORTB=2;		    /* = E high  und RS=RW=0 */
    zumPCF(dat);		
	PORTB &= (~2);
	;			        /* pause()zu lang,  10 ns reichen */
	PORTB |=2; 	        /* E wieder high */
	return;
	}

void lcdtxt(uint8_t dat)/* Text zum 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 */
	return;
	}			

int lcdinit(void)      /* uint8_t text,uint8_t mode */
	{
	DDRB=14;             /* PORTB 1-3 sind Ausgänge */
	kdo(0x15);
	kdo(0x38);  kdo(0x38); kdo(0x38);
	kdo(20);  kdo(14);  kdo(6); kdo(2); kdo(1);
	return 0;
	}

/* ------------ Texte ------------ */

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);  /*    */
	return;
	}	

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);  /*    */
	return;
	 }
/* +++++++++++++++++++++++++++++++++++++++++ */




/* abfragemanagement */
void texte(uint8_t a)
		{
//		pcfstart(116);    // 116 PCF-Adr für LCD auf AVR-B x0104 
		if      (a==1)   Teich_unten();
		else if (a==2)   zulauf();
		return;
		}
		

//***********************************************************
//  ISD2560                 Wertigkeiten: A0=1, P/R=2, PD=4.

void cepulstakt(void)	 // schnellerer CE-Puls (reicht zum Durchtakten)
 		{
		DDRD  |= 130;    // ISD:  CE = D7 = 128 und D0 sind Ausgänge  129-->130
		PORTD |= 129;    // CE = D7  high (und D0 zur Kontrolle)
		pause();
		PORTD &= 126;	 // D7 pulse low	
		pause();
		PORTD |= 129;    // CE = D7 wieder high
	return;
		}

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();
		PORTD &= 126;	 // D7 pulse low	
		lange_warten();
		lange_warten();
		PORTD |= 129;    // CE = D7 wieder high
	return;
		}

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();	
	return;
		}
// ********************************************************

int main(void)    					 	    
	{ 
		uint8_t a;
		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)
		texte(a);
		a = a*2;
		if (a==4) a=1;

//  Telefon              RVLC = PC6=64; LC = PC7=128
			            // wenn DDRC gesetzt. ok, sonst immer high (???)
/*		DDRC  |= 192;   // Ports C7=LC und C6=RVLC als Ausgänge
		PORTC  |= 64;	// Problem RVLC (muß Eingang sein)
		lange_warten();		
		PORTC  &= 191;
		lange_warten();	
		PORTC  |= 128;
		lange_warten();		
		PORTC  &=127;
		lange_warten();		
		kontrolle();     // LED's als Tätigkeitsindikator
*/

		sagen(7);  //  ISD2560             
		sagen(0);
//		stop();          /* I2C - Startbedingung vorbereiten */
		} /* Ende while   */

		return 0;
	}

 
 
