#include "lprintf.h"
#include "lprintf_config.h"
#include "chip.h"
#include <stdlib.h>

#ifndef LPRINTF_UART_NUM
    #error lprintf uart number is not specified
#endif


#if LPRINTF_UART_NUM == 0
    #define LPRINTF_UART_PIN_TX         CHIP_PIN_PD07_UART0_TX
    #define LPRINTF_UART_PIN_TX_OFFCFG  CHIP_PIN_PD07_GPIO
#elif LPRINTF_UART_NUM == 1
    #define LPRINTF_UART_PIN_TX         CHIP_PIN_PG15_UART1_TX
    #define LPRINTF_UART_PIN_TX_OFFCFG  CHIP_PIN_PG15_GPIO
#else
    #error invalid lprintf uart number
#endif


#define LPRINTF_UART_REG_CLK                LPRINTF_UART_REG_CLK_(LPRINTF_UART_NUM)
#define LPRINTF_UART_REG_CLK_(num)          LPRINTF_UART_REG_CLK__(num)
#define LPRINTF_UART_REG_CLK__(num)         *pREG_UART ## num ## _CLK

#define LPRINTF_UART_REG_CTL                LPRINTF_UART_REG_CTL_(LPRINTF_UART_NUM)
#define LPRINTF_UART_REG_CTL_(num)          LPRINTF_UART_REG_CTL__(num)
#define LPRINTF_UART_REG_CTL__(num)         *pREG_UART ## num ## _CTL

#define LPRINTF_UART_REG_STAT                LPRINTF_UART_REG_STAT_(LPRINTF_UART_NUM)
#define LPRINTF_UART_REG_STAT_(num)          LPRINTF_UART_REG_STAT__(num)
#define LPRINTF_UART_REG_STAT__(num)         *pREG_UART ## num ## _STAT

#define LPRINTF_UART_REG_TX                LPRINTF_UART_REG_TX_(LPRINTF_UART_NUM)
#define LPRINTF_UART_REG_TX_(num)          LPRINTF_UART_REG_TX__(num)
#define LPRINTF_UART_REG_TX__(num)         *pREG_UART ## num ## _THR






int lprintf_uart_init(uint32_t baud, uint8_t databits, t_lprintf_uart_parity parity) {
    int err = 0;
    unsigned ctl = 0;

    CHIP_PIN_CONFIG(LPRINTF_UART_PIN_TX);

    if (!err) {
        if (parity == LPRINTF_UART_PARITY_EVEN) {
            ctl |= (BITM_UART_CTL_EPS | BITM_UART_CTL_PEN);
        } else if (parity == LPRINTF_UART_PARITY_ODD) {
            ctl |= BITM_UART_CTL_PEN;
        } else if (parity != LPRINTF_UART_PARITY_NONE) {
            err = -1;
        }
    }

    if (!err) {
       if ((databits >= 5) && (databits <= 8)) {
           ctl |= (databits-5) << BITP_UART_CTL_WLS;
       } else {
           err = -1;
       }
    }

    if (!err) {
        LPRINTF_UART_REG_CTL = 0;
        if (baud > 0) {
            unsigned baud_div = CHIP_CLKF_SCLK0/baud + 0.5;
            LPRINTF_UART_REG_CLK = BITM_UART_CLK_EDBO | ((baud_div << BITP_UART_CLK_DIV) & BITM_UART_CLK_DIV);
        }
        LPRINTF_UART_REG_CTL = ctl | BITM_UART_CTL_EN;
    }


    return err;
}

void lprintf_putchar(char c) {
    while (!(LPRINTF_UART_REG_STAT & BITM_UART_STAT_THRE)) {}
    LPRINTF_UART_REG_TX = c;
}

void lprintf_close(void) {
    while (!(LPRINTF_UART_REG_STAT & BITM_UART_STAT_TEMT)) {}
    LPRINTF_UART_REG_CTL = 0;
    CHIP_PIN_CONFIG(LPRINTF_UART_PIN_TX_OFFCFG);
}
