/****************************************************************************************************
* created by sunpeng 2017 all rights reserved!
****************************************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ROTATION_H__
#define __ROTATION_H__

/* Includes ------------------------------------------------------------------*/
#include "include.h"

#if ARCH_MODE == CC254X_Peripheral_Mode
#include <ioCC2541.h>
#endif

//六对鼠标滚轮电位器检测IO，6路中断对应6路普通输入IO 
//例如：PIN1对应普通IO PIN11 依次类推
#if ARCH_MODE == NRF52832_Slave_Mode || ARCH_MODE == NRF51822_Peripheral_Mode

#define GET_PIN_IN_STATUS(pin_num)    nrf_gpio_pin_read(pin_num)

#define GET_PIN_IN_STATUS_PIN1    nrf_gpio_pin_read(RotP1)
#define GET_PIN_IN_STATUS_PIN2    nrf_gpio_pin_read(RotP2)
#define GET_PIN_IN_STATUS_PIN3    nrf_gpio_pin_read(RotP3)
#define GET_PIN_IN_STATUS_PIN4    nrf_gpio_pin_read(RotP4)
#define GET_PIN_IN_STATUS_PIN5    nrf_gpio_pin_read(RotP5)
#define GET_PIN_IN_STATUS_PIN6    nrf_gpio_pin_read(RotP6)

#define GET_PIN_IN_STATUS_PIN11   nrf_gpio_pin_read(RotN1)
#define GET_PIN_IN_STATUS_PIN12   nrf_gpio_pin_read(RotN2)
#define GET_PIN_IN_STATUS_PIN13   nrf_gpio_pin_read(RotN3)
#define GET_PIN_IN_STATUS_PIN14   nrf_gpio_pin_read(RotN4)
#define GET_PIN_IN_STATUS_PIN15   nrf_gpio_pin_read(RotN5)
#define GET_PIN_IN_STATUS_PIN16   nrf_gpio_pin_read(RotN6)

#elif ARCH_MODE == CC254X_Peripheral_Mode

#define GET_PIN_IN_STATUS_PIN1    P0_1
#define GET_PIN_IN_STATUS_PIN2    P0_0
#define GET_PIN_IN_STATUS_PIN3    P1_4
#define GET_PIN_IN_STATUS_PIN4    P2_3
#define GET_PIN_IN_STATUS_PIN5    P1_6
#define GET_PIN_IN_STATUS_PIN6    P0_3
				 
#define GET_PIN_IN_STATUS_PIN11   P0_2
#define GET_PIN_IN_STATUS_PIN12   P0_7
#define GET_PIN_IN_STATUS_PIN13   P1_5
#define GET_PIN_IN_STATUS_PIN14   P2_4
#define GET_PIN_IN_STATUS_PIN15   P1_7
#define GET_PIN_IN_STATUS_PIN16   P0_4

#endif

#define mr_axis_max 	6   	//轴数量上限

#if ARCH_MODE == NRF52832_Slave_Mode
#define iTimCntMin		6		//15 轴转动计时器计数下限，小于此数无效  
#define iTimCntMax  	4000	//4000 轴转动计时器计数上限，大于此数无效 
#elif ARCH_MODE == CC254X_Peripheral_Mode
#define iTimCntMin		6		//15 轴转动计时器计数下限，小于此数无效  
#define iTimCntMax  	4000	//4000 轴转动计时器计数上限，大于此数无效 
#elif ARCH_MODE == NRF51822_Peripheral_Mode
#define iTimCntMin		6		//15 轴转动计时器计数下限，小于此数无效  
#define iTimCntMax  	4000	//4000 轴转动计时器计数上限，大于此数无效 
#else
#define iTimCntMin		15		//15 轴转动计时器计数下限，小于此数无效  
#define iTimCntMax  	4000	//4000 轴转动计时器计数上限，大于此数无效 
#endif

#define iTimCntLedShineIntervalMax  	1	//Led闪烁间歇时间计数， 时间100ms间隔左右 

/******************************************************************************/
#if ARCH_MODE == NRF51802_Peripheral_Mode
#define stepPer360        	4              // 每周转动数据总个数
#else
#if ROTATION_DETECT_MODE == ROTATION_DETECT_20_40_MODE || ROTATION_DETECT_MODE == ROTATION_DETECT_20_40_ACK_MODE
#define stepPer360        	40              //40 30 40 39 24 21  每周转动数据总个数
#elif ROTATION_DETECT_MODE == ROTATION_DETECT_15_30_MODE || ROTATION_DETECT_MODE == ROTATION_DETECT_15_30_ACK_MODE
#define stepPer360        	30              //每周转动数据总个数
#endif

#endif
/******************************************************************************/
/* Exported types ------------------------------------------------------------*/


