#include "bsp_lin.h"
#include "circular_buffer.h"


static lin_error_enum lin_error = FIFO_VOID;
static lin_rxstate_enum lin_rxstateget = BREAK_GET;
static lin_msg_struct lin_msg = {0};
static CircBuf_t lin_rx_circbuf = {0};//接收环形队列索引


void lin_init(void)
{
		gpio_init_type gpio_init_struct;
		
		crm_periph_clock_enable(CRM_USART5_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
	
		// TX引脚配置
    gpio_default_para_init(&gpio_init_struct); // 清空结构体
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE; // 中等驱动强度
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; // 推挽输出
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX; // 引脚复用模式
    gpio_init_struct.gpio_pins = GPIO_PINS_3; // TX引脚
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE; // 无上下拉
    gpio_init(GPIOB, &gpio_init_struct); // 初始化TX引脚
	
		gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE3, GPIO_MUX_10);
    
    // RX引脚配置
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX; // 输入模式
    gpio_init_struct.gpio_pins = GPIO_PINS_4; // RX引脚
    gpio_init(GPIOB, &gpio_init_struct); // 初始化RX引脚
	
		gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE4, GPIO_MUX_10);
		
		// USART配置
    usart_init(USART5, Lin_Speed, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USART5, TRUE); // 使能发送器
    usart_receiver_enable(USART5, TRUE); // 使能接收器
    usart_parity_selection_config(USART5, USART_PARITY_NONE); // 无奇偶校验
    usart_break_bit_num_set(USART5, USART_BREAK_11BITS); // 断帧检测
    usart_lin_mode_enable(USART5, TRUE); // 启用LIN模式

		// 中断配置
    nvic_irq_enable(USART5_IRQn, 0, 0); // 配置串口优先级
    usart_enable(USART5, TRUE); // 使能USART1
    usart_interrupt_enable(USART5, USART_BF_INT, TRUE); // 使能帧中断
		usart_interrupt_enable(USART5, USART_RDBF_INT,TRUE);// 使能串口接收中断

		CircBuf_Alloc(&lin_rx_circbuf, sizeof(lin_msg_struct)*2);
}

uint8_t lin_getpid(uint8_t id)
{
		uint8_t pid = 0, p0 = 0, p1 = 0;
	
		p0 = (((id>>0)^(id>>1)^(id>>2)^(id>>4))&0x01)<<6;//偶校验位
		p1 = ((~((id>>1)^(id>>3)^(id>>4)^(id>>5)))&0x01)<<7;//奇校验位
		pid = (id|p0|p1);
		return pid;
}

uint8_t lin_getchecksum(uint8_t pid, uint8_t* p_data, uint8_t data_len, uint8_t flag)
{
		uint16_t checksum = 0;
		if((pid != 0x3c)&&(pid != 0x7d))
		{
				checksum = pid;
		}
		for(uint8_t i = 0; i < data_len; i++)
		{
				checksum += p_data[i];
				if(checksum > 0xff)
				{
						checksum -=0xff;
				}
		}
		
		if(flag == 0)
		{
				return (~checksum) & 0xff;	//发送方需要取反
		}
		else
		{
				return checksum & 0xff;			//接收方不需要
		}
}

void lin_send_bytes(usart_type * usart_x, uint8_t* p_data, uint8_t data_len)
{
		for(uint8_t i = 0; i < data_len; i++)
		{
				usart_data_transmit(usart_x, *p_data++);
				while(usart_flag_get(USART3, USART_TDBE_FLAG) == RESET);
		}
}

void lin_rx_data(uint8_t pid, uint8_t* p_data, uint8_t data_len)
{
		uint8_t lin_buffer[data_len + 1];
		uint8_t checksum = lin_getchecksum(pid, p_data, data_len, 0);
		
		for(uint8_t i = 0; i < data_len; i++)
		{
				lin_buffer[i] = *(p_data + i);
		}
		
		lin_buffer[data_len] = checksum;
		lin_send_bytes(USART3,lin_buffer, data_len + 1);
}


