/*
 * 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_TIMER_COUNTER_B_H
#define ECXX_PLATFORM_AVRX_TIMER_COUNTER_B_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 timer/counter type B wrapper
//
class TimerCounterB : public Uncopyable {
    public:
        ~TimerCounterB() = default;

    private:
         inline TimerCounterB(TCB_t* tcb, uint8_t pwmPortMuxBM, uint8_t pwmPinDef, uint8_t pwmPinAlt);

         friend class Application;

    public:
        // Clock source
        enum class ClockSource : uint8_t {
            // These values are derived from the datasheet
            Peripheral1 = 0x00, // Peripheral clock     (default)
            Peripheral2 = 0x01, // Peripheral clock / 2
            TCA         = 0x02  // TCA0       clock
        };

        // Mode of operation
        enum class Mode : uint8_t {
            // These values are derived from the datasheet
            PeriodicInterrupt       = 0x00, // Periodic interrupt (default)
            TimeoutCheck            = 0x01, // Time-out check
            ICaptOnEvent            = 0x02, // Input capture on event
            ICaptFreq               = 0x03, // Input capture frequency measurement
            ICaptPulseWidth         = 0x04, // Input capture pulse-width measurement
            ICaptFrequAndPulseWidth = 0x05, // Input capture frequency and pulse-width measurement
            OneShot                 = 0x06, // Single-shot
            PWM8                    = 0x07  // 8-bit PWM
        };

        // PWM output mode
        enum class PWMOutput : uint8_t {
            Disabled  = 0x00, // Disabled
            Default   = 0x01, // Default   output pin
            Alternate = 0x02  // Alternate output pin
        };

    public:
        // Set clock source
        void setClock(ClockSource source = ClockSource::Peripheral1);

        // Set mode
        void setMode(Mode mode = Mode::PeriodicInterrupt);

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

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

        // Get and set period
        uint16_t getPeriod();
        void setPeriod(uint16_t value);

        // Set PWM output mode
        bool setPMOutput(PWMOutput pwmOutput);
        void setPWMPeriodAndDutyCycle(uint8_t period, uint8_t duty);
        void setPWMDutyCycle(uint8_t value);

        // Interrupt
        void attachInterrupt(eCxx::VoidCallback userFunc);
        void detachInterrupt();

    private:
        TCB_t* const  _tcb;
        const uint8_t _pwmPortMuxBM;
        const uint8_t _pwmPinDef;
        const uint8_t _pwmPinAlt;
              uint8_t _pwmPin;

};


inline TimerCounterB::TimerCounterB(TCB_t* tcb, uint8_t pwmPortMuxBM, uint8_t pwmPinDef, uint8_t pwmPinAlt)
: _tcb         (tcb)
, _pwmPortMuxBM(pwmPortMuxBM)
, _pwmPinDef   (pwmPinDef)
, _pwmPinAlt   (pwmPinAlt)
, _pwmPin      (Application::InvalidPin)
{}


} // namespace eCxx


//
// Unsupported MCU
//
#else

#error "unsupported AVR MCU"

#endif


#endif
