////////////////////////////////////////////////////////////////////////////////
// FW_VERSION  150617 (yymmdd)
//
// FUSES CONFIGURATION: EXT=0xFF HIGH=0xCD LOW=0xCC LOCK=0xFF

// Compiler includes
// -----------------
#include <iom48.h>
#include <ina90.h>

// Application defines
// -------------------
#define BYTE    unsigned char
#define WORD    unsigned int
#define LONG    unsigned long

#define STOP    22  // Pulse width for motor STOP
#define CW      15  // Pulse width for motor run ClockWise
#define CCW     30  // Pulse width for motor run CounterClocWise
#define ONESEC  61  // num. of timer ticks for 1 second
#define TWOSEC  122 // num. of timer ticks for 2 seconds

// I/O signals
// -----------
#define TEST    PORTB_Bit2  // Test output
#define LEDR    PORTD_Bit7  // RED led

// Global variables
// ----------------
volatile BYTE softt1; // software timer #1 (down counter) 16.384 mS step
volatile BYTE tdelay; // delay timer for last input capture 
volatile BYTE cap; // capure flag, set in irq, reset in main
BYTE tstart; // counter for "start" signal
BYTE t0; // counter for "0" signal
BYTE t1; // counter for "1" signal
WORD samples[2]; // last two samples from input capture
WORD diff; // difference accumulator

// Global read-only arrays
// -----------------------
flash BYTE author[] = "(c) E.Ficara 2015\r\n";

////////////////////////////////////////////////////////////////////////////////
// Debug
// -----
void DebugBurst(void) // burst on TEST pin (executed with irq disabled)
{
    for(GPIOR1 = 0; GPIOR1 < 100; ++GPIOR1)
        {
        TEST ^= 1;
        for(GPIOR0 = 0; GPIOR0 < 200; ++GPIOR0);
        }
}

void SetWatchdog(BYTE to) // change the watchdog timeout (irq must be disabled)
{
    __watchdog_reset();
    MCUSR &= ~(1<<WDRF); // Clear WDRF in MCUSR
    WDTCSR |= (1<<WDCE); // enable write
    WDTCSR = to; // 00x0.exxx set enable flag and new watchdog time
}

////////////////////////////////////////////////////////////////////////////////
// Interrupts
// ----------
#pragma vector = TIMER0_OVF_vect
__interrupt void TIMER0_OVF_i(void) // TMR0 Overflow (16.384 mS tick)
{  
    if(softt1) // if software timer enabled
        --softt1; // decrement time
    if(tdelay) // if delay time after capture running
        {
        if(--tdelay == 0) // if time finished
            {
            tstart = 0; // reset "start" time counter
            t0 = 0; // reset "0" time counter
            t1 = 0; // reset "1" time counter
            samples[0] = 0; // clear first sample
            samples[1] = 0; // clear second sample
            }
        }
}

#pragma vector = TIMER1_CAPT_vect
__interrupt void TIMER1_CAPT_i(void) // TMR1 Input Capture
{  
    samples[0] = samples[1]; // shift first sample
    samples[1] = ICR1; // get actual Input Capure value (irq disabled 16bit rd)
    tdelay = 5; // restart delay time after last input capture (5*16.384mS)
    cap = 1; // set new capture flag
}

////////////////////////////////////////////////////////////////////////////////
// Main Program
// ------------
//
void SetDelay(BYTE dt) // set delay time dt*16.384 mS
{
    __disable_interrupt(); // global interrupts disable
    softt1 = dt; // assign value to software timer #1
    __enable_interrupt(); // global interrupts enable
}