/******************************************************************/
typedef enum
{
    MOUSE_PIN_MIN = -1,
    MOUSE_PIN_1,        	//需保证第一位有效枚举值为0，用于作为数组下标
    MOUSE_PIN_2,
    MOUSE_PIN_3,
    MOUSE_PIN_4,
    MOUSE_PIN_5,
    MOUSE_PIN_6,
    MOUSE_PIN_11,        	//需保证第一位有效枚举值为0，用于作为数组下标
    MOUSE_PIN_12,
    MOUSE_PIN_13,
    MOUSE_PIN_14,
    MOUSE_PIN_15,
    MOUSE_PIN_16,

    MOUSE_PIN_MAX
}MOUSE_PIN_ENUM;

typedef struct
{
    s16 lStepCnt;	  							//转动步数计数值
    u16 iTimCnt;								//存储两个边沿定时器溢出次数计数值
    ROLL_DIRECTION_ENUM prev_prev_direction;  	//存储前次转动方向
    ROLL_DIRECTION_ENUM prev_direction;  		//存储上次转动方向
    ROLL_DIRECTION_ENUM current_direction;  	//存储本次转动方向
    
    unsigned long *mrollpin1;        //第一管脚，中断触发
    unsigned long *mrollpin2;        //第二管脚，判断电平
    int uncertainStep_Flag;                    	//未确定方向的单步标志
#if ROTATION_DETECT_MODE == ROTATION_DETECT_20_40_ACK_MODE || ROTATION_DETECT_MODE == ROTATION_DETECT_15_30_ACK_MODE	
	s8 prevPin2Status;				//pin上次下降沿时对应的pin2电平状态（1/0）
#endif
}MOUSE_ROLL_STRUCT; //转动总结构体

/******************************************************************/
typedef enum
{
	ROLL_POSITION_MIN = -1,
	ROLL_POSITION_0,							//0度位置
	ROLL_POSITION_90,							//90度位置
	ROLL_POSITION_180,							//180度位置
	ROLL_POSITION_270,							//270度位置
	ROLL_POSITION_MAX
}ROLL_POSITION_ENUM;				//转动一周360度共计步数标志

typedef struct
{
	ROLL_POSITION_ENUM position;	//当前位置
	ROLL_DIRECTION_ENUM direction;	//转动方向
	u8 steps;						//转动步数
}ROLL_AXIS_STRUCT;		//面转动状态

typedef struct
{
	ROLL_AXIS_STRUCT side[mr_axis_max];		//所有面转动状态
}ROLL_ALL_AXIS_STRUCT;	//所有面转动状态

/******************************************************************/
typedef struct
{
    MOUSE_PIN_ENUM pin;			//管脚对编号
    s8 status1;					//管脚1 	电平状态
    s8 status11;				//管脚11 	电平状态（对应管脚1）
    u32 time;					//时间戳
}MOUSE_ROLL_STEP_PIN_STATUS_STRUCT;		//转动单步所有管脚状态

#define MOUSE_ROLL_STEP_PIN_STATUS_MAX		512		/* 448 164 64	*/
typedef struct
{
    MOUSE_ROLL_STEP_PIN_STATUS_STRUCT step[MOUSE_ROLL_STEP_PIN_STATUS_MAX];		//所有单步状态
    u16 head;
    u16 tail;
}MOUSE_ROLL_PIN_STATUS_QUEUE_STRUCT;	//转动管脚状态队列


/******************************************************************/
extern u8 keyMotionValid_Flag;// = false;  //电源按键有效标志

#if ARCH_MODE == NRF52832_Slave_Mode || ARCH_MODE == NRF51802_Peripheral_Mode
extern COM_NUM_ENUM com1;
#elif ARCH_MODE == CC254x_Slave_Mode
extern COM_NUM_ENUM com2, com3;
#endif

#if ARCH_MODE == NRF51802_Peripheral_Mode
extern ROLL_ALL_AXIS_STRUCT raas;		//所有面转状态控制

#endif

/* Exported constants --------------------------------------------------------*/
extern MOUSE_ROLL_STRUCT amr[mr_axis_max]; //6个轴转动状态
extern MOUSE_PIN_ENUM current_pin[mr_axis_max];  //分离存储当前处理的轴pin，避免冲掉前一个中断处理函数

extern const float anglePerStep;// = 360/stepPer360+1; //每步代表的角度 360/44 = 8.181818
extern u16 CurrentAngleAllSide[mr_axis_max];//={0x0};  //所有面轴转动最新角度数据  实时更新，格式：AnglePer360Tab

/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
extern void init_rotation_gpio(void);

#if ARCH_MODE == NRF51802_Peripheral_Mode
//把电压转换成位置
s8 convert_from_voltage_to_position(u16 voltage, ROLL_POSITION_ENUM *position);

