// uart.c
// KCO 2010.5.24
#include "common.h"
#include "uart.h"

char pop_tx1_buf(void);
char pop_tx2_buf(void);
char pop_tx3_buf(void);

#define UART1_TX_START  {if(txen1_use) TXEN1_ENABLE;   \
                            USART_ITConfig(USART1, USART_IT_TXE, ENABLE);}
#define UART2_TX_START  {if(txen2_use) TXEN2_ENABLE;   \
                            USART_ITConfig(USART2, USART_IT_TXE, ENABLE);}
#define UART3_TX_START  {if(txen3_use) TXEN3_ENABLE;   \
                            USART_ITConfig(USART3, USART_IT_TXE, ENABLE);}

#define	UART_TX_BUF_SIZE    200

char uart1_tx_buf[UART_TX_BUF_SIZE+1];
char uart1_tx_pos=0,uart1_tx_end=0;
char uart2_tx_buf[UART_TX_BUF_SIZE+1];
char uart2_tx_pos=0,uart2_tx_end=0;
char uart3_tx_buf[UART_TX_BUF_SIZE+1];
char uart3_tx_pos=0,uart3_tx_end=0;

u8 txen1_use=0,txen2_use=0,txen3_use=0;
u8 rx1_flag=0,rx2_flag=0,rx3_flag=0;
u8 rx1_data,rx2_data,rx3_data;
u8 rx1_cnt=0,rx2_cnt=0,rx3_cnt=0;

void push_tx1_buf(char c){
    uart1_tx_buf[uart1_tx_end++] = c;
    if(uart1_tx_end >= UART_TX_BUF_SIZE) uart1_tx_end = 0;
}
void push_tx2_buf(char c){
    uart2_tx_buf[uart2_tx_end++] = c;
    if(uart2_tx_end >= UART_TX_BUF_SIZE) uart2_tx_end = 0;
}
void push_tx3_buf(char c){
    uart3_tx_buf[uart3_tx_end++] = c;
    if(uart3_tx_end >= UART_TX_BUF_SIZE) uart3_tx_end = 0;
}

char pop_tx1_buf(void){
char  c;
    c = uart1_tx_buf[uart1_tx_pos++];
    if(uart1_tx_pos >= UART_TX_BUF_SIZE) uart1_tx_pos = 0;
    return c;
}
char pop_tx2_buf(void){
char  c;
    c = uart2_tx_buf[uart2_tx_pos++];
    if(uart2_tx_pos >= UART_TX_BUF_SIZE) uart2_tx_pos = 0;
    return c;
}
char pop_tx3_buf(void){
char  c;
    c = uart3_tx_buf[uart3_tx_pos++];
    if(uart3_tx_pos >= UART_TX_BUF_SIZE) uart3_tx_pos = 0;
    return c;
}

void init_uart(u8 uart, u32 bps, u8 txen){
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;    

    USART_InitStructure.USART_BaudRate = bps;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    switch(uart){
    case 1:
        /* Enable USART1 clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);   

        /* Configure USART1 Tx (PA9) as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure USART1 Rx (PA10) as Input */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        if(txen){   /* TXEN1 init */
            txen1_use = 1;
            GPIO_InitStructure.GPIO_Pin = TXEN1_PIN;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_Init(TXEN1_PORT, &GPIO_InitStructure);
        }
        else txen1_use = 0;
        
        /* UART1 init. */
        USART_Init(USART1, &USART_InitStructure);

        /* Enable the USART1 Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
        NVIC_Init(&NVIC_InitStructure);                   

        USART_ClearFlag(USART1, USART_FLAG_CTS | USART_FLAG_LBD  |
                            USART_FLAG_TC  | USART_FLAG_RXNE | USART_FLAG_IDLE |
                            USART_FLAG_ORE | USART_FLAG_NE   | USART_FLAG_FE |
                            USART_FLAG_PE);
        /* Enable USART1 Receive interrupt */
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);      

        /* Enable the USART1 */
        USART_Cmd(USART1, ENABLE);
        break;

    case 2:
        /* Enable USART2 clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_GPIOC, ENABLE); 
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 

        /* Configure USART2 Tx (PA2) as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure USART2 Rx (PA3) as Input*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        if(txen){   /* TXEN2 init */
            txen2_use = 1;
            GPIO_InitStructure.GPIO_Pin = TXEN2_PIN;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_Init(TXEN2_PORT, &GPIO_InitStructure);
        }
        else txen2_use = 0;

        /* UART2 init. */
        USART_Init(USART2, &USART_InitStructure);

        /* Enable the USART2 Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
        NVIC_Init(&NVIC_InitStructure);           
    
        USART_ClearFlag(USART2, USART_FLAG_CTS | USART_FLAG_LBD  |
                            USART_FLAG_TC  | USART_FLAG_RXNE | USART_FLAG_IDLE |
                            USART_FLAG_ORE | USART_FLAG_NE   | USART_FLAG_FE |
                            USART_FLAG_PE);

        /* Enable USART2 Receive interrupt */
        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);      
        
        /* Enable the USART2 */
        USART_Cmd(USART2, ENABLE);
        break;

    case 3:
        /* Enable USART3 clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); 
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); 

        /* Enable the USART3 Pins Software Remapping */
        GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);

        /* Configure USART3 Tx (PC10) as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOC, &GPIO_InitStructure);

        /* Configure USART3 Rx (PC11) as Input */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOC, &GPIO_InitStructure);


        if(txen){   /* TXEN3 init */
            txen3_use = 1;
            GPIO_InitStructure.GPIO_Pin = TXEN3_PIN;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_Init(TXEN3_PORT, &GPIO_InitStructure);
        }
        else txen3_use = 0;

        /* Enable the USART3 */
        USART_Init(USART3, &USART_InitStructure);

        /* Enable the USART3 Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
        NVIC_Init(&NVIC_InitStructure);           
    
        USART_ClearFlag(USART3, USART_FLAG_CTS | USART_FLAG_LBD  |
                            USART_FLAG_TC  | USART_FLAG_RXNE | USART_FLAG_IDLE |
                            USART_FLAG_ORE | USART_FLAG_NE   | USART_FLAG_FE |
                            USART_FLAG_PE);

        /* Enable USART3 Receive interrupt */
        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);      
        
        /* Enable the USART3 */
        USART_Cmd(USART3, ENABLE);
        break;
    default:    break;
    }
}
//////////////////// Polling tx function ////////////////////
void uart1_putc_p(char c){
   while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  
   USART_SendData(USART1,c);
}
void uart2_putc_p(char c){
   while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);  
   USART_SendData(USART2,c);
}
void uart3_putc_p(char c){
   while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);  
   USART_SendData(USART3,c);
}
void uart1_puts_p(char *p){
	while(*p) uart1_putc_p(*p++);
}
void uart2_puts_p(char *p){
	while(*p) uart2_putc_p(*p++);
}
void uart3_puts_p(char *p){
	while(*p) uart3_putc_p(*p++);
}
void uart1_printf_p(const char *fmt,...){
char str[256];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart1_puts_p(str);
}
void uart2_printf_p(const char *fmt,...){
char str[256];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart2_puts_p(str);
}
void uart3_printf_p(const char *fmt,...){
char str[256];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart3_puts_p(str);
}
//////////////////// Interrupt tx function ////////////////////
void uart1_putc(char c){
	push_tx1_buf(c);
	UART1_TX_START;
}
void uart2_putc(char c){
	push_tx2_buf(c);
	UART2_TX_START;
}
void uart3_putc(char c){
	push_tx3_buf(c);
	UART3_TX_START;
}

