/*************************************************************
** Attiny 25 Regen_messer
*
*
* Interupt Belegung attiny25                       wo              warum
* -------------------------------------------------------------------------------------------
* RESET       External Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, External Interrupt Request 0
* INT0        External Interrupt Request 0
* PCINT0      Pin Change Interrupt Request 0
* TIM1_COMPA  Timer/Counter1 Compare Match A
* TIM1_OVF    Timer/Counter1 Overflow
* TIM0_OVF    Timer/Counter0 Overflow
* EE_RDY      EEPROM Ready
* ANA_COMP    Analog Comparator
* ADC ADC     Conversion Complete
* TIM1_COMPB  Timer/Counter1 Compare Match B
* TIM0_COMPA  Timer/Counter0 Compare Match A      main.c           ca. 1800 Hz Int
* TIM0_COMPB  Timer/Counter0 Compare Match B
* WDT         Watchdog Time-out
* USI_STR     USI START
* USI_OVF     USI Overflow
*
* Prozessor:  Attiny25
* Frequenz:   1,000 MHz (interner Clock)
*
* -------------------------------------------------------------------------------------------
* Pin Belegung Attiny25
*                                            +----------------+
* Reset ISP      (PCINT5/RESET/ADC0/dW) PB5 -|1     XXX      8|- VCC
*                                            |                |
*         (PCINT3/XTAL1/CLKI/OC1B/ADC3) PB3 -|2              7|- PB2 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2)       LED
*                                            |                |
*         (PCINT4/XTAL2/CLKO/OC1B/ADC2) PB4 -|3              6|- PB1 (MISO/DO/AIN1/OC0B/OC1A/PCINT1)          Input
*                                            |                |
*                                       GND -|4              5|- PB0 (MOSI/DI/SDA/AIN0/OC0A/OC1A/AREF/PCINT0) Software UART Output
*                                            +----------------+
*--------------------------------------------------------------------------------------------
* 10.03.2011 li attiny25 mit 1Mhz Takt und timer0, einstellbare Taktraten, fuse clock/8
* 11.03.2011 li software uart sendet sRF000pe signal alle 60 Sekunden
* 16.03.2011 li UART Signale vertauscht, empfang nur über optokoppler
* 20.03.2011 li Regenmesser Ergebnisse 3mal hintereinander senden (zur Sicherheit) 
*               sRF000pe  F = Flag = 0 bis 9, wechsel nach jeder Serie 
* 07.06.2011 li software uart sendet sRF000pe signale ca. alle 30 Sekunden  
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "../abc/basis.h"
/*
#include <math.h>
*/

#define BUFSIZE 16

                            // FIFO Struct
typedef struct
{
   unsigned char *buffer;              // buffer Adresse
   unsigned char volatile count;       // Anzahl Zeichen im Puffer
   unsigned char volatile read;        // Lese position
   unsigned char volatile write;       // Schreib position
} SOFT_FIFO;

SOFT_FIFO stx_fifo;          // Stuktur FIFO zu sendende Zeichen

unsigned char stxbuffer[ BUFSIZE ];

volatile unsigned char tim0_event_flag = 0;
volatile unsigned char ts = 0;
volatile unsigned char rt = 0;

volatile unsigned char stx_count = 0;
unsigned char volatile stx_data;
unsigned char volatile stx_busy;

unsigned char rflag=0;
unsigned char save_regen=0;

int  soft_putc( unsigned char );
int  soft_putstring( char *s );
void soft_start_tx( void );
static void sfifo_init (SOFT_FIFO*, unsigned char *buf, unsigned char size);
static unsigned char   sfifo_put( SOFT_FIFO*, unsigned char data);
static int  sfifo_get( SOFT_FIFO *f);
//int ADC_Messung(void);
void transmit_regen( void );

static void timer0_init( void );


// 16.3.2011 Pegel vertauscht wegen Optokoppler Ansteuerung
#define UARTBIT_L1  PORTB &= ~BIT0
#define UARTBIT_L0  PORTB |= BIT0

 