s8 init_RAAS(ROLL_ALL_AXIS_STRUCT *raas);
s8 get_RAAS_position_by_axis(ROLL_ALL_AXIS_STRUCT *raas, u16 axis, ROLL_POSITION_ENUM *position);
s8 set_RAAS_position_by_axis(ROLL_ALL_AXIS_STRUCT *raas, u16 axis, ROLL_POSITION_ENUM position);
s8 get_RAAS_direction_and_steps_by_axis(ROLL_ALL_AXIS_STRUCT *raas, u16 axis, ROLL_DIRECTION_ENUM *direction, u8 *steps);
s8 set_RAAS_direction_and_steps_by_axis(ROLL_ALL_AXIS_STRUCT *raas, u16 axis, ROLL_DIRECTION_ENUM direction, u8 steps);

//更新并判断位置是否变化 true=位置变化  false=位置未变化
s8 update_and_judge_position_changing(u16 axis, ROLL_POSITION_ENUM position);


#endif
extern void uninit_rotation_gpio(void);

extern u8 updateZeroAngleAllSide(u8 *buf); //更新所有面零度机器常数

/************************************************************
初始化360度每步转动所占的角度  角度范围【0,360】
************************************************************/
extern u8 initAnglePer360Tab(void);
extern u8 updateCurrentAngleBySide(u8 side, u16 angle);
extern int getCurrentAngleBySide(u8 side, u16 *angle);
extern int setCurrentAngleBySide(u8 side, u16 angle);
extern u8 sendRotationAngleBySide(u8 cmd);

/***************************************************
初始化6个面所有相邻的四个面
***************************************************/
extern void initBesidePins(void);
/***************************************************
判断prev_pin所代表的面与new_pin代表的面是否相邻
***************************************************/
extern int judgeBesidePins(MOUSE_PIN_ENUM *prev_pin,MOUSE_PIN_ENUM *new_pin);

/************************************************************
初始化6路滚轮传感器转动方向识别数据结构初始值
	鼠标滚轮传感器两路信号识别方式：
		两路信号编号分别为1、2号，1号管脚为外部中断触发，上升沿下降沿都触发中断
		通过一号脚中断后判断一号二号的电平高低判断当前转动方向
		
************************************************************/
extern int initDetectVariable(void);
/**********************************************************
	定时器中定时递增TimCnt计数值  1ms每次
**********************************************************/
extern void timerAddTimCnt(void);


#if ARCH_MODE == NRF51822_Peripheral_Mode
/************************************************************
//全部：6路外部中断P类管脚电平状态检测
************************************************************/
extern s8 cycleDetectAllPin(void);

#else
/************************************************************
//单路：6路外部中断P类管脚电平状态检测
************************************************************/
extern s8 cycleDetect(MOUSE_PIN_ENUM pin);

//定时处理管脚状态队列
extern s8 cycleProcessPinStatus(void);

#endif

/************************************************************
通过1号、2号管脚电平判断单步转动方向：
		1号电平   2号电平	方向
		1			1		前
		1			0		后
		0			1		后
		0			0		前
************************************************************/
extern s8 judgePin1UpDown(MOUSE_PIN_ENUM *pin,
                    MOUSE_ROLL_STRUCT *mr, 
					s8 *status1, 
					s8 *status11,
					u32 *time
                    );
					
/************************************************************
转动步计数增减
************************************************************/
extern s8 stepAddMinus(ROLL_DIRECTION_ENUM directionNow,//单步转动方向
				MOUSE_PIN_ENUM *pin,
				MOUSE_ROLL_STRUCT *mr,
				u32 *time
				);

//将转动检测到的动作压入缓冲队列
extern void mouse_rotation_queue(
							MOUSE_PIN_ENUM *pin,
							MOUSE_ROLL_STRUCT *mr,
							u32 *time
							);

/***************************************************
	执行面转动Led灯闪烁命令分发到灯控板
***************************************************/
extern u8 performRollLedShine(void);

#if ARCH_MODE == NRF51802_Peripheral_Mode

void potentiometer_rotation_queue(	u16 axis,						//转动轴代号
							ROLL_DIRECTION_ENUM direction,	//转动方向
							u8 steps						//转动步数（一步90度）
							);
#endif
/************************************************************
	定时检测转动检测队列是否有数据，若有通过网络上传App
************************************************************/
extern s8 send_mouse_rotation_queue(void);

/*********************************************************************/
//初始化管脚状态缓冲队列
extern void InitRollPinStaQue(MOUSE_ROLL_PIN_STATUS_QUEUE_STRUCT *dataS);
//获取队列长度
extern u16 GetRollPinStaQueLen(MOUSE_ROLL_PIN_STATUS_QUEUE_STRUCT *dataS);
//写入一个数据到队列
extern s8 PutRollPinStaQue(MOUSE_ROLL_PIN_STATUS_QUEUE_STRUCT *dataS, MOUSE_PIN_ENUM *pin, s8 *status1, s8 *status11, u32 *time, u16 dataLen);
//获取队列中队首一个成员，改变读head
extern s8 GetRollPinStaQue(MOUSE_ROLL_PIN_STATUS_QUEUE_STRUCT *dataS, MOUSE_PIN_ENUM *pin, s8 *status1, s8 *status11, u32 *time);


#endif /* __ROTATION_H */

/*********************************************end of file*********************************************/
