#include "terminal_usartbridge.h"
#include "terminal_sbs.h"
#include <string.h>
#include <stdio.h>

//Usart bridge object for global terminal
UsartBridgeTerminal terminalUsartBridge;

//Pointer to global terminal object
extern Terminal* pTerminal;


#ifdef __GNUC__    
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)    
#else    
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)    
#endif  

PUTCHAR_PROTOTYPE   
{   
    while (usart_flag_get(USART_BRIDGE_USART, USART_TDBE_FLAG) == RESET);
    usart_data_transmit(USART_BRIDGE_USART, (uint16_t)ch);
    while (usart_flag_get(USART_BRIDGE_USART, USART_TDC_FLAG) == RESET);
    
    return ch;
}  


//-----------------------------------------------------------------------------
// Connect usartBridge objectt with ANSI C Interfaces
//-----------------------------------------------------------------------------

//Configure usart bridge
void configure_usartbridge() {
    terminalUsartBridge.configure();
}

//Print callback for terminal object
void print_usartbridge(const char * str) {
    terminalUsartBridge.print(str);
}

//-----------------------------------------------------------------------------
// Usart Bridge for terminal
//-----------------------------------------------------------------------------
UsartBridgeTerminal::UsartBridgeTerminal():
    m_readIndex(0),
    m_state(true)
{
}

UsartBridgeTerminal::~UsartBridgeTerminal()
{
}

//Configure hardware and link with terminal
void UsartBridgeTerminal::configure()
{
    m_sizeCache = 0;
    m_readIndex = 0;
	
    InitUsart();

    //Add usart print to global terminal object
    pTerminal->addPrint(::print_usartbridge);
}

//print function
void UsartBridgeTerminal::print(const char *str)
{
    uint16_t index = 0;
    uint16_t len = strlen(str);
    if (len <= 0)
      return;
    
    while (index < len) {
        sendByte(str[index++]);
    }
}


//-----------------------------------------------------------------------------
// Hardware usart function
//-----------------------------------------------------------------------------

extern "C" {

void USART_BRIDGE_IRQHandler(void) 
{
    if (usart_flag_get(USART_BRIDGE_USART, USART_RDBF_FLAG) != RESET)
    {
        if (terminalUsartBridge.m_state) {
            terminalUsartBridge.recvByte();
        }
    }  
}

}

// Recv byte from usart
void UsartBridgeTerminal::recvByte()
{
    sbsTerminal.put_byte((char)USART_BRIDGE_USART->dt);
}

// Send byte to usart
void UsartBridgeTerminal::sendByte(uint8_t byte)
{
    USART_BRIDGE_USART->dt = (byte & 0x01FF);
    while (usart_flag_get(USART_BRIDGE_USART, USART_TDC_FLAG) == RESET) {}
}

// Init USART
void UsartBridgeTerminal::InitUsart()
{
    gpio_init_type gpio_init_struct;
    
    
    USART_BRIDGE_TX_PORT_CLK_ENABLE
    USART_BRIDGE_RX_PORT_CLK_ENABLE
      
    USART_BRIDGE_CLK_ENABLE
  
    gpio_default_para_init(&gpio_init_struct);

    /* configure the uart tx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = USART_BRIDGE_TX_PIN | USART_BRIDGE_RX_PIN;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(USART_BRIDGE_TX_PORT, &gpio_init_struct);
    
    gpio_init_struct.gpio_pins = USART_BRIDGE_RX_PIN;
    gpio_init(USART_BRIDGE_RX_PORT, &gpio_init_struct);
    
    /* configure uart param */
    usart_init(USART_BRIDGE_USART, USART_BRIDGE_SPEED, 
               USART_DATA_8BITS, USART_STOP_1_BIT);
    
    usart_transmitter_enable(USART_BRIDGE_USART, TRUE);
    usart_receiver_enable(USART_BRIDGE_USART, TRUE);
    usart_enable(USART_BRIDGE_USART, TRUE);
    
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    NVIC_ClearPendingIRQ(USART_BRIDGE_IRQn);
    nvic_irq_enable(USART_BRIDGE_IRQn, 6, 0);
    
    usart_interrupt_enable(USART_BRIDGE_USART, USART_RDBF_INT, TRUE);
}
