#include "LineFollowerLearn8CH.h"
#include "string.h"
#include "global.h"
#include "AI8051U_I2C.h"
#include "AI8051U_Uart.h"

extern char debug_bit;
extern char debug_value;

/**
 * @brief 完成八路巡线传感器IIC通信前必要的硬件接口初始化。
 */
void LineFollowerLearn8CH_IIC_init(){
	i2c_init();
}
	

/**
 * @brief IIC通信方式获取各通道状态值并解析
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note StateReg_OriginData为传感器发来的原始数据，可供调试观测
 */
void detect_state_all_channel_IIC(linefollower_8ch *obj){
	uint8_t len=0;
	
	i2c_read_data(LineFollowerLearn8CH_I2C_ADDR << 1, SensorStateReg, &(obj->StateReg_OriginData), sizeof(obj->StateReg_OriginData));
	
	for(len = 0; len < SENSOR_SUM; len++)
	{
		obj->state_all_ch[len]= ((obj->StateReg_OriginData >> len) & 0x01); //解析数据，提取各通道状态值
	}
	
}

/**
 * @brief IIC通信方式获取各通道模拟量并解析
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note SensorAnalogReg_OriginData为传感器发来的原始数据，可供调试观测
 */
void get_AnalogVoltage_all_channel_IIC(linefollower_8ch *obj){
	uint8_t len=0;
	uint8_t count=0;
	
	i2c_read_data(LineFollowerLearn8CH_I2C_ADDR << 1, SensorAnalogReg_ch1, obj->SensorAnalogReg_OriginData, sizeof(obj->SensorAnalogReg_OriginData));
	
	for(len = 0,count = 0; len < SENSOR_SUM; len++)
	{
		obj->AnalogVoltage_all_ch[len]= (obj->SensorAnalogReg_OriginData[count]) | (obj->SensorAnalogReg_OriginData[count+1]<<8);  //解析数据，把各通道模拟值低8位和高8位数据合并为16位数据
		count += 2;
	}
}

/**
 * @brief IIC通信方式获取各通道阈值量并解析
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note SensorThresholdReg_OriginData为传感器发来的原始数据，可供调试观测
 */
void get_ThresholdValue_all_channel_IIC(linefollower_8ch *obj){
	uint8_t len = 0;
	uint8_t count=0;

	i2c_read_data(LineFollowerLearn8CH_I2C_ADDR << 1, SensorThresholdReg_ch1, obj->SensorThresholdReg_OriginData, sizeof(obj->SensorThresholdReg_OriginData));
	
	for(len = 0,count = 0; len < SENSOR_SUM; len++)
	{
		obj->ThresholdVoltage_all_ch[len]= (obj->SensorThresholdReg_OriginData[count]) | (obj->SensorThresholdReg_OriginData[count+1]<<8);  //解析数据，把各通道阈值低8位和高8位数据合并为16位数据
		count += 2;
	}
}

/**
 * @brief 完成八路巡线传感器IIC通信前必要的硬件接口初始化，同时发送配置指令指定传感器的运行模式。
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @param int mode：传感器工作模式，可传入的参数宏定义详见头文件
 *
 * @note 1.如使用手动模式，还需要在该函数之后调用Change_TransmitData_In_Mode_manual指定子模式方可获取数据
 *       2.运行模式配置后无法重新配置，如果需要更换模式需要复位后重新初始化 
 */
