/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef INCLUDE_ECXX_PLATFORM_AVR_ISR_TIMER0_CPP
#error "this file cannot be compiled directly"
#endif
#undef INCLUDE_ECXX_PLATFORM_AVR_ISR_TIMER0_CPP


/*
 * Timer0 is set to tick every 64 clock cycles. Timer0's overflow handler is called every 256 ticks.
 * Therefore, in relation to the CPU frequency, the number of microseconds for each overflow are:
 *    128 kHz : 128000 uS
 *      1 MHz :  16384 uS
 *      2 MHz :   8192 uS
 *      4 MHz :   4096 uS
 *      8 MHz :   2048 uS
 *     12 MHz :   1365 uS
 *     16 MHz :   1024 uS
 *     20 MHz :    819 uS
 *
 * The whole number of milliseconds per Timer0 overflow can be then derived:
 *    128 kHz : 128 mS
 *      1 MHz :  16 mS
 *      2 MHz :   8 mS
 *      4 MHz :   4 mS
 *      8 MHz :   2 mS
 *     12 MHz :   1 mS
 *     16 MHz :   1 mS
 *     20 MHz :   0 mS
 *
 * The fractional number of milliseconds (thus, microseconds) per Timer0 overflow are then:
 *    128 kHz :   0 uS
 *      1 MHz : 384 uS
 *      2 MHz : 192 uS
 *      4 MHz :  96 uS
 *      8 MHz :  48 uS
 *     12 MHz : 365 uS
 *     16 MHz :  24 uS
 *     20 MHz : 819 uS
 *
 * To reduce memory usage (with a slight lost of precision for some CPU frequency), those values can
 * be divided by 8 and thus they become:
 *    128 kHz :   0 steps
 *      1 MHz :  48 steps
 *      2 MHz :  24 steps
 *      4 MHz :  12 steps
 *      8 MHz :   6 steps
 *     12 MHz :  46 steps
 *     16 MHz :   3 steps
 *     20 MHz : 102 steps
 */


//
// Used for millis() and micros()
//
static          eCxx::uint16_t t0MillisInc;
static          eCxx::uint8_t  t0FractFInc;

static volatile eCxx::uint32_t t0OVFCount = 0;
static volatile eCxx::uint32_t t0Millis   = 0;
static          eCxx::uint16_t t0Fract    = 0;


//
// Timer0 interrupt vector
//
#if defined(TIM0_OVF_vect)
ISR(TIM0_OVF_vect)
#elif defined(TIMER0_OVF_vect)
ISR(TIMER0_OVF_vect)
#else
#error "unsupported Timer0 'Overflow' interrupt vector name"
#endif
{
    // Create a local copy of the variables
    eCxx::uint32_t millis = t0Millis;
    eCxx::uint16_t fract  = t0Fract;

    // Increment the variables
    millis += t0MillisInc;
    fract  += t0FractFInc;

    // Check if we have got a full fractional and hence can increment the millis by one
    if(fract >= (1000 >> 3) ) {
        fract -= (1000 >> 3);
        ++millis;
    }

    // Store back the variables
    t0Fract  = fract;
    t0Millis = millis;

    // Increment the Timer0 overflow counter
    ++t0OVFCount;
}
