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

/*
 * If you are not using a bootloader, please set the correct fuses for this firmware using:
 *
 *     avrdude -c usbasp -B 1 -p atmega8 -U lfuse:w:0xBF:m -U hfuse:w:0xD9:m -U lock:w:0x3F:m
 */


#include <eCxx/eCxx.h>


//
// Check the MCU
//
#if ( !defined(__AVR_ATmega8__) && !defined(__AVR_ATmega8A__) ) || ( (F_CPU) != 16000000UL )
#warning "this firmware is meant for ATmega8(A) at 16 MHz"
#endif


//
// For convenience
//
using App = eCxx::Application;


//
// Pin numbers
//
static constexpr eCxx::uint8_t I_EN_ =  8;

static constexpr eCxx::uint8_t O_V0  =  9;
static constexpr eCxx::uint8_t O_V1  = 10;
static constexpr eCxx::uint8_t O_V2  = 11;
static constexpr eCxx::uint8_t O_V3  = 12;
static constexpr eCxx::uint8_t O_V4  = 14;
static constexpr eCxx::uint8_t O_V5  = 15;
static constexpr eCxx::uint8_t O_V6  = 16;
static constexpr eCxx::uint8_t O_V7  = 17;


//
// Fast-digital-write data
//
static App::_PinFDW fdwV0;
static App::_PinFDW fdwV1;
static App::_PinFDW fdwV2;
static App::_PinFDW fdwV3;
static App::_PinFDW fdwV4;
static App::_PinFDW fdwV5;
static App::_PinFDW fdwV6;
static App::_PinFDW fdwV7;


//
// The init function
//
void eCxx_user_init()
{
    // Initialize application
    const App::Config config( false, App::Config::WDTO::_250mS );

    App::initialize(config);

    // Initialize the EN\ pin
    App::setPinMode(I_EN_, App::PinMode::InputPullUp);

    // Initialize the virtual output port pins
    App::setPinMode(O_V0, App::PinMode::Output);
    App::setPinMode(O_V1, App::PinMode::Output);
    App::setPinMode(O_V2, App::PinMode::Output);
    App::setPinMode(O_V3, App::PinMode::Output);
    App::setPinMode(O_V4, App::PinMode::Output);
    App::setPinMode(O_V5, App::PinMode::Output);
    App::setPinMode(O_V6, App::PinMode::Output);
    App::setPinMode(O_V7, App::PinMode::Output);

    App::digitalWrite(O_V0, false);
    App::digitalWrite(O_V1, false);
    App::digitalWrite(O_V2, false);
    App::digitalWrite(O_V3, false);
    App::digitalWrite(O_V4, false);
    App::digitalWrite(O_V5, false);
    App::digitalWrite(O_V6, false);
    App::digitalWrite(O_V7, false);

    // Prepare the fast-digital-write data
    App::_preparePinFDW(fdwV0, O_V0);
    App::_preparePinFDW(fdwV1, O_V1);
    App::_preparePinFDW(fdwV2, O_V2);
    App::_preparePinFDW(fdwV3, O_V3);
    App::_preparePinFDW(fdwV4, O_V4);
    App::_preparePinFDW(fdwV5, O_V5);
    App::_preparePinFDW(fdwV6, O_V6);
    App::_preparePinFDW(fdwV7, O_V7);

    // Initialize UART
    App::uart().begin(115200);
}


//
// The task function
//
void eCxx_user_task()
{
    // Process event
    eCxx::Application::processEvent();

    // Simply return if EN\ is not asserted (active low)
    if( App::digitalRead(I_EN_) ) return;

    // Read from UART and send it to the virtual output port
    auto& uart = App::uart();

    if( uart.canRead() ) {
        // Read a byte from UART
        eCxx::uint8_t c;
        uart.read(c);
        // Send the bits
        fdwV7(c & 0b10000000);
        fdwV6(c & 0b01000000);
        fdwV5(c & 0b00100000);
        fdwV4(c & 0b00010000);
        fdwV3(c & 0b00001000);
        fdwV2(c & 0b00000100);
        fdwV1(c & 0b00000010);
        fdwV0(c & 0b00000001);
    }
}