void LineFollowerLearn8CH_UART_init(linefollower_8ch *obj , int mode){
	uart2_init(115200);
	
	obj->RX_state_machine = unpack_FrameHEAD_1;   //初始化串口接收状态机
	obj->Work_mode = mode;                        //赋值工作模式成员
	obj->sub_work_mode_InManual = 0;              //将手动模式子模式成员清零，后面如有需要再赋值
	obj->uart_rx_buffer_index = 0;                //将对象串口接收缓冲区索引归零
	obj->Data_usable = 0;                         //清空数据可用标志位，只有串口中断中的解析完成才允许置1
	
	switch(mode){
		case manual_mode:{
			obj->DataLength_Receive = 0;              //手动模式需要获取的数据(命令帧中的参数长度)到后面确定子模式后再赋值
			uart4_SendByte(manual_mode);              //发送指令使传感器进入手动模式
			break;
		}
		case Transmit_SensorState_auto_mode:{
			obj->DataLength_Receive = 1;
			uart4_SendByte(Transmit_SensorState_auto_mode);
			break;
		}
		case Transmit_AnalogValue_auto_mode:{
			obj->DataLength_Receive = SENSOR_SUM*2;
			uart4_SendByte(Transmit_AnalogValue_auto_mode);
			break;
		}
		case Transmit_ThresholdValue_auto_mode:{
			obj->DataLength_Receive = SENSOR_SUM*2;
			uart4_SendByte(Transmit_ThresholdValue_auto_mode);
			break;
		}
		default:{
			break;
		}
	}
}

/**
 * @brief 发送配置指令，指定传感器在手动模式下的的子模式。
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @param int mode：传感器工作模式，可传入的参数宏定义详见头文件
 *
 * @note 1.手动模式下，可随时自由的切换至各个子模式
 *       2.每切换一次子模式，主控向串口发送一条配置指令，传感器返回一帧数据后不再主动发送数据，直至主控再次发去下一条配置指令
 *       3.“手动模式-发送模拟量子模式”与“自动发送模拟量模式”的数据帧结构一致；同理，阈值、通道状态在自动模式下与手动模式的子模式下发送的数据帧结构也一致
 */
void Change_TransmitData_In_Mode_manual(int mode_in_manual){
	
	memset((void *)linefollower.uart_rx_buffer, 0x00, sizeof(linefollower.uart_rx_buffer));
	linefollower.Data_usable = 0;
	linefollower.sub_work_mode_InManual = mode_in_manual;
	linefollower.uart_rx_buffer_index = 0;
	linefollower.RX_state_machine = unpack_FrameHEAD_1;   //初始化串口接收状态机
	
	switch(mode_in_manual){
		case Transmit_SensorState:{
			linefollower.DataLength_Receive = 1;
			uart4_SendByte(Transmit_SensorState);
			break;
		}
		case Transmit_AnalogValue:{
			linefollower.DataLength_Receive = SENSOR_SUM*2;
			uart4_SendByte(Transmit_AnalogValue);
			break;
		}
		case Transmit_ThresholdValue:{
			linefollower.DataLength_Receive = SENSOR_SUM*2;
			uart4_SendByte(Transmit_ThresholdValue);
			break;
		}
		default:{
			break;
		}
	}
	
}

/**
 * @brief 计算八路巡线传感器在发送阈值/模拟量的数据帧中的校验码
 * @param unsigned char *buf 包含了帧头、命令类型、数据长度、全部参数（不包括校验字节)的一个数组
 * 
 */
unsigned char Check_Code(unsigned char *buf){
  unsigned short sum = 0;
	unsigned char Index = 2;
	unsigned char IndexEnd = (buf[3]+Index+2);
	unsigned char i = 0;
	unsigned char check = 0;
	
  for (i=Index; i < IndexEnd; ++i){
		sum += buf[i];
  }
	
  check = (uint8_t)(~sum);
	
  return check;
}

/**
 * @brief 解析八路巡线传感器发来的数据帧。
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @param unsigned char dat：串口当前收到的1bit数据
 *
 * @note 1.该函数置于串口中断中执行（Uart4_isr(void)）
 *       2.只有涉及模拟量、阈值的回传数据使用数据帧，因此使用状态机进行解析；通道状态的回传数据直接回传1字节，直接读取即可
 */
