/*
 * 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>

#include "PinName.h"


#ifndef ECXX_PLATFORM_AVRX_EVENT_SYSTEM_H
#define ECXX_PLATFORM_AVRX_EVENT_SYSTEM_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 event system wrapper
//
// NOTE : Not all event generator and user constants defined below are
//        fully supported by eCxx and/or the target MCU.
//
class EventSystem : public Uninstantiable {
    public:
#if defined(__AVR_ATmega808__) || defined(__AVR_ATmega1608__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega4808__)
        static constexpr uint8_t EventSystemChannels = 6;
#else
        static constexpr uint8_t EventSystemChannels = 8;
#endif

        // Event generator
        enum class Generator : uint8_t {
            // These values are derived from the datasheet
            UPDI_SYNC        = 0x01, // UPDI SYNC character
            RTC_Overflow     = 0x06, // RTC overflow
            RTC_CompareMatch = 0x07, // RTC compare match
            RTC_PInt0        = 0x08, // RTC periodic interrupt : 8192 512 8192 512 8192 512 8192 512
            RTC_PInt1        = 0x09, // RTC periodic interrupt : 4096 256 4096 256 4096 256 4096 256
            RTC_PInt2        = 0x0A, // RTC periodic interrupt : 2048 128 2048 128 2048 128 2048 128
            RTC_PInt3        = 0x0B, // RTC periodic interrupt : 1048  64 1048  64 1048  64 1048  64
            CCL_LUT0         = 0x10, // CCL LUT0 output
            CCL_LUT1         = 0x11, // CCL LUT1 output
            CCL_LUT2         = 0x12, // CCL LUT2 output
            CCL_LUT3         = 0x13, // CCL LUT3 output
            AC0_Output       = 0x20, // Analog comparator output
            ADC0_ResultReady = 0x24, // ADC result ready
            Port0_Pin0       = 0x40, // Pin input : PORTA.0 PORTA.0 PORTC.0 PORTC.0 PORTE.0 PORTE.0 N/A N/A
            Port0_Pin1       = 0x41, // Pin input : PORTA.1 PORTA.1 PORTC.1 PORTC.1 PORTE.1 PORTE.1 N/A N/A
            Port0_Pin2       = 0x42, // Pin input : PORTA.2 PORTA.2 PORTC.2 PORTC.2 PORTE.2 PORTE.2 N/A N/A
            Port0_Pin3       = 0x43, // Pin input : PORTA.3 PORTA.3 PORTC.3 PORTC.3 PORTE.3 PORTE.3 N/A N/A
            Port0_Pin4       = 0x44, // Pin input : PORTA.4 PORTA.4 PORTC.4 PORTC.4 PORTE.4 PORTE.4 N/A N/A
            Port0_Pin5       = 0x45, // Pin input : PORTA.5 PORTA.5 PORTC.5 PORTC.5 PORTE.5 PORTE.5 N/A N/A
            Port0_Pin6       = 0x46, // Pin input : PORTA.6 PORTA.6 PORTC.6 PORTC.6 PORTE.6 PORTE.6 N/A N/A
            Port0_Pin7       = 0x47, // Pin input : PORTA.7 PORTA.7 PORTC.7 PORTC.7 PORTE.7 PORTE.7 N/A N/A
            Port1_Pin0       = 0x48, // Pin input : PORTB.0 PORTB.0 PORTD.0 PORTD.0 PORTF.0 PORTF.0 N/A N/A
            Port1_Pin1       = 0x49, // Pin input : PORTB.1 PORTB.1 PORTD.1 PORTD.1 PORTF.1 PORTF.1 N/A N/A
            Port1_Pin2       = 0x4A, // Pin input : PORTB.2 PORTB.2 PORTD.2 PORTD.2 PORTF.2 PORTF.2 N/A N/A
            Port1_Pin3       = 0x4B, // Pin input : PORTB.3 PORTB.3 PORTD.3 PORTD.3 PORTF.3 PORTF.3 N/A N/A
            Port1_Pin4       = 0x4C, // Pin input : PORTB.4 PORTB.4 PORTD.4 PORTD.4 PORTF.4 PORTF.4 N/A N/A
            Port1_Pin5       = 0x4D, // Pin input : PORTB.5 PORTB.5 PORTD.5 PORTD.5 PORTF.5 PORTF.5 N/A N/A
            Port1_Pin6       = 0x4E, // Pin input : PORTB.6 PORTB.6 PORTD.6 PORTC.6 PORTF.6 PORTF.6 N/A N/A
            Port1_Pin7       = 0x4F, // Pin input : PORTB.7 PORTB.7 PORTD.7 PORTC.7 PORTF.7 PORTF.7 N/A N/A
            USART0_XCK       = 0x60, // USART0 baudrate clock
            USART1_XCK       = 0x61, // USART1 baudrate clock
            USART2_XCK       = 0x62, // USART2 baudrate clock
            USART3_XCK       = 0x63, // USART3 baudrate clock
            USART4_XCK       = 0x64, // USART4 baudrate clock
            USART5_XCK       = 0x65, // USART5 baudrate clock
            USART6_XCK       = 0x66, // USART6 baudrate clock
            USART7_XCK       = 0x67, // USART7 baudrate clock
            SPI0_SCK         = 0x68, // SPI0 master clock
            TCA0_Overflow    = 0x80, // TCA0 overflow
            TCA0_Underflow   = 0x81, // TCA0 underflow in split mode
            TCA0_Compare0    = 0x84, // TCA0 compare match channel 0
            TCA0_Compare1    = 0x85, // TCA0 compare match channel 1
            TCA0_Compare2    = 0x86, // TCA0 compare match channel 2
            TCB0_Capture     = 0xA0, // TCB0  capture
            TCB1_Capture     = 0xA1, // TCB1  capture
            TCB2_Capture     = 0xA2, // TCB2  capture
            TCB3_Capture     = 0xA3, // TCB3  capture
            TCB4_Capture     = 0xA4, // TCB4  capture
            TCB5_Capture     = 0xA5, // TCB5  capture
            TCB6_Capture     = 0xA6, // TCB6  capture
            TCB7_Capture     = 0xA7, // TCB7  capture
            TCB8_Capture     = 0xA8, // TCB8  capture
            TCB9_Capture     = 0xA9, // TCB9  capture
            TCB10_Capture    = 0xAA, // TCB10 capture
            TCB11_Capture    = 0xAB, // TCB11 capture
            TCB12_Capture    = 0xAC, // TCB12 capture
            TCB13_Capture    = 0xAD, // TCB13 capture
            TCB14_Capture    = 0xAE, // TCB14 capture
            UnbindGenerator  = 0xFF  // A special value used to unbind channel from generator
        };

        // Event user
        enum class User : uint8_t {
            // These values are derived from the datasheet
            CCL_LUT0A    =   0, // CCL LUT0 input A
            CCL_LUT0B    =   1, // CCL LUT0 input B
            CCL_LUT1A    =   2, // CCL LUT1 input A
            CCL_LUT1B    =   3, // CCL LUT1 input B
            CCL_LUT2A    =   4, // CCL LUT2 input A
            CCL_LUT2B    =   5, // CCL LUT2 input B
            CCL_LUT3A    =   6, // CCL LUT3 input A
            CCL_LUT3B    =   7, // CCL LUT3 input B
            ADC0_Start   =   8, // ADC0 start trigger
            EVOUTA_Def   =   9, // Default pin output A
            EVOUTB_Def   =  10, // Default pin output B
            EVOUTC_Def   =  11, // Default pin output C
            EVOUTD_Def   =  12, // Default pin output D
            EVOUTE_Def   =  13, // Default pin output E
            EVOUTF_Def   =  14, // Default pin output F
            USART0_Input =  15, // USART0 event input
            USART1_Input =  16, // USART1 event input
            USART2_Input =  17, // USART2 event input
            USART3_Input =  18, // USART3 event input
            TCA_Input    =  19, // TCA0 input
            TCB0_Input   =  20, // TCB0 input
            TCB1_Input   =  21, // TCB1 input
            TCB2_Input   =  22, // TCB2 input
            TCB3_Input   =  23, // TCB3 input
            __STD_END__  =  23,
            __ALT_BEG__  = 209,
            EVOUTA_Alt   = 209, // Alternate pin output A
            EVOUTB_Alt   = 210, // Alternate pin output B
            EVOUTC_Alt   = 211, // Alternate pin output C
            EVOUTD_Alt   = 212, // Alternate pin output D
            EVOUTE_Alt   = 213, // Alternate pin output E
            EVOUTF_Alt   = 214, // Alternate pin output F
            __ALT_END__  = 214
        };

    public:
        // A special value used to unbind user from channel
        static constexpr uint8_t UnbindChannel = 0xFF;

        static bool bindChannelToGenerator(uint8_t channel, Generator generator);
        static bool bindUserToChannel(User user, uint8_t channel);

        static void strobeChannel(uint8_t channel);

    private:
        static bool configureOutputPin(User user, bool enabled);
};


} // namespace eCxx


//
// Unsupported MCU
//
#else

#error "unsupported AVR MCU"

#endif


#endif
