/*
 * File      : uart_dev.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006-2013, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date           Author       Notes
 * 2009-01-05     Bernard      the first version
 * 2010-03-29     Bernard      remove interrupt Tx and DMA Rx mode
 * 2013-05-13     aozima       update for kehong-lingtai.
 */

#include "uart/uart.h"
#include "uart_dev.h"
#include "ae210p.h"
#include "board.h"
#include "bsp_hal.h"

#include "rtdevice.h"

#include "serial.h"

#define UART_ENABLE_IRQ(n)  hal_intc_irq_enable(n)
#define UART_DISABLE_IRQ(n) hal_intc_irq_disable(n)

struct uart_device
{
	uint32_t uart_base;
	uint32_t irq;
};

static rt_err_t __uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
	struct uart_device *uartDev = RT_NULL;

    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

	uartDev = (struct uart_device *)serial->parent.user_data;

	__drv_uart_init(uartDev->uart_base, cfg->baud_rate);

	// todo : enable FIFO threshold, enable rx & rx timeout(threshold) interrupt

    return RT_EOK;
}

static rt_err_t __uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
	struct uart_device *uartDev = RT_NULL;

	RT_ASSERT(serial != RT_NULL);
	uartDev = (struct uart_device *)serial->parent.user_data;

	switch (cmd)
	{
	case RT_DEVICE_CTRL_CLR_INT: /* disable rx irq */
		UART_DISABLE_IRQ(uartDev->irq);
		break;

	case RT_DEVICE_CTRL_SET_INT: /* enable rx irq */
		UART_ENABLE_IRQ(uartDev->irq);
		break;

	default:
		break;
	}

	return RT_EOK;
}

static int __uart_putc(struct rt_serial_device *serial, char c)
{
	struct uart_device *uartDev = RT_NULL;

	RT_ASSERT(serial != RT_NULL);

	uartDev = (struct uart_device *)serial->parent.user_data;

	__drv_uart_put_char(uartDev->uart_base, c); // Transmit Data

	return 1;
}

static int __uart_getc(struct rt_serial_device *serial)
{
	int ch = -1;
	struct uart_device *uartDev = RT_NULL;

	RT_ASSERT(serial != RT_NULL);
	uartDev = (struct uart_device *)serial->parent.user_data;

	ch = -1;

	if (__drv_uart_is_kbd_hit(uartDev->uart_base))
	{
		ch = __drv_uart_get_char(uartDev->uart_base) & 0x00FF;
	}

	return ch;
}

static const struct rt_uart_ops __uart_ops =
{
    __uart_configure,
	__uart_control,
	__uart_putc,
	__uart_getc,
	RT_NULL
};

#if RT_USING_UART01
struct uart_device uartDev01 =
{ // UART01 device driver structure
	UART1_BASE,
	IRQ_UART1_VECTOR
};

struct rt_serial_device serial01;

void URT01_IRQHandler(void)
{
	struct uart_device *uartDev = RT_NULL;
	
	uartDev = &uartDev01;

	rt_interrupt_enter(); /* enter interrupt */

//	if (uart->uart_device->Interrupt & ((1 << bsUART_TIMEOUT_INTENAB) | (1 << bsUART_RECEIVE_INTENAB))) // RX
//	{
//		rt_hw_serial_isr(&serial01, RT_SERIAL_EVENT_RX_IND);
//	}
//
//	if (uart->uart_device->Interrupt & (1 << bsUART_TRANSMIT_INTENAB)) // TX
//	{
//		;
//	}
//
//	/* clear all interrupt */
//	uart->uart_device->IntClear = (1 << bsUART_RECEIVE_INTENAB)
//									| (1 << bsUART_TRANSMIT_INTENAB)
//									| (1 << bsUART_TIMEOUT_INTENAB);

	rt_interrupt_leave(); /* leave interrupt */
}
#endif /* RT_USING_UART01 */

#if RT_USING_UART02
struct uart_device uartDev02 =
{ // UART02 device driver structure
	UART2_BASE,
	IRQ_UATR2_VECTOR
};

struct rt_serial_device serial02;

void URT02_IRQHandler(void)
{
	struct uart_device *uartDev = RT_NULL;

	uartDev = &uartDev02;

	rt_interrupt_enter(); /* enter interrupt */

	uartDev = uartDev;

	rt_interrupt_leave(); /* leave interrupt */
}
#endif /* RT_USING_UART02 */

void rt_hw_usart_init(void)
{
	struct uart_device *uartDev = RT_NULL;
	struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;

#if RT_USING_UART01
	uart = &uartDev01;
	config.baud_rate = BAUD_RATE_38400;

	serial01.ops    = &__uart_ops;
	serial01.config = config;

	// set interrupt priority level
	// disable interrupt

	// register UART01 device
	rt_hw_serial_register(&serial01, "uart01",
							RT_DEVICE_FLAG_RDWR /*| RT_DEVICE_FLAG_INT_RX*/,
							uartDev);
#endif /* RT_USING_UART01 */

#if RT_USING_UART02
	uartDev = &uartDev02;

	config.baud_rate = BAUD_RATE_38400;
	serial02.ops    = &__uart_ops;
	serial02.config = config;

	// set interrupt priority level
	// disable interrupt

	/* register UART02 device */
	rt_hw_serial_register(&serial02, "uart02",
							RT_DEVICE_FLAG_RDWR /*| RT_DEVICE_FLAG_INT_RX*/,
							uartDev);
	#endif /* RT_USING_UART02 */
}