void uart_FrameUnpack(linefollower_8ch *obj, unsigned char dat){
	//涉及通道状态的工作模式/手动模式子模式	
	if(obj->Work_mode == Transmit_SensorState_auto_mode || \                                           
		 obj->Work_mode == manual_mode && obj->sub_work_mode_InManual == Transmit_SensorState){          
	//1.自动发送通道状态模式 2.手动模式-发送通道状态子模式
					
		obj->StateReg_OriginData = dat;		
		obj->Data_usable = 1;
		
	//涉及模拟量、阈值的工作模式/手动模式子模式
	}else if(obj->Work_mode == Transmit_ThresholdValue_auto_mode || obj->Work_mode == Transmit_AnalogValue_auto_mode  || \   
					 obj->Work_mode == manual_mode && obj->sub_work_mode_InManual == Transmit_AnalogValue || \                       
					 obj->Work_mode == manual_mode && obj->sub_work_mode_InManual == Transmit_ThresholdValue){                       
	//1.自动发送阈值模式 2.自动发送模拟量模式 3.手动模式-发送模拟量状态子模式 4.手动模式-发送阈值状态子模式
		
		//使用状态机逐字节解析收到的数据帧
		switch(obj->RX_state_machine){
			case unpack_FrameHEAD_1:{                                                                                        //获取帧头1
				if(dat == Frame_HEAD_1){
					memset((void *)obj->uart_rx_buffer, 0x00, sizeof(obj->uart_rx_buffer));                                      //清空对象串口缓冲区成员，避免数据混杂
					obj->RX_state_machine = unpack_FrameHEAD_2;
				}	
				break;
			}
			
			case unpack_FrameHEAD_2:{                                                                                        //获取帧头2
				if(dat == Frame_HEAD_2){
					obj->RX_state_machine = unpack_FrameCMD;
					
				}else{
					obj->RX_state_machine = unpack_FrameHEAD_1;				
					
				}			
				break;
			}
			
			case unpack_FrameCMD:{                                                                                          //获取模式类型
				if(dat == obj->Work_mode || (obj->Work_mode == manual_mode && dat == obj->sub_work_mode_InManual)){
					obj->RX_state_machine = unpack_FrameLength;	
					
				}else{
					obj->RX_state_machine = unpack_FrameHEAD_1;	
					
				}
				
				break;
			}
			
			case unpack_FrameLength:{                                                                                       //获取帧参数长度                                                                                                                                                                  
				if( dat == obj->DataLength_Receive ){
					obj->RX_state_machine = unpack_FrameData;
					obj->uart_rx_buffer_index = 3;                                                                              
					/*通过前面状态机的筛选，已基本可以确定当前正在接收的是一帧命令帧，可以将前面的数据放心的传入缓存中，同时索引值向之后的空间，下一个状态循环存入数据帧参数*/
					
					obj->uart_rx_buffer[0] = Frame_HEAD_1;
					obj->uart_rx_buffer[1] = Frame_HEAD_2;
					
					if(obj->Work_mode != manual_mode){
						obj->uart_rx_buffer[2] = obj->Work_mode;
						
					}else{
						obj->uart_rx_buffer[2] = obj->sub_work_mode_InManual;
						
					}
					
					obj->uart_rx_buffer[3] = obj->DataLength_Receive;
					
				}else{
					obj->RX_state_machine = unpack_FrameHEAD_1;	
					
				}
				break;
			}
			
			case unpack_FrameData:{                                                                                        //获取全部参数                              
				if((++ obj->uart_rx_buffer_index) < (3 + obj->DataLength_Receive )){
					obj->uart_rx_buffer[ obj->uart_rx_buffer_index ] = dat;
					break;
					
				}else{                                                      //最后1字节参数
					obj->uart_rx_buffer[ obj->uart_rx_buffer_index ] = dat;
					obj->RX_state_machine = unpack_FrameCheck;		
					break;
				}
				
			}
			
			case unpack_FrameCheck:{                                                                                      //校验数据有效性
				if(dat == Check_Code( obj->uart_rx_buffer )){			//数据校验无误，将串口数据对应搬运至对象自有的存放原始数据的成员中，在之后的其他地方进一步解析	
				
					if(obj->Work_mode == Transmit_AnalogValue_auto_mode || \
						 obj->Work_mode == manual_mode && obj->sub_work_mode_InManual == Transmit_AnalogValue){
						memcpy(obj->SensorAnalogReg_OriginData , (obj->uart_rx_buffer +4), 16);
						
					}else if(obj->Work_mode == Transmit_ThresholdValue_auto_mode || \
									 obj->Work_mode == manual_mode && obj->sub_work_mode_InManual == Transmit_ThresholdValue){
						memcpy(obj->SensorThresholdReg_OriginData , (obj->uart_rx_buffer +4), 16);
						
					}
					
					obj->RX_state_machine = unpack_FrameHEAD_1;
					obj->Data_usable = 1;
					
				}else{			
					obj->RX_state_machine = unpack_FrameHEAD_1;				
					
				}	
				
				break;
			}
			
			default:{		
				break;
			}
		}
	}
}

