////////////////////////////////////////////////////////////////////////////////
// FW_VERSION  150627 (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 fast ClockWise
#define SCW     21  // Pulse width for motor run slow ClockWise
#define CCW     30  // Pulse width for motor run fast CounterClocWise
#define SCCW    23  // Pulse width for motor run slow 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 tdelay; // delay timer for last input capture 
volatile BYTE optime; // operation timer 16.384mS per step
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
BYTE mask; // mask for bits decoded from tones
BYTE cmd; // command received
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(optime) // if operation timer
        --optime; // decrement timer
    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 = 3; // restart delay time after last input capture (3*16.384mS)
    cap = 1; // set new capture flag
}

////////////////////////////////////////////////////////////////////////////////
// Main Program
// ------------
//
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 >= (52-5) && diff <= (52+5)) // if F=1.2KHz (T=833uS 52*16uS)
        {
        if(++tstart >= 48) // increment tstart counter, if > 40mS (48*0.833mS)
            {
            LEDR = 0; // turn ON Red led
            __disable_interrupt(); // global interrupts disable
            optime = ONESEC; // set operation time for command
            __enable_interrupt(); // global interrupts enable
            mask = 0x08; // init mask for tone bits
            cmd = 0; // reset incoming command
            tstart = 0; // reset counter
            }
        return; // exit here
        }

    if(optime == 0) // if operation time elapsed
        return; // exit here

    // the following code is executed only while optime != 0

    if(mask == 0) // if full 4 bit data received
        {
        switch(cmd) // select action to do
            {
            case 0x01: // MOT-Left Fast Forward
                OCR0A = CW;
                break;
            case 0x02: // MOT-Left Slow Forward
                OCR0A = SCW;
                break;
            case 0x03: // MOT-Left Stop
                OCR0A = STOP;
                break;
            case 0x05: // MOT-Left Slow Backward
                OCR0A = SCCW;
                break;
            case 0x06: // MOT-Left Fast Backward
                OCR0A = CCW;
                break;

            case 0x09: // MOT-Right Fast Forward
                OCR0B = CW;
                break;
            case 0x0A: // MOT-Right Slow Forward
                OCR0B = SCW;
                break;
            case 0x0B: // MOT-Right Stop
                OCR0B = STOP;
                break;
            case 0x0D: // MOT-Right Slow Backward
                OCR0B = SCCW;
                break;
            case 0x0E: // MOT-Right Fast Backward
                OCR0B = CCW;
                break;
            }
        __disable_interrupt(); // global interrupts disable
        optime = 0; // operation time terminated
        __enable_interrupt(); // global interrupts enable
        return; // exit here
        }

    if(diff >= (39-4) && diff <= (39+4)) // if F=1.6KHz (T=625uS 39*16uS)
        {
        if(++t0 >= 64) // increment tstart counter, if > 40mS (64*0.625mS)
            {
            cmd |= mask; // '1' bit received
            mask >>= 1; // shift right mask
            t0 = 0; // reset counter
            }
        return; // exit here
        }

    if(diff >= (78-7) && diff <= (78+7)) // if F=800Hz (T=1250uS 78*16uS)
        {
        if(++t1 >= 32) // increment tstop counter, if > 40mS (32*1.6mS)
            {
            mask >>= 1; // shift right mask ('0' bit received)
            t1 = 0; // reset counter
            }
        }
}

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    MOTL    MOTR                                             
    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(optime == 0) // if operative time elapsed
            LEDR = 1; // turn OFF Red led

        if(cap) // if new capture flag set
            {
            __disable_interrupt(); // global interrupts enable
            cap = 0; // reset flag
            __enable_interrupt(); // global interrupts enable
            DecodeTone();
            }
        } 
}