/*##################################################################
** Main
** die Regnemsser ticks werden 3 mal gesendet, danach wechselt das flag  
*/
int main(void)
{
   unsigned char cnt0 = 0;
   unsigned char cnt1 = 0;
   unsigned char regen_flag = 0;
   unsigned char regen = 0;
   unsigned int stimer = 0;
   //int temperatur=0;
   
   	
	#define REGEN_TIM1  10000          // ca. 30 Sekunden
	#define REGEN_TIM2  10400          // ca. +1,11 Sekunden
	#define REGEN_TIM3  10800          // ca. +1,11 Sekunden
		
   unsigned char tflag=0;
   #define TXD_ZTEMP  BIT0            // .... ...1 
	#define TXD_REGS1  BIT1            // .... ..1.
   #define TXD_REGD1  BIT2            // .... .1.. 
   #define TXD_REGS2  BIT3            // .... 1... 
   #define TXD_REGD2  BIT4            // ...1 .... 
   #define TXD_REGS3  BIT5            // ..1. .... 
   #define TXD_REGD3  BIT6            // .1.. .... 
   #define TXD_ZDONE  BIT7            // 1... .... 
   
	timer0_init();                      // timer 1800 Hz wegen Software Uart mit 300 baud

   DDRB |= BIT0+BIT2;                  // set output
   DDRB &= ~(BIT1);                    // Input  Lichtschranke
   PORTB &= ~(BIT2+BIT1);              // clear und ohne Pullup
   UARTBIT_L1;                         // RS232
   sei();                              // enable int

   sfifo_init( &stx_fifo, stxbuffer, BUFSIZE );   // init fifo
   stx_busy = 0;

   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   for(;;)
   {
      if ( tim0_event_flag )             // syncronisieren mit Lichtschranken LED ON
      {
         _delay_us(200);                 // Etwas verzögert richtung pulse Mitte warten
         tim0_event_flag = 0;            // clear flag
         stimer++;                       // 

         if ( PINB & BIT1 )              // Lichtschranke unterbrochen ?
         {
            cnt1++;
            if ( cnt1 >= 2 )             // ereignis mindestens 2 mal da ?
            {
               cnt1 = 2;
               cnt0 = 0;
               regen_flag = 1;
            }
         }
         else
         {
            cnt0++;
            if ( cnt0 >= 2 )
            {
               cnt0 = 2;                 // ereignis mindestens 2 mal da ?
               cnt1 = 0;
               if ( regen_flag )
               {
                  regen++;               // Trigger Regen Counter
                  regen_flag = 0;
               }
            }
         }
			                                // Temperatur Messung ist Mist
			// if ( stimer >= 10800 )       // 30 Sekunden vorbei
			//    tflag |= TXD_ZTEMP;
         
         if ( stimer == 10 )             // restart transfer cyclus
            tflag = 0;
         
         if ( stimer == REGEN_TIM1 )      
         {   
            if ( !( tflag & (TXD_REGD1+TXD_REGS1)))
            {            
               save_regen = regen;
               regen  = 0;
               rflag++;                     // Transfer Flag von 0-9 
               if ( rflag > 9 )
                  rflag = 0;
               tflag |= TXD_REGS1;
            }
         }
			
			if ( stimer == REGEN_TIM2)   
         {  
            if ( !( tflag & (TXD_REGD2+TXD_REGS2)))
				   tflag |= TXD_REGS2;
         }
			
			if ( stimer == REGEN_TIM3 )   
         { 
            if ( !( tflag & (TXD_REGD3+TXD_REGS3)))
            {
               stimer = 0;
				   tflag |= TXD_REGS3;
            }
         }
      }
		
		if ( (tflag & TXD_REGS1) && stx_busy == 0 )
      {
		   tflag &= ~TXD_REGS1;
         tflag |= TXD_REGD1;
			transmit_regen();
		}
      
      if ( (tflag & TXD_REGS2) && stx_busy == 0 )
      {
		   tflag &= ~TXD_REGS2;
         tflag |= TXD_REGD2;
			transmit_regen();
		}
      
      if ( (tflag & TXD_REGS3) && stx_busy == 0 )
      {
		   tflag &= ~TXD_REGS3;
         tflag |= TXD_REGD3;
			transmit_regen();
		}
/*      
      if ( (tflag & TXD_ZTEMP) && stx_busy == 0 )
      {
         temperatur = ADC_Messung();
         tflag &= ~TXD_ZTEMP;
         text[0] = 0x02;
         text[1] = 'Z';               // Regen  ASCII 0x52
         edit99( temperatur, text+2, 4 );
         n = berechne_PZ( text+2, 4 );
         text[6] = n + 0x30 ;
         text[7] = 0x03;
         text[8] = 0x00;              // string Ende
         soft_putstring( text );
      }
*/      
   }
   return 0;           // dummy
}



