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


#include <eCxx/eCxx_InputDevice.h>

#include "AVR_Common.h"


//
// Uncomment this to use UART1 instead of the default UART
//
// #define USE_UART1


//
// Pin numbers
//
#ifndef __AVR_ARCH_X__

// ATmega328P : these eCxx pin numbers are the same as the pin numbers on the
//              silkscreen of Arduino and compatible boards
static constexpr eCxx::uint8_t PWM_R  =  9;
static constexpr eCxx::uint8_t PWM_G  = 10;
static constexpr eCxx::uint8_t PWM_B  = 11;

static constexpr eCxx::uint8_t ADC_V0 = 16;
static constexpr eCxx::uint8_t ADC_RD = 17;
static constexpr eCxx::uint8_t ADC_V5 = 18;

static constexpr eCxx::uint8_t INP_SW =  4;

#else

// ATmega4808
static constexpr eCxx::uint8_t PWM_R  = 14; // A0  on the silkscreen of Thinary ATmega4808 board
static constexpr eCxx::uint8_t PWM_G  = 15; // A1  on the silkscreen of Thinary ATmega4808 board
static constexpr eCxx::uint8_t PWM_B  = 16; // A2  on the silkscreen of Thinary ATmega4808 board

static constexpr eCxx::uint8_t ADC_V0 = 18; // A4  on the silkscreen of Thinary ATmega4808 board
static constexpr eCxx::uint8_t ADC_RD = 19; // A5  on the silkscreen of Thinary ATmega4808 board
static constexpr eCxx::uint8_t ADC_V5 = 20; // A6  on the silkscreen of Thinary ATmega4808 board

static constexpr eCxx::uint8_t INP_SW = 24; // D24 on the silkscreen of Thinary ATmega4808 board

#endif


//
// Instantiate the switch debouncer
//
static eCxx::Debounce8Switch db8sw;


//
// The init function
//
void eCxx_user_init()
{
    // Initialize application
    initBasicAVRApp();

    // Set the RGB LED pins as output and turn them off initially
    App::setPinMode(PWM_R, App::PinMode::Output);
    App::setPinMode(PWM_G, App::PinMode::Output);
    App::setPinMode(PWM_B, App::PinMode::Output);

    App::digitalWrite(PWM_R, true); // Active low
    App::digitalWrite(PWM_G, true); // Active low
    App::digitalWrite(PWM_B, true); // Active low

    // Set the ADC voltage source pins as output and read pin as input
    App::setPinMode(ADC_V0, App::PinMode::Output);
    App::setPinMode(ADC_RD, App::PinMode::Input );
    App::setPinMode(ADC_V5, App::PinMode::Output);

    App::digitalWrite(ADC_V0, false);
    App::digitalWrite(ADC_V5, true );

    // Set the switch pin as input
    App::setPinMode(INP_SW, App::PinMode::InputPullUp);

    // Initialize UART
#ifndef USE_UART1
    App::uart().begin(9600);
#else
    App::uart1()->begin(9600);
#endif
}


//
// The task function
//
void eCxx_user_task()
{
    // Process event and delay
    static eCxx::uint32_t prvMillis = 0;
           eCxx::uint32_t curMillis = App::processEvent();
    if(curMillis - prvMillis < 10) return;
    else                           prvMillis = curMillis;

    // Read ADC
    const eCxx::uint8_t adcVal = App::analogRead(ADC_RD) / 4;

    // Output PWM values
    static eCxx::uint8_t curChn = 0;
    static eCxx::uint8_t curVal = 0;
    static eCxx::uint8_t curDir = 1;

    if(curDir > 0) {
        if(curVal < adcVal) ++curVal;
        else                curDir = 0;
    }
    else {
        if(curVal > 0) --curVal;
        else           curDir = 1;
    }

    App::analogWrite( PWM_R, 255 - ( (curChn == 0) ? curVal : 0 ) ); // The LED is active low
    App::analogWrite( PWM_G, 255 - ( (curChn == 1) ? curVal : 0 ) ); // The LED is active low
    App::analogWrite( PWM_B, 255 - ( (curChn == 2) ? curVal : 0 ) ); // The LED is active low

    // Read the switch
    if( App::digitalRead(INP_SW) ) db8sw.debounce(0b00000000); // The switch is active low
    else                           db8sw.debounce(0b00000001);

    if( db8sw.pressed(0b00000001) ) {
        ++curChn;
        if(curChn > 2) curChn = 0;
    }

    // Read from UART and write it back
#ifndef USE_UART1
    auto& uart = App::uart();
#else
    auto& uart = *App::uart1();
#endif
    if( uart.canRead() ) {
        eCxx::uint8_t c;
        uart.read(c);

#if 1
        uart.printfString( PGM_STR("Got: %c\n"), c);
#else
        uart.writeString( PGM_STR("Got: ") );
        uart.write(c);
        uart.write('\n');
#endif
    }
}
