#include "at32f403a_407.h"
#include "at32f403a_407_board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "mb.h"
#include "port.h"
#include "mbport.h"
#include "tim_delay.h"
#include "mux.h"
#include <stdlib.h>
#include <stdbool.h>


#define MB_UART                 USART3
#define USART_INVALID_PORT      ( 0xFF )




void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    if (xRxEnable) {
        // В обработчике прерывания таймера будет включен режим приемника
        mb_helper_set_tx_state(false);
        mb_helper_tim_enable(); 
        usart_interrupt_enable(MB_UART, USART_RDBF_INT, TRUE);
	}
	else {
        usart_interrupt_enable(MB_UART, USART_RDBF_INT, FALSE);
	}
	if (xTxEnable) {
        gpio_bits_set(GPIOD, GPIO_PINS_10);
        mb_helper_set_tx_state(true);
        mb_helper_tim_enable();
	}
	else {
        // В обработчике прерывания таймера будет включен режим приемника
        mb_helper_set_tx_state(false);
        mb_helper_tim_enable();
        usart_interrupt_enable(MB_UART, USART_TDBE_INT, FALSE);
	}
}


BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, 
                   eMBParity eParity, unsigned int stop_bit )
{
#if 1  
    gpio_init_type gpio_init_struct;
    usart_parity_selection_type parity;
    usart_data_bit_num_type data_bits;
    usart_stop_bit_num_type stop_bits;

    crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
    gpio_pin_remap_config(USART3_GMUX_0011, TRUE);
    
    gpio_default_para_init(&gpio_init_struct);

    // configure 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 = GPIO_PINS_8 | GPIO_PINS_9;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOD, &gpio_init_struct);
    
    // configure DE 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_OUTPUT;
    gpio_init_struct.gpio_pins = GPIO_PINS_10;
    gpio_init_struct.gpio_pull = GPIO_PULL_UP;
    gpio_init(GPIOD, &gpio_init_struct);
    
    gpio_bits_reset(GPIOD, GPIO_PINS_10);
    //gpio_bits_set(GPIOD, GPIO_PINS_10);
    
    switch (eParity)
	{
		case MB_PAR_NONE :
            parity = USART_PARITY_NONE;
            data_bits = USART_DATA_8BITS;
			break;
		case MB_PAR_ODD :
            parity = USART_PARITY_ODD;
            data_bits = USART_DATA_9BITS;
			break;
		case MB_PAR_EVEN :
            parity = USART_PARITY_EVEN;
            data_bits = USART_DATA_9BITS;
			break;
		default :
			return FALSE;
	}

    switch (stop_bit)
    {
        case 1 :
            stop_bits = USART_STOP_1_BIT;
        break;
        
        case 3 :
            stop_bits = USART_STOP_2_BIT;
        break;
        
        default :
            return FALSE;
    }
    
    
    // configure uart param
    usart_parity_selection_config(MB_UART, parity);
    usart_init(MB_UART, ulBaudRate, data_bits, stop_bits);
    usart_transmitter_enable(MB_UART, TRUE);
    usart_receiver_enable(MB_UART, TRUE);
    usart_enable(MB_UART, TRUE);  
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    NVIC_ClearPendingIRQ(USART3_IRQn);
    nvic_irq_enable(USART3_IRQn, 5, 0);
    //nvic_irq_enable(USART3_IRQn, 0, 5);
    
    //usart_interrupt_enable(USART3, USART_TDC_INT, TRUE);
    //usart_interrupt_enable(USART3, USART_RDBF_INT, TRUE);
    
    return TRUE;
#endif
#if 0    
    gpio_init_type gpio_init_struct;
    usart_parity_selection_type parity;
    usart_data_bit_num_type data_bits;
    usart_stop_bit_num_type stop_bits;

    crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
    
    gpio_default_para_init(&gpio_init_struct);

    // configure 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 = GPIO_PINS_10 | GPIO_PINS_9;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);
    
    switch (eParity)
	{
		case MB_PAR_NONE :
            parity = USART_PARITY_NONE;
            data_bits = USART_DATA_8BITS;
			break;
		case MB_PAR_ODD :
            parity = USART_PARITY_ODD;
            data_bits = USART_DATA_9BITS;
			break;
		case MB_PAR_EVEN :
            parity = USART_PARITY_EVEN;
            data_bits = USART_DATA_9BITS;
			break;
		default :
			return FALSE;
	}

    switch (stop_bit)
    {
        case 1 :
            stop_bits = USART_STOP_1_BIT;
        break;
        
        case 3 :
            stop_bits = USART_STOP_2_BIT;
        break;
        
        default :
            return FALSE;
    }
    
    
    // configure uart param
    usart_parity_selection_config(MB_UART, parity);
    usart_init(MB_UART, ulBaudRate, data_bits, stop_bits);
    usart_transmitter_enable(MB_UART, TRUE);
    usart_receiver_enable(MB_UART, TRUE);
    usart_enable(MB_UART, TRUE);  
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    NVIC_ClearPendingIRQ(USART1_IRQn);
    nvic_irq_enable(USART1_IRQn, 5, 0);
    
    return TRUE;
#endif    
}

//
void vMBPortSerialClose( void )
{
    crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, FALSE);
}

//
BOOL xMBPortSerialPutByte( CHAR ucByte )
{
    //usart_data_transmit(PRINT_UART, ucByte);
    usart_data_transmit(MB_UART, ucByte);
    return TRUE;
}

//
BOOL xMBPortSerialGetByte( CHAR * pucByte )
{
    *pucByte = usart_data_receive(MB_UART);
    return TRUE;
}


#if 1
void USART3_IRQHandler(void)
//void USART1_IRQHandler(void)
{   
    if (MB_UART->ctrl1_bit.rdbfien == SET)
    {
        if (usart_flag_get(MB_UART, USART_RDBF_FLAG) == SET) 
        {
            leds[RX_G].state = LED_ON;
            pxMBFrameCBByteReceived();
        }
    }  
    
    if (MB_UART->ctrl1_bit.tdbeien == SET)
    {
        if (usart_flag_get(MB_UART, USART_TDBE_FLAG) == SET) 
        {
            vMBPortSetWithinException(TRUE);
            pxMBFrameCBTransmitterEmpty();
            vMBPortSetWithinException(FALSE);
        }
    }      
}
#endif

//
void vMB_USART_IRQHandler(void)
{
#if 0  
	if ((__HAL_UART_GET_IT(&huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_RXNE) != RESET)) {
		pxMBFrameCBByteReceived();
		__HAL_UART_SEND_REQ(&huart, UART_RXDATA_FLUSH_REQUEST);
	}
	if ((__HAL_UART_GET_IT(&huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&huart, UART_IT_TXE) != RESET)) {
		pxMBFrameCBTransmitterEmpty();
		HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
	}
    
    if (__HAL_UART_GET_IT(&huart, UART_IT_ERR) != RESET)
        __HAL_UART_CLEAR_IT(&huart, UART_CLEAR_OREF);
#endif    
}
