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


#include <eCxx/CTL/Types.h>


#ifndef ECXX_PLATFORM_AVRX_REAL_TIME_COUNTER_H
#define ECXX_PLATFORM_AVRX_REAL_TIME_COUNTER_H


#if defined(__AVR_ATmega808__) || defined(__AVR_ATmega1608__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega4808__) || \
    defined(__AVR_ATmega809__) || defined(__AVR_ATmega1609__) || defined(__AVR_ATmega3209__) || defined(__AVR_ATmega4809__)


namespace eCxx {


//
// A simple AVR real-time counter wrapper
//
// NOTE : Not all event generator and user constants defined below are
//        fully supported by eCxx and/or the target MCU.
//
class RealTimeCounter : public Uninstantiable {
    public:
        // Clock source
        enum class ClockSource : uint8_t {
            // These values are derived from the datasheet
            Internal32K = 0x00, // Internal 32768 Hz oscillator (default)
            Internal1K  = 0x01, // Internal  1024 Hz oscillator
            External    = 0x03  // External EXTCLK pin
        };

        // Clock prescaler
        enum class ClockPrescaler : uint8_t {
            // These values are derived from the datasheet
                _1 = 0x00, // RTC_Clock = ClockSource /     1 (default)
                _2 = 0x01, // RTC_Clock = ClockSource /     2
                _4 = 0x02, // RTC_Clock = ClockSource /     4
                _8 = 0x03, // RTC_Clock = ClockSource /     8
               _16 = 0x04, // RTC_Clock = ClockSource /    16
               _32 = 0x05, // RTC_Clock = ClockSource /    32
               _64 = 0x06, // RTC_Clock = ClockSource /    64
              _128 = 0x07, // RTC_Clock = ClockSource /   128
              _256 = 0x08, // RTC_Clock = ClockSource /   256
              _512 = 0x09, // RTC_Clock = ClockSource /   512
             _1024 = 0x0A, // RTC_Clock = ClockSource /  1024
             _2048 = 0x0B, // RTC_Clock = ClockSource /  2048
             _4096 = 0x0C, // RTC_Clock = ClockSource /  4096
             _8192 = 0x0D, // RTC_Clock = ClockSource /  8192
            _16384 = 0x0E, // RTC_Clock = ClockSource / 16384
            _32768 = 0x0F  // RTC_Clock = ClockSource / 32768
        };

        // Periodic interrupt cycle
        enum class PICycle : uint8_t {
            Disabled = 0x00, // No interrupt
                _4   = 0x01, //     4 RTC_Clock cycles
                _8   = 0x02, //     8 RTC_Clock cycles
               _16   = 0x03, //    16 RTC_Clock cycles
               _32   = 0x04, //    32 RTC_Clock cycles
               _64   = 0x05, //    64 RTC_Clock cycles
              _128   = 0x06, //   128 RTC_Clock cycles
              _256   = 0x07, //   256 RTC_Clock cycles
              _512   = 0x08, //   512 RTC_Clock cycles
             _1024   = 0x09, //  1024 RTC_Clock cycles
             _2048   = 0x0A, //  2048 RTC_Clock cycles
             _4096   = 0x0B, //  4096 RTC_Clock cycles
             _8192   = 0x0C, //  8192 RTC_Clock cycles
            _16384   = 0x0D, // 16384 RTC_Clock cycles
            _32768   = 0x0E  // 32768 RTC_Clock cycles
        };

    public:
        // Set clock source and prescaler
        static void setClock(
            ClockSource    source    = ClockSource::Internal32K,
            ClockPrescaler prescaler = ClockPrescaler::_1
        );

        // # Positive value will cause the prescaler to count slower.
        // # Negative value will cause the prescaler to count faster; it requires that
        //   the prescaler is set to a minimum value of ClockPrescaler::_2.
        static void setCrystalFrequencyCalibrationValue(int8_t value);

        // Start and stop
        static void start();
        static void stop();

        // Get the RTC running counter value
        static uint16_t getRunningCounterValue();

        // Overflow (overflow interrupt resets the RTC running counter)
        static void setOverflowPeriod(uint16_t value);
        static void attachOverflowInterrupt(eCxx::VoidCallback userFunc);
        static void detachOverflowInterrupt();

        // Compare-match (compare-match interrupt does not reset the RTC running counter)
        static void setCompareMatchValue(uint16_t value);
        static void attachCompareMatchInterrupt(eCxx::VoidCallback userFunc);
        static void detachCompareMatchInterrupt();

        // Periodic interrupt (it has nothing to do with the RTC running counter)
        static void setPeriodicInterruptCycle(PICycle cycle);
        static void attachPeriodicInterrupt(eCxx::VoidCallback userFunc);
        static void detachPeriodicInterrupt();
};


} // namespace eCxx


//
// Unsupported MCU
//
#else

#error "unsupported AVR MCU"

#endif


#endif
