#include "chip.h"
#include "lprintf.h"
#include "lprintf_config.h"

#define LPRINTF_UART_PREFIX  UART

#define LPRINTF_UART                        LPRINTF_UART_(LPRINTF_UART_PREFIX, LPRINTF_UART_NUM)
#define LPRINTF_UART_(pref, num)            LPRINTF_UART__(pref, num)
#define LPRINTF_UART__(pref, num)           CHIP_REGS_ ## pref ## num

#define LPRINTF_UART_PER_ID                 LPRINTF_UART_PER_ID_(LPRINTF_UART_PREFIX, LPRINTF_UART_NUM)
#define LPRINTF_UART_PER_ID_(pref, num)     LPRINTF_UART_PER_ID__(pref, num)
#define LPRINTF_UART_PER_ID__(pref, num)    CHIP_PER_ID_ ## pref ## num


#define LPRINTF_UART_CLK_FREQ               LPRINTF_UART_CLK_FREQ_(LPRINTF_UART_PREFIX, LPRINTF_UART_NUM)
#define LPRINTF_UART_CLK_FREQ_(pref, num)   LPRINTF_UART_CLK_FREQ__(pref, num)
#define LPRINTF_UART_CLK_FREQ__(pref, num)  CHIP_CLK_ ## pref ## num ## _FREQ







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

   uint32_t lcrh = LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_FEN, 1);


    if (databits == 5) {
        lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_WLEN, CHIP_REGFLDVAL_UART_LCRH_WLEN_5);
    } else if (databits == 6) {
        lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_WLEN, CHIP_REGFLDVAL_UART_LCRH_WLEN_6);
    } else if (databits == 7) {
        lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_WLEN, CHIP_REGFLDVAL_UART_LCRH_WLEN_7);
    } else if (databits == 8) {
        lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_WLEN, CHIP_REGFLDVAL_UART_LCRH_WLEN_8);
    } else {
        err = LPRINTF_ERR_UART_INVALID_BITLEN;
    }

    if (!err) {
        if (parity == LPRINTF_UART_PARITY_NONE) {
            lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_PEN, 0);
        } else if (parity == LPRINTF_UART_PARITY_ODD) {
            lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_PEN, 1)
                    | LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_EPS, CHIP_REGFLDVAL_UART_LCRH_EPS_ODD);
        } else if (parity == LPRINTF_UART_PARITY_EVEN) {
            lcrh |= LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_PEN, 1)
                    | LBITFIELD_SET(CHIP_REGFLD_UART_LCRH_EPS, CHIP_REGFLDVAL_UART_LCRH_EPS_EVEN);
        } else {
            err = LPRINTF_ERR_UART_INVALID_PARITY;
        }
    }

    if (!err) {
        chip_per_clk_en(LPRINTF_UART_PER_ID);




        uint32_t div = (LPRINTF_UART_CLK_FREQ * 4 + baud/2) / baud;
        uint32_t idiv = div >> 6;
        uint32_t fdiv = div & 0x3F;

        if (idiv > 0xFFFF)
            idiv = 0xFFFF;

        LPRINTF_UART->IBRD = idiv;
        LPRINTF_UART->FBRD = fdiv;
        LPRINTF_UART->LCRH = lcrh;

        LPRINTF_UART->CR = CHIP_REGFLD_UART_CR_TXE | CHIP_REGFLD_UART_CR_UART_EN;

#ifdef LPRINTF_UART_TX_PIN
        CHIP_PIN_CONFIG(LPRINTF_UART_TX_PIN);
#endif
    }


    return err;
}


void lprintf_close(void) {
    /* ожидание завершения передачи */
    while (lprintf_uart_busy())
        continue;
#ifdef LPRINTF_UART_TX_PIN
    CHIP_PIN_CONFIG(LPRINTF_UART_TX_PIN);
#endif
    LPRINTF_UART->CR = 0;
    chip_per_clk_dis(LPRINTF_UART_PER_ID);
}

void lprintf_putchar(char c) {
    while ((LPRINTF_UART->FR & CHIP_REGFLD_UART_FR_TXFF) != 0) {
        continue;
    }
    LPRINTF_UART->DR = LBITFIELD_SET(CHIP_REGFLD_UART_DR_DATA, c);
}

int lprintf_uart_busy(void) {
    return (LPRINTF_UART->FR & CHIP_REGFLD_UART_FR_BUSY) != 0;
}
