
#include "imx8_drv_gpio.h"

static volatile uintptr_t gpio_base_0;
static volatile uintptr_t gpio_base_1;
static volatile uintptr_t gpio_base_2;
static volatile uintptr_t gpio_base_3;
static volatile uintptr_t gpio_base_4;
static volatile uintptr_t gpio_base_5;

static uintptr_t tbase;
static volatile unsigned int cnt = 0;
static int val;
static pthread_t timer_thread;
static pthread_t gpioFeedbackIrq_thread;
static pthread_t gpioChanAIrq_thread;
static pthread_t gpioChanBIrq_thread;
static struct sigevent event;
static intrspin_t spinner;

static struct sigevent gpioFeedbackIrqEvent = {0};
static struct sigevent gpioChanAIrqEvent = {0};
static struct sigevent gpioChanBIrqEvent = {0};
static uint32_t irqCnt[3U] = {0};


/*AB Sync*/
static volatile uint8_t s_isABSyncStart = 0u;
static volatile uint8_t s_ECapPause[3u] = {0u};//采集开关控制
static volatile uint32_t s_ABSynDuty = 0u;//定义双系心跳信号输出的占空比：0.5--对应输出是50%
static volatile struct SCapInfo s_CapInfo[3u] = {0U};
static volatile ABSynMsgType g_userSetSyncMsgType = ABSynMsgType_0;

static float sSyncMsgErrInfo[ABSynMsgType_MAX] = {0.0f};

static void calculate(uint8_t index,float *Duty,float *Period,uint32_t* pPulseCnt);
static ABSynMsgType drvPWMAnalyze(float Duty,float Period);
static void pulseCount(uint8_t index);
static void drvGetABSyn(float *Duty,float *Period,uint32_t* pPulseCnt);
static void Task_ABSyncPulse(void);

void* gpioChanAIrq( void * arg);
const struct sigevent *gpioChanAIrq_handler (void *not_used, int id);
void* gpioChanBIrq( void * arg);
const struct sigevent *gpioChanBIrq_handler (void *not_used, int id);
void* gpioFeedbackIrq( void * arg);
const struct sigevent *gpioFeedbackIrq_handler (void *not_used, int id);

static struct ifdrv2{
    struct ifdrv ifd;
    phy_access_t req;
}phycmd;

char drv_vsr[4] = {93, 8, 0, 11};

/*GPIO init*/
int imx8_gpio_init(void)
{

	int ret = 0;
	gpio_base_0 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO0_BASE);
	if(gpio_base_0 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 0 I/O");
		ret = -1;
	}
	else
	{

	}

	gpio_base_1 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO1_BASE);
	if(gpio_base_1 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 1 I/O");
		ret = -1;
	}
	else
	{

	}

	gpio_base_2 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO2_BASE);
	if(gpio_base_2 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 2 I/O");
		ret = -1;
	}
	else
	{

	}

	gpio_base_3 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO3_BASE);
	if(gpio_base_3 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 3 I/O");
		ret = -1;
	}
	else
	{

	}

	gpio_base_4 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO4_BASE);
	if(gpio_base_4 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 4 I/O");
		ret = -1;
	}
	else
	{

	}

	gpio_base_5 = mmap_device_io((size_t)IMX_GPIO_SIZE, (uint64_t)IMX_GPIO5_BASE);
	if(gpio_base_5 == MAP_DEVICE_FAILED)
	{
		perror("Can't map device base 5 I/O");
		ret = -1;
	}
	else
	{

	}

	/*input config*/
	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) & ~(0x932000U)));
	out32(gpio_base_3 + IMX_GPIO_GDIR, (in32(gpio_base_3 + IMX_GPIO_GDIR) & ~(0x17fc0000U)));
	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) & ~(0x100006U)));

	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) | (1UL << 12)));
	out32(gpio_base_4 + IMX_GPIO_DR, (in32(gpio_base_4 + IMX_GPIO_DR) | (1UL << 12)));



	/*output config*/
	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) | (0xcc00cc0UL)));


	printf("dirver version : %d,%d,%d,%d\n",drv_vsr[0],drv_vsr[1],drv_vsr[2],drv_vsr[3]);

	return ret;
}


/*This function for switch button*/
int imx8_switch_button(void)
{

	int ret = 0;

	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) | (1UL << 22)));
	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) & ~(1UL << 20)));

	out32(gpio_base_4 + IMX_GPIO_DR, (in32(gpio_base_4 + IMX_GPIO_DR) | (1UL << 22)));
	ret = (uint32_t)(in32(gpio_base_4 + IMX_GPIO_PSR) & (1UL << 20)) >> 20;

	return ret;

}

/*read boardid function*/
unsigned char imx8_read_boardID(void)
{
	unsigned char id = 0U;
	out32(gpio_base_3 + IMX_GPIO_GDIR, (uint32_t)(in32(gpio_base_3 + IMX_GPIO_GDIR) & ~((0xFFUL << 18))));

	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 18)) >> 18) << 7);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 19)) >> 19) << 6);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 20)) >> 20) << 5);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 21)) >> 21) << 4);

	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 22)) >> 22) << 3);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 23)) >> 23) << 2);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 24)) >> 24) << 1);
	id |= (uint8_t)(((in32(gpio_base_3 + IMX_GPIO_PSR) & (1UL << 25)) >> 25));

	return id;
}

/*input collect*/
int imx8_input_collect(int channel)
{
	ThreadCtl (_NTO_TCTL_IO, 0);
	int value = 0;
#if 0
	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) & ~(0x932000U)));
	out32(gpio_base_3 + IMX_GPIO_GDIR, (in32(gpio_base_3 + IMX_GPIO_GDIR) & ~(0x17fc0000U)));
	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) & ~(0x100006U)));

	out32(gpio_base_4 + IMX_GPIO_GDIR, (in32(gpio_base_4 + IMX_GPIO_GDIR) | (1UL << 12)));
	out32(gpio_base_4 + IMX_GPIO_DR, (in32(gpio_base_4 + IMX_GPIO_DR) | (1UL << 12)));