/*****************************************************************************
** Regen Nachricht senden
*/
void transmit_regen( void )
{
   char text[10];
   unsigned char n;

   text[0] = 0x02;
	text[1] = 'R';                // Regen  ASCII 0x52
	text[2] = rflag + 0x30;       // flag von 0 bis 9                 
	edit99( save_regen, text+3, 3 );
	n = berechne_PZ( text+2, 4 );
	text[6] = n + 0x30 ;
	text[7] = 0x03;
	text[8] = 0x00;               // string Ende
	soft_putstring( text );
}



/*****************************************************************************
** Read internen Temperatursensor
** VRef = Vcc

int ADC_Messung(void)
{
   unsigned char i;
   int result = 0;
                                 // ADC Noise Reduction
   MCUCR  |= (1<<SM0);
                                 // first dummy reading, VRef=Vcc
   ADMUX  = 0x0F;                // temperatur sensor 
   ADMUX |= (1<<REFS1);          // 1,1V interne reverenz  

                                 // Teiler auf 8, enable adc
   ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);

   ADCSRA |=  (1<<ADSC );        // Start conversion
   while(ADCSRA & (1<<ADSC));    // dummy read = warten bis ADSC = 0

   for( i = 0; i < 1; i++ )
   {
      ADCSRA |= (1<<ADSC);       // start conversion
      while(ADCSRA & (1<<ADSC)); // warten bis fertig
      result += ADCW;            // ergebnis auslesen
   }
   ADCSRA = 0;                   // disable ADC

   return ( result/i );
}
*/


/*****************************************************************************
**  set Timer0 bei 1 MHz CPU
*/
static void timer0_init( void )
{
   TCCR0A |= (1<<WGM01) ;            // CTC mode und toggle output
   TCCR0B |= (1<<CS01);              // prescaler = 8
   OCR0A  = 68;                      // 69 = 1800 Hz , vielfaches für 300 BAUT
   TIMSK |= (1<<OCIE0A);             // compare match A int enable
   TCNT0 = 0;
   tim0_event_flag = 0;
}



/*****************************************************************************
*  8 Bit TIMER0 Compare Match jetzt mit 1800 Hz, gleichzeitig für 300 Baut Software UART
*  Lichtschranken LED mit pwm 20% ansteuern
*  +---+               +---+
*  |   |               |   |
*--+   +---+---+---+---+   +---+---+---+---+


*  Software UART 8N1 , ein Bit benötigt 6 Takte
*---+               +---+               +---+ 
*   | S   0   1   2 | 3 | 4   5   6   7 | E |
*   +---+---+---+---+   +---+---+---+---+   +--
*/

