#include "async.h"
#include "aum1_cm1.h"
#include "buffer.h"
#include "crash.h"
#include "gpio.h"
#include "timer.h"
#include "trace.h"
#include "uart.h"
#include "uart_async.h"

extern volatile uint32_t _vector_table[];

namespace {
using async::AwaitableType;

void Uart0Isr() {
    tracing::trace(tracing::TraceEvent::kUartIsr);
    HandleUartIsr();
}

void Timer0Isr() {
    tracing::dump();
    __builtin_trap();
}

void SetupUart() {
    InitUarts();

    _vector_table[16 + Uart0_IRQn] = reinterpret_cast<uint32_t>(Uart0Isr);
    NVIC_SetPriority(Uart0_IRQn, 3);
    NVIC_EnableIRQ(Uart0_IRQn);
}

void SetupTimer() {
    timer0->SetupAsWdt(100000 * 4000);
    timer0->EnableT1();

    _vector_table[16 + Timer0_IRQn] = reinterpret_cast<uint32_t>(Timer0Isr);
    NVIC_EnableIRQ(Timer0_IRQn);
}

async::task<> echo() {
    while (1) {
        buffer buff = co_await UartRead(1);
        co_await UartWrite(buff.data);
    }
}
}  // namespace

int main() {
    _vector_table[16 + HardFault_IRQn] =
        reinterpret_cast<uint32_t>(crash::HardFaultHandler);

    SetupUart();
    SetupTimer();

    async::schedule(echo().h);

    async::main_loop([]() {
        static int cnt = 0;
        timer0->Pet();
        if ((cnt++ % 100000) == 0) {
            ToggleLed(0);
        }
        return false;
    });
    // should never get here
}
