#include "AI8051U_Uart.h"
#include "AI8051U.h"
#include <string.h>
#include "LineFollowerLearn8CH.h"

#define SET_REGISTER_BIT(reg, dat, num){          \
        reg &= ~((dat) << (num)); /* 清除目标位 */ \
        reg |= ((dat) << (num));  /* 设置目标位 */ }

#define SET_UART_VALUE(th,tl){\
		th = (uint8_t)((uint16_t)(65536.0f - (float)(MAIN_Fosc / (baud * 4))) >> 8); \
		tl = (uint8_t)(65536.0f - (float)(MAIN_Fosc / (baud * 4))); }

#define UART_DMA_CONFIG(n){ \
		DMA_UR##n##T_CFG = 0x80;        /* 打开DMA发送中断 */ \
		DMA_UR##n##T_STA = 0x00;        /* 清空状态标志位 */ \
		DMA_UR##n##T_TXAH = (uint8_t)((uint16_t)&uart##n##_tx_buff >> 8); \
		DMA_UR##n##T_TXAL = (uint8_t)((uint16_t)&uart##n##_tx_buff); \
		DMA_UR##n##T_CR = 0xc0;         /* bit7 1:使能 UARTn_DMA, bit6 1:开始 UARTn_DMA 自动发送 */ \
		DMA_UR##n##R_CFG = 0x10;        /* 关闭DMA接收中断 */ \
		DMA_UR##n##R_STA = 0x00;        /* 清空状态标志位 */ \
		DMA_UR##n##R_AMT = (uint8_t)(Uart##n##_Rx-1);        /*设置传输总字节数(低8位)：n+1*/\
		DMA_UR##n##R_AMTH = (uint8_t)((Uart##n##_Rx-1)>>8);       /*设置传输总字节数(高8位)：n+1*/\
		DMA_UR##n##R_RXAH = (uint8_t)((uint16_t)&uart##n##_rx_buff >> 8); \
		DMA_UR##n##R_RXAL = (uint8_t)((uint16_t)&uart##n##_rx_buff); \
		DMA_UR##n##R_CR = 0xa1;}         /* bit7 1:使能 UARTn_DMA, bit5 1:开始 UARTn_DMA 自动接收, bit0 1:清除 FIFO */

#define SET_UART_CONFIG(ren, uart_num){\
		UR##uart_num##TOCR = 0xc0; \
		UR##uart_num##TOSR = 0x80; \
		UR##uart_num##TOTL = (uint8_t)(idle_byte); \
		UR##uart_num##TOTH = (uint8_t)(idle_byte >> 8); \
		UR##uart_num##TOTE = (uint8_t)(idle_byte >> 16);ren##REN = 1;}

		
//uint8_t xdata uart1_tx_buff[Uart1_Tx] = {0};
//uint8_t xdata uart1_rx_buff[Uart1_Rx] = {0};		

//uint8_t xdata uart2_tx_buff[Uart2_Tx] = {0};
//uint8_t xdata uart2_rx_buff[Uart2_Rx] = {0};	

uint8_t xdata uart3_tx_buff[Uart3_Tx] = {0};
uint8_t xdata uart3_rx_buff[Uart3_Rx] = {0};		

//uint8_t xdata uart4_tx_buff[Uart4_Tx] = {0};
//uint8_t xdata uart4_rx_buff[Uart4_Rx] = {0};	


const uint32_t idle_byte = TIMEOUT;
unsigned char busy_uart1 = 0;
unsigned char busy_uart2 = 0;
unsigned char busy_uart4 = 0;


/* 注意：若需要同时使用多个串口，当波特率不一样时，不能共用定时器2 */