ISR ( TIM0_COMPA_vect )             
{
   int data;
                                           //  8N1 routine   = 8Bits, kein Parity, 1 Stop Bit

   if ( stx_count )                        // TX todo ??
   {
      rt++;                                // rt  1-- 2-- 3-- 4-- 5-- 6-- 1--
                                           //     |<--- Bit zeit -------->|
      switch( stx_count )
      {
        case 10:                           // start Bit 
         if ( rt == 1 )                   
         {
            UARTBIT_L0;                    // Start Bit, 0 = logisch 1
         }
         else if ( rt == 6 )               // 1 Bit time
         {
            rt = 0;
            stx_count--;
         }
         break;

        case 1:                            // stop Bit senden
         if ( rt == 1 )
         {
            UARTBIT_L1;                    // stop Bit, 1 = logisch 0
         }
         else if ( rt == 6 )               // Bit time ende
         {  
            data = sfifo_get( &stx_fifo ); // nächstes zeichen holen 
            if ( data == -1 )              // leer ??
            {
                stx_count--;
                stx_busy = 0;              // ende der Übertragung
            }
            else
            {
               stx_data = (char)data;      // Datenbyte setzen 
               stx_count = 10;             // restart
            }                  
            rt = 0;
         }
         break;

        default:                           // hier die Datenbits
         if ( rt == 1 )
         {
            if( stx_data & BIT0 )          // test Bit
               UARTBIT_L1;                 // 1 = logisch 0
            else
               UARTBIT_L0;                 // 0 = logisch 1
         }
         else if ( rt == 6 )               // 1 Bit time
         {
            stx_data >>= 1;                // shift zero in from left
            rt = 0;
            stx_count--;                   
         }
         break;
      }
   }

                                           // Lichtschranken LED PWM erzeugen und Int flag setzen             
   ts++;                                   // set flag
   if ( ts >= 5 )
   {
      ts = 0;
      tim0_event_flag = 1;                 // set flag = 1800 / 5 = 360 Hz
      PORTB |= BIT2;                       // IR LED ein 
   }
   else if ( ts == 1 )
   {
      PORTB &= ~BIT2;                      // IR LED aus
   }
}



/*****************************************************************************
** fifo struct initialisieren
*/
static void sfifo_init (SOFT_FIFO *f, unsigned char *buffer, unsigned char size)
{
   f->count = 0;
   f->read  = 0;
   f->write = 0;
   f->buffer = buffer;
}



/*****************************************************************************
** zeichen in den fifo buffer ablegen
*/
static unsigned char sfifo_put( SOFT_FIFO *f, unsigned char data )
{
   if ( f->count >= BUFSIZE )
      return 0;

   f->write &= BUFSIZE-1;   // wrap around
   f->buffer[ f->write++ ] = data;
   f->count++;
   return 1;
}



/*****************************************************************************
** zeichen aus dem fifo buffer holen
*/
static int sfifo_get(SOFT_FIFO *f)
{
   unsigned char data;

   if ( f->count == 0 )
      return -1 ;

   f->read &= BUFSIZE-1;   // wrap around
   data = f->buffer[ f->read++ ];
   f->count--;

   return data;
}



/*****************************************************************************
**  Start Transfer
*/
void soft_start_tx( void )
{
   int data;

   data = sfifo_get( &stx_fifo );
   if ( data == -1 )
   {
      stx_busy = 0;
      stx_count = 0;
   }
   else
   {
      stx_data = (char)data;
      stx_busy = 1;
      stx_count = 10;
   }
}



/*****************************************************************************
** Einen 0-terminierten String uebertragen.
** rc =  0  String noch nicht komplett im Buffer
** rc =  1  Transfer gestartet
** rc = -2  Transfer nicht frei
*/
int soft_putstring( char *s )
{
   int rc;

   if ( stx_busy )          // transfer frei ?
      return -2;            // --> nein

   do
   {
      rc = soft_putc (*s);
      if ( rc == 0 )         // Puffer voll ??
        break;
      s++;
   } while( *s );

   if ( rc == 1 )            // Wenn alles im Puffer, transfer starten
      soft_start_tx();

   return rc;
}


/*****************************************************************************
**  Put Char
*/
int soft_putc( unsigned char c)
{
   if ( stx_busy )
     return -2;
   return sfifo_put( &stx_fifo, c );   // Zeichen in den sende buffer
}
