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


UsartBridgeTerminal terminalUsartBridge;

extern Terminal* pTerminal;

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

//PUTCHAR_PROTOTYPE   
int putchar(int ch)    
{   
    terminalUsartBridge.uart.Instance->TDR = (uint16_t)(ch & 0x01FF);
    while (!(terminalUsartBridge.uart.Instance->ISR & UART_FLAG_TC)) {}
  
    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),
    m_isTxNoEmpty(false)
{
}

UsartBridgeTerminal::~UsartBridgeTerminal()
{
}


//Configure hardware and link with terminal
void UsartBridgeTerminal::configure()
{
    m_sizeCache = 0;
    m_readIndex = 0;
    m_isTxNoEmpty = false;
	
    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) 
{
    HAL_UART_IRQHandler(&terminalUsartBridge.uart);
}
}


//void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
void HAL_UART_RxCpltCallbackTerminal(void)
{
    if (terminalUsartBridge.m_state) {
        terminalUsartBridge.recvByte();
    }
      
    HAL_UART_Receive_IT(&terminalUsartBridge.uart, (uint8_t*)&terminalUsartBridge.m_uartByte, 1);
}


//void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
void HAL_UART_TxCpltCallbackTerminal(void)
{
    terminalUsartBridge.clearTxNoEmpty();
}


//Recv byte from usart
void UsartBridgeTerminal::recvByte()
{
    sbsTerminal.put_byte((char)(uart.Instance->RDR & (uint16_t)0x01FF));
}


//Send byte to usart
void UsartBridgeTerminal::sendByte(uint8_t byte)
{
    m_isTxNoEmpty = true;
    terminalUsartBridge.uart.Instance->TDR = (uint16_t)(byte & 0x01FF);
    while (!(terminalUsartBridge.uart.Instance->ISR & UART_FLAG_TC)) {}
}


//Clear TX No Empty flag
void UsartBridgeTerminal::clearTxNoEmpty() 
{
    m_isTxNoEmpty = false;
}


//Init USART
void UsartBridgeTerminal::InitUsart()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    USART_BRIDGE_TX_PORT_CLK_ENABLE
    USART_BRIDGE_RX_PORT_CLK_ENABLE  
  
    GPIO_InitStruct.Pin       = USART_BRIDGE_TX_PIN;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = USART_BRIDGE_AF;
    HAL_GPIO_Init(USART_BRIDGE_TX_PORT, &GPIO_InitStruct);
      
    GPIO_InitStruct.Pin       = USART_BRIDGE_RX_PIN;
    HAL_GPIO_Init(USART_BRIDGE_RX_PORT, &GPIO_InitStruct);  
      

    USART_BRIDGE_CLK_ENABLE

    uart.Instance           = USART_BRIDGE_USART;
    uart.Init.BaudRate      = USART_BRIDGE_SPEED;
    uart.Init.WordLength    = UART_WORDLENGTH_8B;
    uart.Init.StopBits      = UART_STOPBITS_1;
    uart.Init.Parity        = UART_PARITY_NONE;
    uart.Init.Mode          = UART_MODE_TX_RX;
    uart.Init.HwFlowCtl     = UART_HWCONTROL_NONE;
    uart.Init.OverSampling  = UART_OVERSAMPLING_8;
    uart.Init.OneBitSampling= UART_ONE_BIT_SAMPLE_DISABLE;
    HAL_UART_Init(&uart);

    HAL_NVIC_SetPriority(USART_BRIDGE_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(USART_BRIDGE_IRQn);
    HAL_UART_Receive_IT(&uart, (uint8_t*)&m_uartByte, 1);
}