/*
串口1控制寄存器（SCON）
bit7     bit6  bit5  bit4  bit3  bit2  bit1  bit0
SMO/FE   SM1   SM2   REN   TB8   RB8   TI    RI

SMO/FE:(PCON-SMOD0=0)与SM1一起指定串口1通信工作模式
			 (PCON-SMOD0=1)帧错误检测标志位，接收时收到无效停止位置1，需软件清零
SM1: 与SM0一起指定串口1通信工作模式
SM2: 允许模式2/3舵机通信使能位
REN: 串口接收数据使能位
TB8: 串口1使用模式2/3时，TB8为要发送的第9位数据，按需要由软件置位或清0。在模式0/1中，该位不用
RB8: 串口1使用模式2/3时，RB8为要接收的第9位数据，一般用作校验位或者地址帧/数据帧标志位。在模式0/1中，该位不用
TI:  串口1发送中断请求标志位   
RI:  串口1接收中断请求标志位
==================================================================

定时器2计数寄存器（T2L，T2H）
	定时/计数器2工作模式固定为16位重载模式，[T2H，T2L]组合成一个16位寄存器计数
==================================================================

辅助寄存器1（AUXR）
bit7   bit6   bit5       bit4  bit3    bit2   bit1    bit0
T0x12  T1x12  UART_M0x6  T2R   T2_C/T  T2x12  EXTRAM  S1BRT

T0x12:  
T1x12:  
UART_M0x6: 串口1模式0通讯速度控制（0-波特率不加倍，固定Fosc/12、1-波特率6倍速，固定Fosc/2）
T2R:       定时器2运行使能位
T2_C/T:    定时器2的定时/计数功能选择位（0-定时器、1-计数器，计数P1.0引脚外部脉冲）
T2x12:     定时器2速度控制位（0-12T模式，固定Fosc/12、1-1T模式，固定Fosc）
EXTRAM:  
S1BRT:     串口1波特率发生器选择位（0-定时器1、1-定时器2【默认】,推荐定时器2，可共享作为串口1-4波特率发生器）
==================================================================

串口1接收超时控制寄存器（UR1TOCR）
bit7   bit6   bit5    
ENT0   ENTOI  SCALE    
 
ENT0:   串口1接收超时功能使能位
ENTOI:  串口1接收超时中断使能位
SCALE:  串口1超时计数时钟源（0-波特率 1-系统时钟）
==================================================================

串口1超时状态寄存器（UR1TOCR）
bit7   bit6   bit5    
ENT0   ENTOI  SCALE    
 
ENT0:   串口1接收超时功能使能位
ENTOI:  串口1接收超时中断使能位
*/
void uart1_init(uint32 baud)	
{
	uint32_t uart1_timeout = 1;
	
	/* 设置串口1功能脚为准双向口 */
  P3M0 &= ~0x03; 
	P3M1 &= ~0x03; 

	/* SCON寄存器配置（下面还有对该寄存器的配置） */
	/* 模式1：可变波特率8位数据方式 */
	SM0 =0;
	SM1 =1;
	
	/* 串口1功能脚选择,在P_SW1寄存器的串口1功能脚选择位S1_S（bit6-7）设置 */
	/* 核心板上使用P3.0、P3.1作为RX、TX */
	S1_S1 = 0; //P_SW1^7
	S1_S0 = 0; //P_SW1^6
	
	
	/* 在定时器IT速度下配置定时器2计数寄存器[T2H，T2L]，设置重装值，以此产生符合预期的波特率 */
	/* 定时器速度1T-重装值 = 65536 - （sysclk / 4 * baud）
		 定时器速度12T-重装值 = 65536 - （sysclk / 4 * 12 * baud） */
	SET_UART_VALUE(T2H,T2L);


	/* 辅助寄存器1（AUXR）配置 */
	S1BRT = 1; /* 使用定时器2作为串口1波特率发生器 */
	T2x12 = 1;	/* CPU时钟不进行分频处理产生定时器2时钟（1T模式）	*/
	T2R = 1;	/* 定时器2开始计数 */

/*
	UART_DMA_CONFIG(1);
*/	
	/* 串口1接收超时控制寄存器配置 */
	/* 使能串口1超时功能和对应中断*/
	/*
	UR1TOCR = 0xc0; 
	*/
	
/*	
	UR1TOSR = 0x80; 
	UR1TOTL = (uint8_t)(uart1_timeout); 
	UR1TOTH = (uint8_t)(uart1_timeout >> 8);
	UR1TOTE = (uint8_t)(uart1_timeout >> 16);
*/
	
	/* SCON寄存器配置 */
	/* 使能串口接收数据 */
	REN = 1;
}

void uart1_SendByte(char dat){
	while(busy_uart1);
	busy_uart1 = 1;  //置位串口1忙碌状态，在发出该bit进入中断前不允许后续bit填充SBUF，以免数据错乱
	SBUF = dat;

}

void uart1_Sendstring(char *p){
	while(*p){
		uart1_SendByte(*p++);
	}
}