void lin_master_rxmsg(uint8_t data)
{
		lin_msg_struct* p_lin_msg = &lin_msg;
	
		switch((uint8_t)lin_rxstateget)
		{
			case BREAK_GET:
			break;
			case SYNCH_GET:
			{
					if(data != 0x55)
					{
							lin_error = SYNC_ERR;
							lin_rxstateget = BREAK_GET;
					}
					else
					{
							p_lin_msg->sync = data;
							lin_rxstateget = PID_GET;
					}
			}
			break;
			
			case PID_GET:
			{
					p_lin_msg->frameid = data&0x3f;
					p_lin_msg->pid = data;
					uint8_t pid = lin_getpid(p_lin_msg->frameid);
					
					if(pid == p_lin_msg->pid)
					{
							if(p_lin_msg->frameid == 0x03)		//执行 即继续接收数据
							{
									lin_rxstateget = MSG_GET;
									p_lin_msg->datalen = 0;
							}
							else if(p_lin_msg->frameid == 0x32)	//反馈	即向lin总线发送消息
							{
									lin_rx_data(p_lin_msg->pid, &data, 1);
									lin_rxstateget = BREAK_GET;
							}
							else
							{
									lin_rxstateget = BREAK_GET;
							}
					}
					else
					{
							lin_error = PID_ERR;
							lin_rxstateget = BREAK_GET;
					}
			}
			break;
			
			case MSG_GET:
			{
					p_lin_msg->data[p_lin_msg->datalen++] = data;
					lin_rxstateget = (p_lin_msg->datalen >= 8) ? CHECKSUM_GET:MSG_GET;
			}
			break;
			
			case CHECKSUM_GET:
			{
					p_lin_msg->checksum = data;
					uint8_t checksum = lin_getchecksum(p_lin_msg->pid, p_lin_msg->data, p_lin_msg->datalen, 1);
					if((checksum + p_lin_msg->checksum) == 0xff)
					{
							CircBuf_Push(&lin_rx_circbuf, (uint8_t *)p_lin_msg, sizeof(lin_msg_struct));
					}
					else
					{
							lin_error = FORMAT_ERR;
					}
					lin_rxstateget = BREAK_GET;
			}
			break;
			
			default:
					lin_rxstateget = BREAK_GET;
			break;	
		}	
}

uint8_t rx_ring_buffer_get_lin_msg(lin_msg_struct * p_lin_msg)
{
		return CircBuf_Pop(&lin_rx_circbuf,(uint8_t*)p_lin_msg, sizeof(lin_msg_struct));
}

void USART5_IRQHandler(void)
{
	uint8_t receive_data = 0;
	
	
		if(RESET != usart_interrupt_flag_get(USART5,USART_BFF_FLAG))
		{
				usart_data_receive(USART5);
				
				lin_rxstateget = SYNCH_GET;
				
				usart_flag_clear(USART5,USART_FERR_FLAG);//清除帧错误标志，lin断开段也是数据，只不过断开段是超过10位的0，不符合串口的帧标准，所以出现了帧错误
				usart_flag_clear(USART5,USART_BFF_FLAG);
				usart_flag_clear(USART5,USART_RDBF_FLAG);
				return ;
		}
		
		if(RESET != usart_interrupt_flag_get(USART5,USART_RDBF_FLAG))
		{
				receive_data = usart_data_receive(USART5);
				if(RESET == usart_interrupt_flag_get(USART5,USART_FERR_FLAG))
				{
						if((receive_data == 0x55)&&(lin_rxstateget == BREAK_GET))
						{
								lin_rxstateget = SYNCH_GET;
								return ;
						}
						
						lin_master_rxmsg(receive_data);
				}
				
				usart_flag_clear(USART5,USART_RDBF_FLAG);
		}
}