#endif

	InterruptLock( &spinner );

	if(1 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 8)) >> 8;
	}
	else if(2 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 9)) >> 9;
	}
	else if(3 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 12)) >> 12;
	}
	else if(4 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 13)) >> 13;
	}
	else if(5 == channel)
	{
		value = (in32(gpio_base_4 + IMX_GPIO_PSR) & (uint32_t)(1UL << 1)) >> 1;
	}
	else if(6 == channel)
	{
		value = (in32(gpio_base_4 + IMX_GPIO_PSR) & (uint32_t)(1UL << 2)) >> 2;
	}
	else if(7 == channel)
	{
		value = (in32(gpio_base_3 + IMX_GPIO_PSR) & (uint32_t)(1UL << 26)) >> 26;
	}
	else if(8 == channel)
	{
		value = (in32(gpio_base_3 + IMX_GPIO_PSR) & (uint32_t)(1UL << 28)) >> 28;
	}
	else if(9 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 19)) >> 19;
	}
	else if(10 == channel)
	{
		value = (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 16)) >> 16;
	}
	else
	{
		perror("input error channel start 1 to 10");
		value =  -1;
	}

	InterruptUnlock( &spinner );
	return value;
}


int imx8_output(int channel, int level)
{

//	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) | (0xcc00cc0UL)));

	ThreadCtl (_NTO_TCTL_IO, 0);

	int ret = 0;

	InterruptLock( &spinner );

	switch(channel)
	{
	case 1:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 26)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 26)) >> 26;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 26)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 26)) >> 26;
		}
		else
		{
			perror("channel 1 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 2:
		if(1 == level)
		{

			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 27)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 27)) >> 27;

		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 27)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 27)) >> 27;
		}
		else
		{
			perror("channel 2 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 3:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 10)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 10)) >> 10;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 10)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 10)) >> 10;
		}
		else
		{
			perror("channel 3 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 4:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 7)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 7)) >> 7;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 7)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 7)) >> 7;
		}
		else
		{
			perror("channel 4 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 5:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 6)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 6)) >> 6;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 6)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 6)) >> 6;
		}
		else
		{
			perror("channel 5 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 6:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 11)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 11)) >> 11;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 11)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 11)) >> 11;
		}
		else
		{
			perror("channel 6 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 7:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 22)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 22)) >> 22;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 22)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 22)) >> 22;
		}
		else
		{
			perror("channel 7 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	case 8:
		if(1 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 23)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 23)) >> 23;
		}
		else if(0 == level)
		{
			out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 23)));
			ret = (in32(gpio_base_0 + IMX_GPIO_DR) & (1UL << 23)) >> 23;
		}
		else
		{
			perror("channel 8 input wrong para level must 1 or 0");
			ret = -1;
		}
		break;

	default:
		perror("channel must be 1 to 8\n");
		ret = -1;
		break;
	}

	InterruptUnlock( &spinner );


	return ret;
}


/*Input RED, GREEN or OFF,control by cpu1 and cpu2*/
int imx8_led_REA_REB(int light)
{

	int ret = 0;

	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) | (1UL << 26) | (1UL << 27)));

	if(light == RED)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, ((in32(gpio_base_5 + IMX_GPIO_DR) & ~(1UL << 26)) | (1UL << 27)));
	}
	else if(light == GREEN)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, ((in32(gpio_base_5 + IMX_GPIO_DR) | (1UL << 26) )& ~(1UL << 27)));
	}
	else if(light == OFF)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, (in32(gpio_base_5 + IMX_GPIO_DR) & ~(0x3UL << 26)));
	}
	else
	{
		perror("input wrong pare please input GREEN ,RED or OFF");
		ret = -1;
	}
	return ret;
}

/*Input RED, GREEN or OFF, control by cpu1*/
int imx8_led_R_E(int light)
{
	int ret = 0;
	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) | (1UL << 28) | (1UL << 29)));

	if(light == GREEN)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, ((in32(gpio_base_5 + IMX_GPIO_DR) & ~(1UL << 28)) | (1UL << 29)));
	}
	else if(light == RED)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, ((in32(gpio_base_5 + IMX_GPIO_DR) | (1UL << 28) )& ~(1UL << 29)));
	}
	else if(light == OFF)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, (in32(gpio_base_5 + IMX_GPIO_DR) & ~(0x3UL << 28)));
	}
	else
	{
		perror("input wrong pare please input GREEN , RED or OFF\n");
		ret = -1;
	}

	return ret;
}

/*Input YELLOW, GREEN or OFF,control by cpu1*/
int imx8_led_M_S(int light)
{

	int ret = 0;

	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) | (1UL << 14) | (1UL << 15)));

	if(light == YELLOW)
	{
		out32(gpio_base_2 + IMX_GPIO_DR, ((in32(gpio_base_2 + IMX_GPIO_DR) & ~(1UL << 14)) | (1UL << 15)));
	}
	else if(light == GREEN)
	{
		out32(gpio_base_2 + IMX_GPIO_DR, ((in32(gpio_base_2 + IMX_GPIO_DR) | (1UL << 14) )& ~(1UL << 15)));
	}
	else if(light == OFF)
	{
		out32(gpio_base_2 + IMX_GPIO_DR, (in32(gpio_base_2 + IMX_GPIO_DR) & ~(0x3UL << 14)));
	}
	else
	{
		perror("input wrong pare please input GREEN , YELLOW or OFF\n");
		ret = -1;
	}
	return ret;
}



/*return 0 means cpu 0*/
unsigned int imx8_read_cpuid(void)
{
	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) & ~(1UL << 25)));
	return (in32(gpio_base_5 + IMX_GPIO_PSR) & (uint32_t)(1UL << 25)) >> 25;
}

/*input 1 : enable, input 0 : disable*/
int imx8_dcdc_1_ctrl(int level)
{
	int ret = 0;

	out32(gpio_base_1 + IMX_GPIO_GDIR, (in32(gpio_base_1 + IMX_GPIO_GDIR) | (1UL << 10) ));

	if(0 == level)
	{
		out32(gpio_base_1 + IMX_GPIO_DR, (in32(gpio_base_1 + IMX_GPIO_DR) & ~(1UL << 10)));
	}
	else if(1 == level)
	{
		out32(gpio_base_1 + IMX_GPIO_DR, (in32(gpio_base_1 + IMX_GPIO_DR) | (1UL << 10)));
	}
	else
	{
		perror("input wrong level please input 1 or 0");
		ret = -1;
	}
	return ret;
}