/*
串口2配置寄存器（S2CFG）
bit7    bit6    bit5     bit4  bit3  bit2  bit1  bit0
S2MOD   S2MOD0  S2M0x6   x     x     x     x     W1

S2MOD:  串口2波特率控制位（0：所有模式波特率均不加倍 1：模式2波特率加倍） 
S2MOD0: 帧错误检测使能位
S2M0x6: 串口2模式0通信速度控制位（0：模式0波特率不加倍 1：模式0波特率6倍速）
W1:     使用串口2时必须置1
==================================================================

串口2控制寄存器（S2CON）
bit7       bit6    bit5   bit4   bit3   bit2  bit1  bit0
S2SMO/FE   S2SM1   S2SM2  S2REN  S2TB8  S2RB8 S2TI  S2RI

各标志位功能与SCON接近，具体请参考uart1_init函数头注释介绍
==================================================================

辅助寄存器1（AUXR）
bit7   bit6   bit5       bit4  bit3    bit2   bit1    bit0
T0x12  T1x12  UART_M0x6  T2R   T2_C/T  T2x12  EXTRAM  S1BRT

具体请参考uart1_init函数头注释介绍
==================================================================
*/
void uart2_init(uint32 baud){
	/* 设置串口2功能脚为准双向口 */
  P4M0 &= ~0x04;
	P4M1 |= 0x04; 
	
	/* 串口2功能脚选择,在P_SW2寄存器的串口1功能脚选择位S2_S（bit0）设置 */
	/* 核心板上使用P4.2、P4.3作为RX、TX */
	S2_S = 1;	/* 串口2功能脚选择 */
	
	/* S2CFG寄存器配置 */
	/* 波特率不加倍，不打开帧错误检测 */
	S2CFG = 0x01;	/* 使用串口2时，配置寄存器内的W1必须置1 */
	
	/* S2CON寄存器配置（下面还有对该寄存器的配置） */
	/* 模式1：可变波特率8位数据方式 */	
	S2SM0 = 0;	
	S2SM1 = 1;
	
	
	/* 在定时器IT速度下配置定时器2计数寄存器[T2H，T2L]，设置重装值，以此产生符合预期的波特率 */
	/* 重装值 = 65536 - （sysclk / 4 * baud） */
	SET_UART_VALUE(T2H,T2L);
	
	
	/* 辅助寄存器1（AUXR）配置 */
	T2x12 = 1;	/* CPU时钟不进行分频处理（1T模式）*/
//	ET2 = 0;	/* 禁止定时器2中断 */
	T2R = 1;	  /* 定时器2开始计数 */
	//	T2_CT = 0;	/* 设置为定时器 */

//	DMA_UR2R_CFG = 0x10;        /* 关闭DMA接收中断 */ 
//	DMA_UR2R_STA = 0x00;        /* 清空状态标志位 */ 
//	DMA_UR2R_AMT = (uint8_t)(Uart2_Rx-1);        /*设置传输总字节数(低8位)：n+1*/
//	DMA_UR2R_AMTH = (uint8_t)((Uart2_Rx-1)>>8);       /*设置传输总字节数(高8位)：n+1*/
//	DMA_UR2R_RXAH = (uint8_t)((uint16_t)&uart2_rx_buff >> 8); 
//	DMA_UR2R_RXAL = (uint8_t)((uint16_t)&uart2_rx_buff); 
//	DMA_UR2R_CR = 0xa1;        /* bit7 1:使能 UARTn_DMA, bit5 1:开始 UARTn_DMA 自动接收, bit0 1:清除 FIFO */
//	SET_UART_CONFIG(S2,2);

	/* S2CON寄存器配置 */
	/* 使能串口接收数据 */
	S2REN = 1;
}


void uart2_SendByte(char dat){
	while(busy_uart2);
	busy_uart2 = 1;  //置位串口2忙碌状态，在发出该bit进入中断前不允许后续bit填充SBUF，以免数据错乱
	S2BUF = dat;

}

void uart2_Sendstring(char *p){
	while(*p){
		uart2_SendByte(*p++);
	}
}

void uart3_init(uint32 baud)	
{
	/* 设置串口3功能脚为准双向口 */
    P5M0 &= ~0x03; 
	P5M1 &= ~0x03; 
	/* RX脚需要开启施密特触发器 */
    P5NCS &= ~0x01; 
	
	S3SM0 = 0;	/* 可变波特率8位数据方式 */
	S3_S = 1;	/* 串口3功能脚选择 */
	S3ST3 = 0;	/* 选择定时器2为串口3的波特率发生方式 */

	T2R = 0;    /* Timer stop */
	T2_CT = 0;	/* 设置为定时器 */
	
	/* 重装值 = 65536 - （sysclk / 4 * baud） */
	SET_UART_VALUE(T2H,T2L);
	T2x12 = 1;	/* CPU时钟不进行分频处理	*/
	ET2 = 0;	/* 禁止定时器2中断 */
	T2R = 1;	/* 定时器2开始计数 */

	UART_DMA_CONFIG(3);
	SET_UART_CONFIG(S3,3);
	
//	PS3H = 1;	/* 将优先级设置为最高 */
//	PS3 = 1;
}