void uart1_puts(char *p){
char c;
	while(c = *p++) push_tx1_buf(c);
	UART1_TX_START;
}
void uart2_puts(char *p){
char c;
	while(c = *p++) push_tx2_buf(c);
	UART2_TX_START;
}
void uart3_puts(char *p){
char c;
	while(c = *p++) push_tx3_buf(c);
	UART3_TX_START;
}

void uart1_printf(const char *fmt,...){
char str[UART_TX_BUF_SIZE];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart1_puts(str);
}
void uart2_printf(const char *fmt,...){
char str[UART_TX_BUF_SIZE];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart2_puts(str);
}
void uart3_printf(const char *fmt,...){
char str[UART_TX_BUF_SIZE];
va_list ap;
	va_start(ap,fmt);
	vsprintf(str,fmt,ap);
	va_end(ap);
	uart3_puts(str);
}
///////////////// UART rx process /////////////////
void uart1_rx_process(u8 rxd){
    rx1_data = rxd;
    rx1_flag = 1;
}

void uart2_rx_process(u8 rxd){
    rx2_data = rxd;
    rx2_flag = 1;
}

void uart3_rx_process(u8 rxd){
    rx3_data = rxd;
    rx3_flag = 1;
}

//////////////// Interrupt Process ////////////////
void USART1_IRQHandler(void){
u8 rxd;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){  // Rx_int. process         
        rxd = USART_ReceiveData(USART1);
        uart1_rx_process(rxd);
        rx1_cnt++;

        // Clear the USART1 Receive interrupt
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);                  
    }

    if(USART_GetITStatus (USART1,USART_IT_TXE) == SET){   // Tx_int. process
        if(uart1_tx_pos != uart1_tx_end){
            USART_SendData(USART1,pop_tx1_buf());
        }
        else{
          USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
          if(txen1_use) USART_ITConfig(USART1, USART_IT_TC, ENABLE);
        }
    }
    if(USART_GetITStatus(USART1,USART_IT_TC) == SET){
      USART_ITConfig(USART1, USART_IT_TC, DISABLE);
      TXEN1_DISABLE;
    }
}
void USART2_IRQHandler(void){
u8 rxd;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){  // Rx_int. process         
        rxd = USART_ReceiveData(USART2);
        uart2_rx_process(rxd);
        rx2_cnt++;

        // Clear the USART2 Receive interrupt
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);                  
    }  
    if(USART_GetITStatus (USART2,USART_IT_TXE) == SET){   // Tx_int. process
        if(uart2_tx_pos != uart2_tx_end){
            USART_SendData(USART2,pop_tx2_buf());
        }
        else{
          USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
          if(txen2_use) USART_ITConfig(USART2, USART_IT_TC, ENABLE);
        }
    }
    if(USART_GetITStatus(USART2,USART_IT_TC) == SET){
      USART_ITConfig(USART2, USART_IT_TC, DISABLE);
      TXEN2_DISABLE;
    }
}
void USART3_IRQHandler(void){
u8 rxd;
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET){  // Rx_int. process         
        rxd = USART_ReceiveData(USART3);
        uart3_rx_process(rxd);
        rx3_cnt++;

        // Clear the USART3 Receive interrupt
        USART_ClearITPendingBit(USART3, USART_IT_RXNE);                  
    }  
    if(USART_GetITStatus (USART3,USART_IT_TXE) == SET){   // Tx_int. process
        if(uart3_tx_pos != uart3_tx_end){
            USART_SendData(USART3,pop_tx3_buf());
        }
        else{
          USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
          if(txen3_use) USART_ITConfig(USART3, USART_IT_TC, ENABLE);
        }
    }
    if(USART_GetITStatus(USART3,USART_IT_TC) == SET){
      USART_ITConfig(USART3, USART_IT_TC, DISABLE);
      TXEN3_DISABLE;
    }
}