/*input 1 : enable, input 0 : disable*/
int imx8_dcdc_2_ctrl(int level)
{
	int ret = 0;

	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) | (1UL << 20) ));

	if(0 == level)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, (in32(gpio_base_5 + IMX_GPIO_DR) & ~(1UL << 20)));
	}
	else if(1 == level)
	{
		out32(gpio_base_5 + IMX_GPIO_DR, (in32(gpio_base_5 + IMX_GPIO_DR) | (1UL << 20)));
	}
	else
	{
		perror("input wrong level please input 1 or 0");
		ret = -1;
	}
	return ret;
}


/*return 1 means normal, 0 means Overvoltage*/
unsigned int imx8_Safe_gate_overvoltage_state_1(void)
{
	out32(gpio_base_1 + IMX_GPIO_GDIR, (in32(gpio_base_1 + IMX_GPIO_GDIR) & ~(1UL << 20)));
	return (in32(gpio_base_1 + IMX_GPIO_PSR) & (uint32_t)(1UL << 20)) >> 20;
}

/*return 1 means normal, 0 means Overvoltage*/
unsigned int imx8_Safe_gate_undervoltage_state_1(void)
{
	out32(gpio_base_1 + IMX_GPIO_GDIR, (in32(gpio_base_1 + IMX_GPIO_GDIR) & ~(1UL << 6)));
	return (in32(gpio_base_1 + IMX_GPIO_PSR) & (uint32_t)(1UL << 6)) >> 6;
}

/*return 1 means normal, 0 means Overvoltage*/
unsigned int imx8_Safe_gate_overvoltage_state_2(void)
{
	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) & ~(1UL << 29)));
	return (in32(gpio_base_2 + IMX_GPIO_PSR) & (uint32_t)(1UL << 29)) >> 29;
}

/*return 1 means normal, 0 means Overvoltage*/
unsigned int imx8_Safe_gate_undervoltage_state_2(void)
{
	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) & ~(1UL << 19)));
	return (in32(gpio_base_5 + IMX_GPIO_PSR) & (uint32_t)(1UL << 19)) >> 19;
}


/*return 1 means on, return 0 means off*/
unsigned int imx8_ethernet_switch_state_1_1(void)
{
	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) & ~(1UL << 22)));
	return (in32(gpio_base_2 + IMX_GPIO_PSR) & (uint32_t)(1UL << 22)) >> 22;
}

/*return 1 means on, return 0 means off*/
unsigned int imx8_ethernet_switch_state_1_2(void)
{
	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) & ~(1UL << 23)));
	return (in32(gpio_base_2 + IMX_GPIO_PSR) & (uint32_t)(1UL << 23)) >> 23;
}

/*return 1 means on, return 0 means off*/
unsigned int imx8_ethernet_switch_state_2_1(void)
{
	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) & ~(1UL << 25)));
	return (in32(gpio_base_2 + IMX_GPIO_PSR) & (uint32_t)(1UL << 25)) >> 25;
}

/*return 1 means on, return 0 means off*/
unsigned int imx8_ethernet_switch_state_2_2(void)
{
	out32(gpio_base_2 + IMX_GPIO_GDIR, (in32(gpio_base_2 + IMX_GPIO_GDIR) & ~(1UL << 31)));
	return (in32(gpio_base_2 + IMX_GPIO_PSR) & (uint32_t)(1UL << 31)) >> 31;
}

/*------------------------------------------------------------*/


/*return 1 means 24V normal*/
unsigned int imx8_24V_voltage_state(void)
{
	out32(gpio_base_1 + IMX_GPIO_GDIR, (in32(gpio_base_1 + IMX_GPIO_GDIR) & ~(1UL << 7)));
	return (in32(gpio_base_1 + IMX_GPIO_PSR) & (uint32_t)(1UL << 7)) >> 7;
}


/*------------------------------------------------------------*/

/*return 1 means 5V 3.3V normal*/
unsigned int imx8_5V_overvoltage_state(void)
{
	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) & ~(1UL << 2)));
	return (in32(gpio_base_0 + IMX_GPIO_PSR) & (uint32_t)(1UL << 2)) >> 2;
}

/*return 1 means 5V 3.3V normal*/
unsigned int imx8_5V_undervoltage_state(void)
{
	out32(gpio_base_5 + IMX_GPIO_GDIR, (in32(gpio_base_5 + IMX_GPIO_GDIR) & ~(1UL << 23)));
	return (in32(gpio_base_5 + IMX_GPIO_PSR) & (uint32_t)(1UL << 23)) >> 23;
}

/*-------------------------- power-off ethernet----------------------------*/

int imx8_safty_ethernet_off(void)
{

	int ret = 0;

    ret = imx8_dcdc_1_ctrl(0);
    ret = imx8_dcdc_2_ctrl(0);


	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) & ~(1UL << 4)));
	out32(gpio_base_3 + IMX_GPIO_GDIR, (in32(gpio_base_3 + IMX_GPIO_GDIR) & ~(1UL << 14)));

	out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) &  ~(1UL << 4)));
	out32(gpio_base_3 + IMX_GPIO_DR, (in32(gpio_base_3 + IMX_GPIO_DR) &  ~(1UL << 14)));

	return ret;
}


/*timer irq function*/
const struct sigevent *handler (void *not_used, int id)
{

	cnt++;

	if((cnt%(uint32_t)2) == (uint32_t)0)
	{
		out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 4)));
		out32(gpio_base_3 + IMX_GPIO_DR, (in32(gpio_base_3 + IMX_GPIO_DR) | (1UL << 14)));
	}
	else
	{
		out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 4)));
		out32(gpio_base_3 + IMX_GPIO_DR, (in32(gpio_base_3 + IMX_GPIO_DR) & ~(1UL << 14)));
	}

    out32(tbase + GPT_SR, 0x1U);
    return &event;

}