/*
串口4控制寄存器（S4CON）
bit7       bit6    bit5   bit4   bit3   bit2  bit1  bit0
S4SMO/FE   S4SM1   S4SM2  S4REN  S4TB8  S4RB8 S4TI  S4RI

各标志位功能与SCON接近，具体请参考uart1_init函数头注释介绍
==================================================================

定时器4/3控制寄存器（T4T3M）
bit7   bit6    bit5   bit4    bit3  bit2   bit1    bit0
T4R    T4_C/T  T4x12  T4CLKO  T3R   T3_C/T  T3x12  T3CLKO  
 
T4R：   定时器4运行使能位
T4_C/T：定时/计数功能选择位（0-定时器、1-计数器，计数P0.6外部脉冲）  
T4x12： 定时器4速度控制位（0-12T模式，固定Fosc/12、1-1T模式，固定Fosc）
T4CLKO：时钟输出使能位
==================================================================
*/
void uart4_init(uint32 baud)	
{
	/* 设置串口4功能脚为准双向口 */
  P0M0 &= ~0x0c;
	P0M1 &= ~0x0c; 

	/* 配置S4CON寄存器 */
	S4SM0 = 0;	/* 可变波特率8位数据方式（模式0） */
	S4ST4 = 1;	/* 选择定时器4为串口4的波特率发生方式 */
	S4REN = 1;  /* 允许串口接收数据 */
	
	/* 串口4功能脚选择,在P_SW2寄存器的串口1功能脚选择位S4_S（bit2）设置 */
	/* 核心板上使用P0.2、P0.3作为RX、TX */	
	S4_S = 0;	

	/* 在定时器IT速度下配置定时器2计数寄存器[T2H，T2L]，设置重装值，以此产生符合预期的波特率 */	
	/* 重装值 = 65536 - （sysclk / 4 * baud） */
	SET_UART_VALUE(T4H,T4L);

	/* 配置T4T3M寄存器 */	
//	T4R = 0;    /* Timer stop */
	T4_CT = 0;	/* 设置为定时器 */	
	T4x12 = 1;	/* CPU时钟不进行分频处理（1T模式）	*/
	T4R = 1;	/* 定时器4开始计数 */

	ET4 = 0;	/* 禁止定时器4中断 */

//	UART_DMA_CONFIG(4);
//	DMA_UR4T_CFG = 0x8f;
//	SET_UART_CONFIG(S4,4);
//	PS4H = 1;	/* 将优先级设置为最高 */
//	PS4 = 1;
}


void uart4_SendByte(char dat){
	while(busy_uart4);
	busy_uart4 = 1;  //置位串口2忙碌状态，在发出该bit进入中断前不允许后续bit填充SBUF，以免数据错乱
	S4BUF = dat;

}

void uart4_Sendstring(char *p){
	while(*p){
		uart4_SendByte(*p++);
	}
}

void Uart1_isr(void) interrupt 4
{
	if(TI){
		TI = 0;         //软件清空中断标志位
		busy_uart1 = 0; //串口1完成数据发送，解除忙碌状态，允许后续1bit准备发送
	}else if(RI){
		RI = 0;         //软件清空中断标志位
		
	}
}

void Uart2_isr(void) interrupt 8
{
	if(S2TI){
		busy_uart2 = 0; //串口2完成数据发送，解除忙碌状态，允许后续1bit准备发送
		S2TI = 0;         //软件清空中断标志位
	}else if(S2RI){
		S2RI = 0;         //软件清空中断标志位

	}
}

void Uart4_isr(void) interrupt 18
{
	if(S4TI){
		busy_uart4 = 0; //串口4完成数据发送，解除忙碌状态，允许后续1bit准备发送
		S4TI = 0;         //软件清空中断标志位
	}else if(S4RI){
		S4RI = 0;         //软件清空中断标志位
		uart_FrameUnpack(&linefollower, S4BUF);

	}
}