void DecodeTone(void) // decoding a tone
{
    if(samples[1] > samples[0]) // if last sample higher that previous
        diff = samples[1] - samples[0]; // difference of last 2 captures
    else // if last sample lower than the previous
        diff = samples[0] - samples[1]; // difference of last 2 captures

    if(diff >= (39-4) && diff <= (39+4)) // if F=1.6KHz (T=625uS 39*16uS)
        {
        if(++t0 >= (80-8)) // increment tstart counter, if > 80*0.625mS
            {
            LEDR = 1; // turn OFF Red led
            OCR0A = CW; // set pulse duration for ClockWise (MOT1)
            }
        return;
        }

    if(diff >= (52-5) && diff <= (52+5)) // if F=1.2KHz (T=833uS 52*16uS)
        {
        if(++tstart >= (60-6)) // increment tstart counter, if > 60*0.833mS
            {
            LEDR = 0; // turn ON Red led
            OCR0A = STOP; // set pulse duration for STOP
            OCR0B = STOP; // set pulse duration for STOP
            }
        return;
        }

    if(diff >= (78-7) && diff <= (78+7)) // if F=800Hz (T=1250uS 78*16uS)
        {
        if(++t1 >= (31-3)) // increment tstop counter, if > 31*1.6mS
            {
            LEDR = 1; // turn OFF Red led
            OCR0B = CCW; // set pulse duration for CounterClockWise (MOT2)
            }
        }
}

void main(void)
{ 
    CLKPR = 0x80; // enable writing to CLKPR register
    CLKPR = 0; // clock frequency = Fosc/1 (4 MHz)
    
// Pin    10       9      19      18      17      16      15      14
//      --------------------------------------------------------------
// Port  PB.7    PB.6    PB.5    PB.4    PB.3    PB.2    PB.1    PB.0
// Func [XTAL2] [XTAL1]  [SCK]  [MISO]  [OC2A]  [OC1B]  [OC1A]  [ICP1]
// Func [TOSC2] [TOSC1]                 [MOSI]   [/SS]          [CLKO]
// I/O                                           test            FrqIn                  
    PORTB = 0xFF;   // 1111.1111
    DDRB = 0xFE;    // 1111.1110 (0=input)

// Pin             1      28      27      26      25      24      23
//      --------------------------------------------------------------
// Port          PC.6    PC.5    PC.4    PC.3    PC.2    PC.1    PC.0
// Func         [/RES]  [ADC5]  [ADC4]  [ADC3]  [ADC2]  [ADC1]  [ADC0]
// Func                  [SCL]   [SDA]
// I/O                                                                 
    PORTC = 0xFF;   // 1111.1111
    DDRC = 0xBF;    // 1011.1111 (0=input)

// Pin    13      12      11       6       5       4       3       2
//      --------------------------------------------------------------
// Port  PD.7    PD.6    PD.5    PD.4    PD.3    PD.2    PD.1    PD.0
// Func [AIN1]  [AIN0]   [T1]    [T0]   [INT1]  [INT0]   [TXD]   [RXD] 
// Func         [OC0A]  [OC0B]  [XCK]   [OC2B]
// I/O   LEDR    MOT1    MOT2                                             
    PORTD = 0xFF;   // 1111.1111
    DDRD = 0xFF;    // 1111.1111 (0=input)

//  Pin    7       8      20      21      22
//      -------------------------------------
//  Func [VCC]   [GND]  [AVCC]  [AREF]  [GND]  

    OCR0A = STOP; // set pulse duration (OCR0A*64 uS) every 16,384 mS
    OCR0B = STOP; // set pulse duration (OCR0B*64 uS) every 16,384 mS
    TCCR0A = 0xA3; // 1010.0011 TMR0 is Fast PWM mode, 8 bits
    TCCR0B = 0x04; // 0000.0100 TMR0 clock is IOclk/256 = 15625 Hz (64uS)
    TIMSK0 = (1<<TOIE0); // enable TMR0 Overflow interrupt

    TCCR1B = 0x83; // 1000.0011 activate IC Noise Canceler, IOclk/64 (16uS)
    TIMSK1 = (1<<ICIE1); // enable Input Capture interrupt

    GPIOR1 = MCUSR; // read MCU reset status in GPIO Register[1]
    MCUSR = 0; // clear flags (8 Watchdog, 4 Brownout, 2 External, 1 Power-on)

    // enable watchdog, timeout = 2 sec
    SetWatchdog((1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0));
    if(GPIOR1 & 8) // if micro was been reset from watchdog
        DebugBurst(); // burst on TEST output

    __enable_interrupt(); // global interrupts enable
    for(;;) // main loop  
        {    
        __watchdog_reset(); // kick the watchdog
        if(cap) // if new capture flag set
            {
            __disable_interrupt(); // global interrupts disable
            cap = 0; // reset flag
            __enable_interrupt(); // global interrupts enable
            DecodeTone();
            }
        } 
}