/*timer pthread*/
void* timer( void * arg)
{
	int ret = 0;
    ret = ThreadCtl (_NTO_TCTL_IO, 0);
    SIGEV_INTR_INIT (&event);

    ret = imx8_dcdc_1_ctrl(1);
    ret = imx8_dcdc_2_ctrl(1);

	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) |  (1UL << 4)));
	out32(gpio_base_3 + IMX_GPIO_GDIR, (in32(gpio_base_3 + IMX_GPIO_GDIR) |  (1UL << 14)));

	val = InterruptAttach(IMX_GPT0_IRQ, handler, NULL, 0,_NTO_INTR_FLAGS_TRK_MSK );

    out32(tbase + GPT_CR, (uint32_t)0x20000142);
    out32(tbase + GPT_PR, (uint32_t)0x7002);
    out32(tbase + GPT_SR, (uint32_t)0x3f);
    out32(tbase + GPT_IR, (uint32_t)0);
    out32(tbase , (uint32_t)0x20000543);
    out32(tbase + GPT_IR, (uint32_t)0x21);
    out32(tbase + GPT_OCR1, (uint32_t)0x3e);


    while(1)
    {
		ret = InterruptWait(0, 0);
		ret = InterruptUnmask(IMX_GPT0_IRQ, val);
    }

    /*you will never reach here*/
    return NULL;
}

/*create 8khz timer*/
int imx8_create_timer_pthread(void)
{
	int ret = 0;

	tbase = mmap_device_io((size_t)0x1000, (uint64_t)IMX_GPT0_BASE);
	if(tbase == MAP_DEVICE_FAILED)
	{
		perror("Can't map timer device I/O");
		ret = -1;
	}
	else
	{

	}

    ret = pthread_create(&timer_thread, NULL, timer, NULL);
    return ret;
}


/************************************************************************/
/*25% timer irq function*/
const struct sigevent *handler_25 (void *not_used, int id)
{
	unsigned int cpuid = 0;

	cnt++;
	InterruptLock( &spinner );

	cpuid = imx8_read_cpuid();
	if (1U == cpuid)
	{
		Task_ABSyncPulse();
	}
	else
	{
		/*do nothing*/
	}

	if((cnt%(uint32_t)4) == (uint32_t)0)
	{
		out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) | (1UL << 4)));
		out32(gpio_base_3 + IMX_GPIO_DR, (in32(gpio_base_3 + IMX_GPIO_DR) | (1UL << 14)));
	}
	else
	{
		out32(gpio_base_0 + IMX_GPIO_DR, (in32(gpio_base_0 + IMX_GPIO_DR) & ~(1UL << 4)));
		out32(gpio_base_3 + IMX_GPIO_DR, (in32(gpio_base_3 + IMX_GPIO_DR) & ~(1UL << 14)));
	}

	InterruptUnlock( &spinner );

    out32(tbase + GPT_SR, 0x1U);
    return &event;

}


/*25% timer pthread*/
void* timer_25( void * arg)
{
	int ret = 0;

    ret = ThreadCtl (_NTO_TCTL_IO, 0);
    SIGEV_INTR_INIT (&event);

    ret = imx8_dcdc_1_ctrl(1);
    ret = imx8_dcdc_2_ctrl(1);

	out32(gpio_base_0 + IMX_GPIO_GDIR, (in32(gpio_base_0 + IMX_GPIO_GDIR) |  (1UL << 4)));
	out32(gpio_base_3 + IMX_GPIO_GDIR, (in32(gpio_base_3 + IMX_GPIO_GDIR) |  (1UL << 14)));

	val = InterruptAttach(IMX_GPT0_IRQ, handler_25, NULL, 0,_NTO_INTR_FLAGS_TRK_MSK );

    out32(tbase + GPT_CR, (uint32_t)0x20000142);

    out32(tbase + GPT_PR, (uint32_t)0x3002);

    out32(tbase + GPT_SR, (uint32_t)0x3f);
    out32(tbase + GPT_IR, (uint32_t)0);
    out32(tbase , (uint32_t)0x20000543);
    out32(tbase + GPT_IR, (uint32_t)0x21);
    out32(tbase + GPT_OCR1, (uint32_t)0x3e);


    while(1)
    {
		ret = InterruptWait(0, 0);
		ret = InterruptUnmask(IMX_GPT0_IRQ, val);
    }

    /*you will never reach here*/
    ret = NULL;
    return ret;

}

/*create 25% 8khz timer*/
int imx8_create_timer_pthread_25(void)
{
	int ret = 0;

	tbase = mmap_device_io((size_t)0x1000, (uint64_t)IMX_GPT0_BASE);
	if(tbase == MAP_DEVICE_FAILED)
	{
		perror("Can't map timer device I/O");
		ret = -1;
	}
	else
	{

	}

    ret = pthread_create(&timer_thread, NULL, timer_25, NULL);

    return ret;
}
/************************************************************************/

