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


#ifndef ECXX_PLATFORM_AVRX_PIN_MAPPING_H
#define ECXX_PLATFORM_AVRX_PIN_MAPPING_H


//
// Internal constants
//

// Special marker
#define ECXX_NOT_ADC AVR::InvalidPin
#define ECXX_NOT_PWM AVR::InvalidPin

// Port number
#define ECXX_PA 0
#define ECXX_PB 1
#define ECXX_PC 2
#define ECXX_PD 3
#define ECXX_PE 4
#define ECXX_PF 5

// Timer
#define ECXX_TIMERA0 1
#define ECXX_TIMERB0 2
#define ECXX_TIMERB1 3
#define ECXX_TIMERB2 4
#define ECXX_TIMERB3 5

// A special macro to be used to declare array for direct digital configure/read/write
// as well as for normal digital configure/read/write
#ifdef ECXX_DECLARE_ARRAY_FOR_DDX
    #define ECXX_UINT8_ARRAY static constexpr uint8_t
#else
    #define ECXX_UINT8_ARRAY static const uint8_t PROGMEM
#endif


namespace eCxx {


//
// Include the appropriate standard pin mapping header file
//
#define INCLUDE_ECXX_PLATFORM_AVRX_PIN_MAPPING_STD_H


#if defined(__AVR_ATmega808__) || defined(__AVR_ATmega1608__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega4808__)

    #include "PinMapping_Std_AXCDXF.h"


#elif defined(__AVR_ATmega809__) || defined(__AVR_ATmega1609__) || defined(__AVR_ATmega3209__) || defined(__AVR_ATmega4809__)

    #include "PinMapping_Std_ABCDEF.h"


#endif


#ifdef INCLUDE_ECXX_PLATFORM_AVRX_PIN_MAPPING_STD_H
    #error "unsupported AVR MCU"
#endif


//
// Internal utility functions
//
static inline uint8_t pinNumberToPortNumber (uint8_t pin) { return ECXX_PGM_READ_BYTE( eCxx::PGM_PTR(pin_to_port_number,  pin                  ).p ); }
static inline uint8_t pinNumberToBitPosition(uint8_t pin) { return ECXX_PGM_READ_BYTE( eCxx::PGM_PTR(pin_to_bit_position, pin                  ).p ); }
static inline uint8_t pinNumberToBitmask    (uint8_t pin) { return ECXX_PGM_READ_BYTE( eCxx::PGM_PTR(pin_to_bit_mask,     pin                  ).p ); }
static inline uint8_t pinNumberToPWMTimer   (uint8_t pin) { return ECXX_PGM_READ_BYTE( eCxx::PGM_PTR(pin_to_pwm_timer,    pin - minPWMPinNumber).p ); }
static inline uint8_t pinNumberToADCChannel (uint8_t pin) { return ECXX_PGM_READ_BYTE( eCxx::PGM_PTR(pin_to_adc_channel,  pin - minADCPinNumber).p ); }


using PORT = volatile PORT_t*;
using REG8 = volatile uint8_t*;

static inline PORT pinNumberToPort      (           uint8_t pin   ) { return &PORTA + pinNumberToPortNumber(pin); }
static inline PORT portNumberToPort     (           uint8_t port  ) { return &PORTA + port;                       }
static inline REG8 getPinControlRegister(PORT port, uint8_t bitPos) { return &(port->PIN0CTRL) + bitPos;          }


} // namespace eCxx


#endif
