/*************************************************************
** Attiny25 Nikon remote control
*
*
* 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     main.c           500µsek Interrupt
* 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
* TIM0_COMPB  Timer/Counter0 Compare Match B
* WDT         Watchdog Time-out
* USI_STR     USI START
* USI_OVF     USI Overflow
*
* Prozessor:  Attiny25
* Frequenz:   8,000 MHz (interner Clock, FUSE beachten )
*
* -------------------------------------------------------------------------------------------
* Pin Belegung Attiny25
*                                            +----------------+
* Reset ISP      (PCINT5/RESET/ADC0/dW) PB5 -|1     XXX      8|- VCC
*                                            |                |
* In1     (PCINT3/XTAL1/CLKI/OC1B/ADC3) PB3 -|2              7|- PB2 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2)
*                                            |                |
* out     (PCINT4/XTAL2/CLKO/OC1B/ADC2) PB4 -|3              6|- PB1 (MISO/DO/AIN1/OC0B/OC1A/PCINT1)     38400 Hz
*                                            |                |
*                                       GND -|4              5|- PB0 (MOSI/DI/SDA/AIN0/OC0A/OC1A/AREF/PCINT0)
*                                            +----------------+
*--------------------------------------------------------------------------------------------
* FUSE: Attiny25    FF DF E2
*       mit CLKOUT  FF DF A2
* -------------------------------------------------------------------------------------------
* 02.03.2013 li Umbau auf Nikon remote Control
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// meine BIT Definitionen 
#define BIT0  0x01
#define BIT1  0x02
#define BIT2  0x04
#define BIT3  0x08
#define BIT4  0x10
#define BIT5  0x20
#define BIT6  0x40
#define BIT7  0x80

volatile unsigned char tim1_event = 0;

//--------------------------------------------------------------------------------------
// Im Internet gefunden Zeitsteuerung des IR-Signals: http://www.bigmike.it/control/
// Ich habe die Zeiten etwas vereinfacht auf ein vielfaches von 500µsek
// funktioniert mit Nikon 1 J1
// die Tabelle hat 16 Einträge, der Fehlwert der Zeit ist 2 und start mit Signal=0
// Das Signal wird abwechselnd
                                  //                                   1  
                                  // 0   1  2  3  4  5  6    7  8   9  0  1  2  3  4  5   index
static unsigned char timetable[] = { 4, 56, 1, 3, 1, 7, 1, 127, 4, 56, 1, 3, 1, 7, 1, 2  };
//                                   1   0  1  0  1  0  1    0  1   0  1  0  1  0  1  0     Signal
//                                   |   |  |  |  |  |  |    |  |-2. Sequenz          |-restart value
//                                   |   |  |  |  |  |  |    |-53,5msek
//                                   |   |  |  |  |  |  |0,5msek 
//                                   |   |  |  |  |  |          | 
//                                   |   |  |  |  |  |-3,5msek  |
//                                   |   |  |  |  |-0,5msek     |
//                                   |   |  |  |-1,5msek        | 
//                                   |   |  |-0,5msek           |
//                                   |   |-28msek               |
//                                   |-2msek                    |  
//                                   |<--------100msek--------->| 

unsigned char al_cc = 0;
unsigned char senden = 0;           //
unsigned char index = 0;
unsigned char txd = 0;

static void timer1_init( void );
static void timer0_init( void );
void reset( void );
unsigned char test_switch_B3( void );

/*##################################################################
 * Main
 */
int main(void)
{
   unsigned char tim1_cnt = 0;         // 10msek wegen schalter abfrage
   
   unsigned char time = 2;
   

   timer0_init();                      // IR Frequenz 38,4 kHz
   timer1_init();                      // timer 500µsek Int   

   DDRB  |= BIT1+BIT4;                 // set output
   DDRB  &= ~(BIT3);                   // Input
   PORTB |= BIT3+BIT0+BIT2+BIT5;       // input pullup R wegen staischer Aufladung
   PORTB &= ~BIT1;                     // clear
   
   reset();  

   //OSCCAL = 95;                      // Oscillator Calibration Value ca.8 MHz
                                       // kann sein

   sei();                              // enable int
   _delay_ms(200);

   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   for(;;)
   {
      if ( tim1_event )                   // timer1 500µsek 
      {
         tim1_cnt += tim1_event;          
         tim1_event=0;                    // reset

         if ( senden )                    // Nikon Auslöse Sequenz senden ?
         {
            if ( --time == 0 )            // 500µ counter 0 ?
            {
               txd ^= 1 ;                 // 0 1 0 1 ....
               if ( txd )
               {
                  TCCR0A |= (1<<COM0B0);  // OC0B aktiv = 38400 Hz IR
                  PORTB |= BIT4;             // control LED ON
               }
               else
               {
                  TCCR0A &= ~(1<<COM0B0); // OC0B aus
                  PORTB &= ~BIT4;         // control LED off
               }   

               time = timetable[index];   // new counter
               if ( index == 15 )         // table end ??
               {
                  reset();                       
               }
               else
                  index++;
            }
         }
                                          // switch pressed ??
         if ( tim1_cnt >= 20 )            // 10 msek timer = 100 Hz
         {
            tim1_cnt = 0;
            if ( test_switch_B3() == 1 && senden == 0 )
            {
               senden = 1;               
            }
         }
      }
   }
   return 0;           // dummy
}



/*****************************************************************************
**  Reset
*/
void reset ( void )
{
   senden = 0;
   txd = 0;
   index = 0;
   PORTB &= ~BIT4;         // control LED off
   TCCR0A &= ~(1<<COM0B0); // OC0B aus  
}   


/*****************************************************************************
**  Switch Abfrage an PB3
*/
unsigned char test_switch_B3( void )
{
   if ( !(PINB & BIT3 ) )      // pressed = 0 ??
   {
      if ( !(PINB & BIT3) && al_cc < 128 )
      {
         if ( al_cc++ > 3 )    // 30msek 1 
         {
            al_cc = 128;       // pressed
            return 1;
         }
      }
   }
   else
   {
      if ( al_cc >= 128 )
      {
         if ( PINB & BIT3 )
         {
            if ( al_cc++ > 131 )
            {
               al_cc = 0;  // no pressed
               return 2;
            }
         }
      }
   }
   return 0;
}



/*****************************************************************************
**  Interrupt service routine Timer1 compare A
*/
ISR( TIM1_COMPA_vect )
{
   tim1_event++;
}



/*****************************************************************************
**  set Timer1  compare A, Ziel = 500µsek Interrupt = 4000 Takte
*/
static void timer1_init( void )
{
   TCCR1 |= (1<<CTC1) ;                         // CTC mode
   GTCCR |= (1<<PSR1) ;                         // Reset Timer
   TCCR1 |= (1<<CS10) + (1<<CS12);              // prescaler = 16
   OCR1A  = 249;                                // compare match bei 250-1 
   TCNT1 = 0;
   tim1_event = 0;
   TIMSK |= (1<<OCIE1A);
}



/*****************************************************************************
**  set Timer0  38400 Hz = IR Frequenz
*/
static void timer0_init( void )
{
   TCCR0A |= (1<<WGM01) + (1<<COM0B0);        // CTC mode und toggle output
   TCCR0B |= (1<<FOC0B)+ (1<<CS00);           // prescaler = 1
   OCR0A  = 103;                              // 8 Mhz / 38400 = 208,333 / 2 = 104  
   TCNT0 = 0;
}