int imx8_gpio_release(void)
{
	int ret = 0;
	ret = munmap_device_io(gpio_base_0, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	ret = munmap_device_io(gpio_base_1, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	ret = munmap_device_io(gpio_base_2, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	ret = munmap_device_io(gpio_base_3, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	ret = munmap_device_io(gpio_base_4, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	ret = munmap_device_io(gpio_base_5, 0x10UL);
	if(ret > 0)
	{
		ret = -1;
		perror("munmap_device_io failed");
	}
	else
	{

	}

	return ret;
}

const struct sigevent *gpioFeedbackIrq_handler (void *not_used, int id)
{
	if (NULL == not_used)
	{
		return &gpioFeedbackIrqEvent;
	}
	uint8_t index = *(uint8_t*)not_used;
	InterruptLock( &spinner );
	irqCnt[index]++;
	pulseCount(index);
	InterruptUnlock( &spinner );
    return &gpioFeedbackIrqEvent;
}

void* gpioFeedbackIrq( void * arg)
{
	int feedval = 0;
	uint8_t index = 2u;
	uint32_t regVal = 0u;

    (void)ThreadCtl (_NTO_TCTL_IO, NULL);

	/*disable gpio irq*/
    regVal = (in32(gpio_base_3 + IMX_GPIO_IMR) & (uint32_t)~(1UL << 26U));
	out32(gpio_base_3 + IMX_GPIO_IMR, regVal);
	/*config gpio irq*/
	/*dir is input*/
	regVal = (in32(gpio_base_3 + IMX_GPIO_GDIR) &  (uint32_t)~(1UL << 26U));
	out32(gpio_base_3 + IMX_GPIO_GDIR, regVal);
	/*select trigger way--rising edge sensitive*/
	regVal = (in32(gpio_base_3 + IMX_GPIO_ICR2) | (uint32_t)(2UL << 20U));
	out32(gpio_base_3 + IMX_GPIO_ICR2, regVal);
	/*clear isr reg*/
	regVal = (in32(gpio_base_3 + IMX_GPIO_ISR) | (uint32_t)(1UL << 26U));
	out32(gpio_base_3 + IMX_GPIO_ISR, regVal);
	/*reg intr service*/
    SIGEV_INTR_INIT(&gpioFeedbackIrqEvent);
    feedval = InterruptAttach(666, gpioFeedbackIrq_handler, (const void*)&index, 1,_NTO_INTR_FLAGS_TRK_MSK);
#if 0
	printf("gpio 3_26 irq init finished\n");
	printf("gpio3 IMR val is %x\n",in32(gpio_base_3 + IMX_GPIO_IMR));
	printf("gpio3 ISR val is %x\n",in32(gpio_base_3 + IMX_GPIO_ISR));
	printf("gpio3 GDIR val is %x\n",in32(gpio_base_3 + IMX_GPIO_GDIR));
	printf("gpio3 ICR2 val is %x\n",in32(gpio_base_3 + IMX_GPIO_ICR2));
#endif
	/*enable gpio irq*/
	regVal = (in32(gpio_base_3 + IMX_GPIO_IMR) | (uint32_t)(1UL << 26U));
	out32(gpio_base_3 + IMX_GPIO_IMR, regVal);


    while(1)
    {
		(void)InterruptWait(0, NULL);
		(void)InterruptUnmask(666, feedval);
    }

    /*you will never reach here*/
    return NULL;

}



const struct sigevent *gpioChanBIrq_handler (void *not_used, int id)
{
	if (NULL == not_used)
	{
		return &gpioChanBIrqEvent;
	}
	uint8_t index = *(uint8_t*)not_used;
	InterruptLock( &spinner );
	irqCnt[index]++;
	pulseCount(index);
	InterruptUnlock( &spinner );
    return &gpioChanBIrqEvent;
}

void* gpioChanBIrq( void * arg)
{
	int chanBval = 0;
	uint8_t index = 1u;
	uint32_t regVal = 0u;

    (void)ThreadCtl (_NTO_TCTL_IO, NULL);

	/*disable gpio irq*/
    regVal = (in32(gpio_base_4 + IMX_GPIO_IMR) & (uint32_t)~(1UL << 2U));
	out32(gpio_base_4 + IMX_GPIO_IMR, regVal);
	/*config gpio0_12 irq*/
	/*dir is input*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_GDIR) & (uint32_t)~(1UL << 2U));
	out32(gpio_base_4 + IMX_GPIO_GDIR, regVal);
	/*select trigger way--rising edge sensitive*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_ICR1) | (uint32_t) (2UL << 4U));
	out32(gpio_base_4 + IMX_GPIO_ICR1, regVal);
	/*clear isr reg*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_ISR) | (uint32_t)(1UL << 2U));
	out32(gpio_base_4 + IMX_GPIO_ISR, regVal);
	/*reg intr service*/
    SIGEV_INTR_INIT(&gpioChanBIrqEvent);
    /*This step maybe enable the IMR?*/
    chanBval = InterruptAttach(674, gpioChanBIrq_handler, (const void*)&index, 1,_NTO_INTR_FLAGS_TRK_MSK);
#if 0
	printf("Chan B(4_2) irq init finished\n");
	printf("gpio4 IMR val is %x\n",in32(gpio_base_4 + IMX_GPIO_IMR));
	printf("gpio4 ISR val is %x\n",in32(gpio_base_4 + IMX_GPIO_ISR));
	printf("gpio4 GDIR val is %x\n",in32(gpio_base_4 + IMX_GPIO_GDIR));
	printf("gpio4 ICR1 val is %x\n",in32(gpio_base_4 + IMX_GPIO_ICR1));
#endif
	/*enable gpio irq*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_IMR) | (uint32_t)(1UL << 2U));
	out32(gpio_base_4 + IMX_GPIO_IMR, regVal);


    while(1)
    {
		(void)InterruptWait(0, NULL);
		(void)InterruptUnmask(674, chanBval);
    }

    /*you will never reach here*/
    return NULL;
}


const struct sigevent *gpioChanAIrq_handler (void *not_used, int id)
{
	if (NULL == not_used)
	{
		return &gpioChanAIrqEvent;
	}
	uint8_t index = *(uint8_t*)not_used;
	InterruptLock( &spinner );
	irqCnt[index]++;
	pulseCount(index);
	InterruptUnlock( &spinner );
    return &gpioChanAIrqEvent;
}

void* gpioChanAIrq( void * arg)
{
	int chanAval = 0;
	uint8_t index = 0u;
	uint32_t regVal = 0u;

    (void)ThreadCtl (_NTO_TCTL_IO, NULL);

	/*disable gpio irq*/
    regVal = in32(gpio_base_4 + IMX_GPIO_IMR) & (uint32_t)~(1UL << 1U);
	out32(gpio_base_4 + IMX_GPIO_IMR, regVal);
	/*config gpio0_9 irq*/
	/*dir is input*/
	regVal = in32(gpio_base_4 + IMX_GPIO_GDIR) &  (uint32_t)~(1UL << 1U);
	out32(gpio_base_4 + IMX_GPIO_GDIR,regVal);
	/*select trigger way--rising edge sensitive*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_ICR1) | (uint32_t)(2UL << 2U));
	out32(gpio_base_4 + IMX_GPIO_ICR1, regVal);
	/*clear isr reg*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_ISR) | (uint32_t)(1UL << 1U));
	out32(gpio_base_4 + IMX_GPIO_ISR, regVal);
	/*reg intr service*/
    SIGEV_INTR_INIT(&gpioChanAIrqEvent);
    chanAval = InterruptAttach(673, gpioChanAIrq_handler, (const void*)&index, 1,_NTO_INTR_FLAGS_TRK_MSK);
#if 0
	printf("gpio ChanA(4_1) irq init finished\n");
	printf("gpio4 IMR val is %x\n",in32(gpio_base_4 + IMX_GPIO_IMR));
	printf("gpio4 ISR val is %x\n",in32(gpio_base_4 + IMX_GPIO_ISR));
	printf("gpio4 GDIR val is %x\n",in32(gpio_base_4 + IMX_GPIO_GDIR));
	printf("gpio4 ICR1 val is %x\n",in32(gpio_base_4 + IMX_GPIO_ICR1));
#endif
	/*enable gpio irq*/
	regVal = (in32(gpio_base_4 + IMX_GPIO_IMR) | (uint32_t)(1UL << 1U));
	out32(gpio_base_4 + IMX_GPIO_IMR, regVal);


    while(1)
    {
		(void)InterruptWait(0, NULL);
		(void)InterruptUnmask(673, chanAval);
    }

    /*you will never reach here*/
    return NULL;
}

int imx8_create_gpio_irq_pthread(void)
{
	int ret = 0;

	ret = pthread_create(&gpioFeedbackIrq_thread, NULL, gpioFeedbackIrq, NULL);
	ret = pthread_create(&gpioChanAIrq_thread, NULL, gpioChanAIrq, NULL);
	ret = pthread_create(&gpioChanBIrq_thread, NULL, gpioChanBIrq, NULL);

    return ret;
}


/*  函数功能：双系心跳信号功能开启。
 *  输入参数：无。
 *  输出参数：无。
 *  返回值    ：无。
 *  使用注意：板级初始化之后调用一次该函数启动功能。
 */
void drvStartABSynSwitch(void)
{
	int i = 0;

    s_CapInfo[0U].isLocked = 0;
    s_CapInfo[1U].isLocked = 0;
    s_CapInfo[2U].isLocked = 0;

    for (i=0;i<(int)ABSynMsgType_MAX;i++)
    {
    	sSyncMsgErrInfo[i] = 0.0f;
    }

	(void)imx8_output(5,1);
    s_isABSyncStart = 1;
}


/*  函数功能：双系心跳信号功能关闭
 *  输入参数：无。
 *  输出参数：无。
 *  返回值    ：无。
 *  使用注意：
 */
void drvStopABSynSwitch(void)
{
    s_isABSyncStart = 0;
	(void)imx8_output(5,0);
}
/*  函数功能：发送双系硬通信信号。
 *  输入参数：MsgType：硬通信的信息：ABSynMsgType_0..ABSynMsgType_7
 *  输出参数：无。
 *  返回值    ：无。
 *  使用注意：倒切方案由于硬件限制，发送频率不高于500Hz,最大使用ABSynMsgType_4。
 */
void drvSetABSynMsg(ABSynMsgType MsgType)
{
    g_userSetSyncMsgType = MsgType;
    switch((uint8_t)MsgType)
   {
	   case 0:
		   s_ABSynDuty = 0;
		   break;
	   case 1://200hz
		   s_ABSynDuty = 80;
		   break;
	   case 2://300hz
		   s_ABSynDuty = 53;
		   break;
	   case 3://400hz
		   s_ABSynDuty = 40;
		   break;
	   case 4://500hz
		   s_ABSynDuty = 32;
		   break;
	   case 5://600hz
		   s_ABSynDuty = 27;
		   break;
	   case 6://700hz
		   s_ABSynDuty = 23;
		   break;
	   case 7://800hz
		   s_ABSynDuty = 20;
		   break;
	   default:
		   s_ABSynDuty =0;
		   break;
   }
}


/*  函数功能：输出PWM
 *  输入参数：无。
 *  输出参数：无。
 *  返回值    ：无。
 *  使用注意：放在定时器中断服务程序中，产生PWM
 */
static void Task_ABSyncPulse(void)
{
    static uint32_t PulseCount = 0u;
    static uint32_t  PinValue = 1u;
    uint32_t regVal = 0u;
    uint32_t syncDuty = 0u;

    if(s_isABSyncStart == 1u)
    {
        PulseCount++;
        syncDuty = s_ABSynDuty;
        if((syncDuty > 0u) && (PulseCount >= syncDuty))
        {
			PulseCount = 0;
			PinValue ^= 0x1u;
			if (0U == PinValue)
			{
				regVal = (in32(gpio_base_0 + IMX_GPIO_DR) & (uint32_t)~(1UL << 6U));
				out32(gpio_base_0 + IMX_GPIO_DR,regVal);
			}
			else
			{
				regVal = (in32(gpio_base_0 + IMX_GPIO_DR) | (uint32_t)(1UL << 6U));
				out32(gpio_base_0 + IMX_GPIO_DR, regVal);

			}
        }
    }
}




/*  函数功能：获取双系硬通信的反馈。
 *  输入参数：无。
 *  输出参数：pABSynMsgType *pMsgType,   采集到的type信息
 *  返回值    ：UINT8,
 *            0x00,正常。
 *            0x81,命令与反馈不一致
 *            0x82,指针为空
 *  使用注意：发送与采集间隔至少为40ms。
 */
uint8_t drvFeedbackkABSynMsg(ABSynMsgType *pMsgType)
{
	uint8_t ret = 0U;
    float Duty = 0.0f;
    float period = 0.0f;
    uint32_t  PulseCnt = 0u;
	if (NULL != pMsgType)
	{
		calculate(2U,&Duty,&period,&PulseCnt);
		*pMsgType = drvPWMAnalyze(Duty,period);
		if (g_userSetSyncMsgType == *pMsgType)
		{
			ret =0u;
		}
		else
		{
			ret = 0x81u;
		}
	}
	else
	{
		ret = 0x82U;
	}
	return ret;
}

/*  函数功能：查询当前各通道收到的外部脉冲个数。
 *  输入参数：无。
 *  输出参数： uint8_t index -- 通道索引：0-对方A系通道 1-对方B系通道 2-自身反馈通道
 *          uint32_t* pPulseCnt -- 外部存储变量地址
 *  返回值    ：uint8_t 0-成功   1-失败：入参错误。
 */
uint8_t drvCheckABSynPulCnt(uint8_t index,uint32_t* pPulseCnt)
{
	uint8_t ret = 0U;
	if ((index > 2U) || (NULL == pPulseCnt))
	{
		ret = 1u;
		return ret;
	}

	*pPulseCnt = s_CapInfo[index].capCount;

	return ret;
}


/*  函数功能：获取对系双通道硬通信信号。
 *  输入参数：无。
 *  输出参数：pMsgType[0]:对方A系发出的硬通信信息:ABSynMsgType_0..ABSynMsgType_15
 *         pMsgType[1]：对方B系发出的硬通信信息：ABSynMsgType_0..ABSynMsgType_15
 *         pPulseCnt[0]:收到对方A系发出的脉冲计数,如果此数为0，说明对方A系停止输出脉冲
 *         pPulseCnt[1]:收到对方B系发出的脉冲计数,如果此数为0，说明对方B系停止输出脉冲
 *  返回值    ：无。
 */
void drvGetABSynMsg(ABSynMsgType *pMsgType,uint32_t* pPulseCnt)
{
    float Duty[2] = {0.0f};
    float  Period[2] = {0.0f};

    if(( NULL != pMsgType) && (NULL != pPulseCnt))
    {
        drvGetABSyn(Duty,Period,pPulseCnt);
        pMsgType[0] = drvPWMAnalyze(Duty[0],Period[0]);
        pMsgType[1] = drvPWMAnalyze(Duty[1],Period[1]);
    }
    else
    {
        ;
    }

}


/*  函数功能：获取当前系间信号脉冲的最大误差值。
 *  输入参数：uint8_t index
 *  输出参数：无
 *  返回值    ：float -- 误差百分比。
 */
float drvGetSyncSigErr(ABSynMsgType msgType)
{
	uint8_t index = 0u;
	float ret = -1.0f;
	if (msgType < ABSynMsgType_MAX)
	{
		index = (uint8_t)msgType;
		ret = sSyncMsgErrInfo[index];
	}

	return ret;
}

/*  函数功能：获取双系硬切系信号的占空比及频率。
 *  输入参数：无。
 *  输出参数：Duty[0]:对系CPU1占空比,保留3位有效小数,如30%占空比表示为0.300
 *           Period[0]：对系CPU1频率,单位为Hz
 *           Duty[1]:对系CPU2占空比,保留3位有效小数,如30%占空比表示为0.300
 *           Period[1]：对系CPU2频率,单位为Hz
 *  返回值    ：无。
 *  使用注意：Period为0时表示错误。
 */
static void drvGetABSyn(float *Duty,float *Period,uint32_t* pPulseCnt)
{
	if ((NULL == Duty) || (NULL == Period) || (NULL == pPulseCnt))
	{
		return;
	}
    /*使用IO中断方式*/
    calculate(0U,&Duty[0],&Period[0],&pPulseCnt[0]);
    calculate(1U,&Duty[1],&Period[1],&pPulseCnt[1]);
}


/*  函数功能：PWM信号解析为双系MsgType。
 *  输入参数：Duty:采集到的PWM占空比
 *         Period：采集到的PWM频率
 *  输出参数：无。
 *  返回值    ：ABSynMsgType：双系通信的具体信息。
 *  使用注意：。
 */
static ABSynMsgType drvPWMAnalyze(float Duty,float Period)
{
    ABSynMsgType ABSynMsgTypetemp = ABSynMsgType_0;
    float syncErr = 0.0f;
    float tmp = 0.0f;
    float baseFreq = 0.0f;
    uint8_t index = 0u;

    if((Duty > 0.45f) && (Duty < 0.55f) )
    {
	   if((Period > 150.0f) && (Period < 250.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_1;
	   }
	   else if((Period > 250.0f) && (Period < 350.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_2;
	   }
	   else if((Period > 350.0f) && (Period < 450.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_3;
	   }
	   else if((Period > 450.0f) && (Period < 550.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_4;
	   }
	   else if((Period > 550.0f) && (Period < 650.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_5;
	   }
	   else if((Period > 650.0f) && (Period < 750.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_6;
	   }
	   else if((Period > 750.0f) && (Period < 850.0f))
	   {
		   ABSynMsgTypetemp = ABSynMsgType_7;
	   }
	   else
	   {
		   ABSynMsgTypetemp = ABSynMsgType_0;
	   }
   }
   else//占空比无或不正常
   {
	   ABSynMsgTypetemp = ABSynMsgType_0;
   }

   index = (uint8_t)ABSynMsgTypetemp;
   baseFreq = (float)((uint8_t)(index + 1u)) * 100.0f;
   tmp = (Period > baseFreq) ? (Period - baseFreq) : (baseFreq - Period);
   syncErr = tmp / baseFreq * 100.0f;
   tmp = sSyncMsgErrInfo[index];
   tmp = (syncErr > tmp) ? syncErr : tmp;
   sSyncMsgErrInfo[index] = tmp;

   return ABSynMsgTypetemp;
}

/*使用io中断获取对端脉冲频率*/
static void calculate(uint8_t index,float *Duty,float *Period,uint32_t* pPulseCnt)
{
	uint32_t curTimeStamp = 0u;
	uint32_t startTimeStamp = 0u;
	float tmp = 0.0f;

	if ((index > 2U) || (NULL == Duty) || (NULL == Period) || (NULL == pPulseCnt))
	{
		return;
	}

	s_ECapPause[index] = 1U;
	curTimeStamp = s_CapInfo[index].cap1CurrentTime;
	startTimeStamp = s_CapInfo[index].cap1StartTime;

	uint32_t useTime = (curTimeStamp > startTimeStamp) ? \
			(curTimeStamp - startTimeStamp) : \
			(0xFFFFFFFFU - startTimeStamp + curTimeStamp);

	tmp = (float)useTime / (float)s_CapInfo[index].capCount;
	s_CapInfo[index].fre = (32000.0f / tmp);

	*Period = s_CapInfo[index].fre;
	*Duty = 0.5f;
	*pPulseCnt = s_CapInfo[index].capCount;
	s_CapInfo[index].cap1CurrentTime = 0u;
	s_CapInfo[index].cap1StartTime = 0u;
	s_CapInfo[index].capCount = 0u;
	s_CapInfo[index].isLocked = 0u;
	s_ECapPause[index] = 0U;
}


static void pulseCount(uint8_t index)
{
	uint8_t capPause = 0u;
	uint8_t syncStart = 0u;
    if (index < 3u)
    {
    	capPause = s_ECapPause[index];
    	syncStart = s_isABSyncStart;
    	if ((0u == capPause) && (1u == syncStart))
    	{
			if(0u == s_CapInfo[index].isLocked)
			{
				s_CapInfo[index].isLocked = 1u;
				s_CapInfo[index].capCount = 0u;
				s_CapInfo[index].cap1StartTime = cnt;
			}
			s_CapInfo[index].cap1CurrentTime = cnt;
			s_CapInfo[index].capCount++;
		}
    	else
    	{
    		/*do nothing*/
    	}
    }
}


/************************************************************************/
/*
* @brief 读取phy寄存器相关维护信息
*
* 该函数通过创建套接字并发送SIOCGDRVSPEC控制命令，读取指定网络接口的PHY寄存器状态
*
* @param[in]
* 	const char* fecx 需要检查的网络接口名称（如"fec0","fec1"）
* 	uint16_t infoLen - 寄存器信息数组长度，此长度应该大于等于12
* @param[out]
*   uint16_t * Info - 寄存器信息数组存储首地址
* @return rtn 返回状态
*   - n: n为实际读取的寄存器个数
*   - -1: 链路异常或操作失败
*
*/
int drvPhyRegInfoUpdate(const char* fecx,uint16_t *Info,uint16_t infoLen)
{
    /*- 变量初始化*/
    int sockfd = -1;
    int rtn = -1;
    uint16_t n = 0;
    /*uint16_t regInfo[12u] = {0u};*/
    uint8_t regList[12] = {0u,1u,4u,5u,6u,7u,8u,9u,10u,15u,21u,31u};
    uint16_t i = 0u;

	if ((NULL == fecx) || (NULL == Info) || (0u == infoLen))
	{
		return rtn;
	}

    /*- 创建DGRAM类型套接字*/
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
	{
    	 rtn = -1;
    }
    else
    {
        /*- 配置网络接口名称*/
        (void)strncpy((char*)&phycmd.ifd.ifd_name, fecx, IFNAMSIZ);

        /*- 设置PHY寄存器访问参数*/
        phycmd.ifd.ifd_cmd = READ_PHY_REG;    /* PHY寄存器读取命令 */
        phycmd.ifd.ifd_len = sizeof(phy_access_t);
        phycmd.ifd.ifd_data = (void*)&phycmd.req;
        phycmd.req.phy_id = 7U;               /* PHY设备地址 */
        phycmd.req.phy_reg = 1U;              /* PHY状态寄存器地址 */
        phycmd.req.phy_data = 0U;          /* 初始化数据域 */

        n = ((12U <= infoLen)? 12u : infoLen);

        for(i = 0u;i < n;i++)
        {
        	 phycmd.req.phy_reg = regList[i];        /* PHY状态寄存器地址 */
        	/*- 发送驱动控制命令获取PHY状态*/
        	(void)devctl(sockfd, SIOCGDRVSPEC, &phycmd,sizeof(phycmd),NULL);
        	Info[i] = phycmd.req.phy_data;
        }
        rtn = (int)n;
        (void)close(sockfd);
    }
    /*- 返回最终检测结果*/
    return rtn;
}


#if 0
/*调试接口*/
void checkisr(void)
{
	static int ret = 0;
	printf("irq cnt 0 is %d\n",irqCnt[0]);
	printf("irq cnt 1 is %d\n",irqCnt[1]);
	printf("irq cnt 2 is %d\n",irqCnt[2]);
	printf("cur cnt  is %d\n",cnt);
}
#endif


/************************************************************************/
/*
* @brief 通过PHY寄存器检查指定网卡链路状态
*
* 该函数通过创建套接字并发送SIOCGDRVSPEC控制命令，读取指定网络接口的PHY寄存器状态，
* 根据寄存器值的特定位判断链路是否正常。
*
* @param[in] fecx 需要检查的网络接口名称（如"fec0","fec1"）
* @return rtn 返回状态
*   - 0: 链路状态正常（PHY寄存器bit2为1）
*   - -1: 链路异常或操作失败
*
* @note 函数执行流程：
*   1. 创建UDP套接字
*   2. 配置phycmd控制结构体：
*      - ifd_name: 网络接口名称
*      - ifd_cmd: 使用READ_PHY_REG命令
*      - phy_id: PHY地址7
*      - phy_reg: 寄存器地址1（状态寄存器）
*   3. 通过devctl发送控制命令
*   4. 解析phy_data寄存器值的bit2判断链路状态
*/
int phytool(const char* fecx)
{
    /*- 变量初始化*/
    int sockfd = -1;
    int rtn = -1;

	if (NULL == fecx)
	{
		return rtn;
	}

    /*- 创建DGRAM类型套接字*/
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
	{
        rtn = -1;
    }
    else
    {
        /*- 配置网络接口名称*/
        (void)strncpy((char*)&phycmd.ifd.ifd_name, fecx, IFNAMSIZ);

        /*- 设置PHY寄存器访问参数*/
        phycmd.ifd.ifd_cmd = READ_PHY_REG;    /* PHY寄存器读取命令 */
        phycmd.ifd.ifd_len = sizeof(phy_access_t);
        phycmd.ifd.ifd_data = (void*)&phycmd.req;
        phycmd.req.phy_id = 7U;               /* PHY设备地址 */
        phycmd.req.phy_reg = 1U;              /* PHY状态寄存器地址 */
        phycmd.req.phy_data = 0U;          /* 初始化数据域 */

        /*- 发送驱动控制命令获取PHY状态*/
        (void)devctl(sockfd, SIOCGDRVSPEC, &phycmd,sizeof(phycmd),NULL);

        (void)close(sockfd);

        /*- 解析状态寄存器bit2（0x04）链路状态标志*/
        if(1U == ((phycmd.req.phy_data & 0x04U)>>2U))
        {
            rtn = 0;  /* 链路正常 */
        }
        else
        {
            ; /* 保持默认失败状态 */
        }
    }
    /*- 返回最终检测结果*/
    return rtn;
}