/**
 * @brief UART通信方式获取各通道状态值并解析
 *
 * @return 1：数据读取完成  0：数据未完成读取
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note 1.StateReg_OriginData为传感器发来的原始数据，可供调试观测
 *       2.实际数据解析需要一定时间，建议使用循环方式阻塞执行，直至数据完全解析
 *       3.阻塞使用时，需要注意数据解析失败/串口无回传导致的死循环，建议加入超时退出机制优化
 */
int detect_state_all_channel_UART(linefollower_8ch *obj){
	uint8_t len=0;
	
	if(obj->Data_usable){
		
		obj->Data_usable = 0;    
		
		for(len = 0; len < SENSOR_SUM; len++)
		{
			obj->state_all_ch[len]= ((obj->StateReg_OriginData >> len) & 0x01); //解析数据，提取各通道状态值
		}	
		
		return 1;
	
	}else{
		return 0;
	}
	
}

/**
 * @brief UART通信方式获取各通道模拟量并解析
 *
 * @return 1：数据读取完成  0：数据未完成读取
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note 1.SensorAnalogReg_OriginData为传感器发来的原始数据，可供调试观测
 *       2.实际数据解析需要一定时间，建议使用循环方式阻塞执行，直至数据完全解析
 *       3.阻塞使用时，需要注意数据解析失败/串口无回传导致的死循环，建议加入超时退出机制优化
 */
int get_AnalogVoltage_all_channel_UART(linefollower_8ch *obj){
	uint8_t len=0;
	uint8_t count=0;
	
	if(obj->Data_usable){

		obj->Data_usable = 0;
		
		for(len = 0,count = 0; len < SENSOR_SUM; len++)
		{
			obj->AnalogVoltage_all_ch[len]= (obj->SensorAnalogReg_OriginData[count]) | (obj->SensorAnalogReg_OriginData[count+1]<<8);  //解析数据，把各通道模拟值低8位和高8位数据合并为16位数据
			count += 2;
		}	
		
		return 1;
	
	}else{
		return 0;
	}
	
}

/**
 * @brief UART通信方式获取各通道阈值并解析
 *
 * @return 1：数据读取完成  0：数据未完成读取
 *
 * @param linefollower_8ch *obj：八路巡线传感器对象
 * @note 1.SensorThresholdReg_OriginData为传感器发来的原始数据，可供调试观测
 *       2.实际数据解析需要一定时间，建议使用循环方式阻塞执行，直至数据完全解析
 *       3.阻塞使用时，需要注意数据解析失败/串口无回传导致的死循环，建议加入超时退出机制优化
 */
int get_ThresholdValue_all_channel_UART(linefollower_8ch *obj){
	uint8_t len=0;
	uint8_t count=0;
	
	if(obj->Data_usable){
	
		obj->Data_usable = 0;
		
		for(len = 0,count = 0; len < SENSOR_SUM; len++)
		{
			obj->ThresholdVoltage_all_ch[len]= (obj->SensorThresholdReg_OriginData[count]) | (obj->SensorThresholdReg_OriginData[count+1]<<8);  //解析数据，把各通道阈值低8位和高8位数据合并为16位数据
			count += 2;
		}	
		
		return 1;
	
	}else{
		return 0;
	}
	
}

//void serial_read_write_control(unsigned char new_state)
//{
//	/* 高电平进入写模式，低电平进入读模式 */
//	P20 = new_state;
//}