//=====================================================================
//文件名称：isr.c
//功能概要： 中断底层驱动构件源文件
//版权所有：苏州大学嵌入式系统与物联网研究所(sumcu.suda.edu.cn)
//更新记录：2017-04-07   V1.0
//=====================================================================
#include "includes.h"


//内部函数声明
uint_8 CreateFrame(uint_8 Data,uint_8 * buffer,uint_16 *len);

//========================中断函数服务例程==================================
//=====================================================================
//函数名称：SVC_Handler
//参数说明：无
//函数返回：无
//功能概要：触发SVC中断，调用getBiosUserFun函数获取用户接口函数表首地址
//=====================================================================
void SVC_Handler(void)
{
	__asm("PUSH {LR};");//保存现场
	__asm("BL SVC_HandlerS;");//跳转SVC_HandlerS函数
	__asm("POP {PC};");//恢复现场
//	gFuncFlag=10;       //直接进入更新状态
}

//=====================================================================
//函数名称：NMI_Handler
//参数说明：无
//函数返回：无
//功能概要：非可屏蔽中断处理函数
//=====================================================================
void NMI_Handler(void)
{
	//190227-NMI（1/2）---
	static uint_8 NMI_Count=0;  //静态变量，保存进入NMI中断的次数
	static uint_64 NMI_Time=0;  //静态变量，保存进入NMI中断的次数

	//D10-D8为引脚功能复用设置位，令其为000，为清除原有功能，再设置相应功能
	//PTA4设置为GPIO功能，防止多次进入NMI中断
	PORT_PCR_REG(PORTA_BASE_PTR,4) &= ~PORT_PCR_MUX_MASK; //D10-D8=000,
	PORT_PCR_REG(PORTA_BASE_PTR,4) |= PORT_PCR_MUX(1);    //置D10-D8=001

	if(strcmp(gcUpdateFlag,"NMI-had5") == 0)  goto NMI_Handler_exit;

	//进入NMI中断的次数+1
	NMI_Count++;                //进入NMI中断的次数+1
	//绿灯亮一下
	light_control(LIGHT_RED,LIGHT_ON);  //打开绿灯
	Delay_ms(150);
	light_control(LIGHT_RED,LIGHT_OFF); //关闭绿灯
	Delay_ms(150);
	//记录第1次进入NMI中断的时刻
	if (NMI_Count==1)
	{
		NMI_Time=sysTimeGet();
		memcpy(gcUpdateFlag,"NMI-NO-5\0",9);  //清1分钟内有5次以上NMI中断标志
	}
	//若一分钟内没有按5次，清除（防止干扰性NMI中断）
	if ((NMI_Count<=5) && ((sysTimeGet()-NMI_Time)>60)) NMI_Count=0;
	//如果60s内连续5次以上进入NMI中断，则复位并停留在BIOS运行
	if((NMI_Count>5)&&((sysTimeGet()-NMI_Time)<=60))
	{
		//置1分钟内有5次以上NMI中断标志
		NMI_Count=0;
		memcpy(gcUpdateFlag,"NMI-had5\0",9);
		NVIC_SystemReset();   //系统复位
	}
NMI_Handler_exit:
    __asm ("NOP");
    //PTA4设置为NMI，可再次进入NMI中断
    PORT_PCR_REG(PORTA_BASE_PTR,4) &= ~PORT_PCR_MUX_MASK;//置D10-D8=000
    PORT_PCR_REG(PORTA_BASE_PTR,4) |= PORT_PCR_MUX(7);//置D10-D8=111
}

//======================================================================
//函数名称：SysTick_Handler
//参数说明：无
//函数返回：无
//功能概要：SysTick中断服务程序，每500ms执行一次
//======================================================================
void SysTick_Handler(void)
{
	uart_enable_re_int(UART_1);  //使能UARTC模块中断
	wdog_feed();                 //喂狗
	//（1）记录系统时间
	gCount++;      //500计数单元+1
	if(gCount>=2)
	{   gCount=0;  //500计数单元清0
	gTime++;   //秒单元+1
	}
	(WDTimeCount)++;//看门狗时间计数值+1
	//（2）如果计数值大于240,即120S,则将变量置0,重新计数
	if((WDTimeCount)>=240||(WDResetCount)>3)
	{
		WDTimeCount=0;
		WDResetCount=0;
	}
	//（3）在首次按键复位发生了以后，进行时间计数值+1操作
	if((PINResetCount)>=1)
	{
		(PINTimeCount)++;//按键复位时间计数值+1
		//（3.1）如果计时累计超过60S，将复位计数值和时间计数值重置
		if((PINTimeCount)>=120)
		{
			//（3.1.1）将按键复位次数计数值与按键复位时间计数值重置
			PINTimeCount=0;
			PINResetCount=0;
		}
	}

}

//======================================================================
//函数名称：UART1_IRQHandler
//参数说明：无
//函数返回：无
//功能概要：串口1接收中断服务程序，用于远程通信
//======================================================================
void UART1_IRQHandler(void)
{
	//（1）变量声明
	vuint_8 i,j;
	uint_8 uflag;  //更新接收标志
	uint_8 flag,ch;
	uint_8 buf[150]; //150字节数据用于存放返回数据
	uint_16 bufLen;  //返回数据长度
	uint_8 flashBuf[SECTORSIZE];
	uint_32 address,address_s; //存放读取存储器的地址

	DISABLE_INTERRUPTS;            //关总中断

	//（2）串口1接收1个字节的数据
	ch = uart_re1 (UART_1, &flag);               //调用接收一个字节的函数，清接收中断位
	if(flag==0)  goto UART1_IRQHandler_Exit;     //若没有成功接收数据，直接退出

	//（3）调用组帧程序，对接收到的数据组帧
	gcRecvLen = emuart_recv(ch,gcRecvBuf);         //组帧程序仅当组帧完成时返回非0帧长
	if(gcRecvLen == 0) goto UART1_IRQHandler_Exit;//未组帧直接退出，直接退出

	//（4）组帧完成，开始通过有效数据首字节解析子命令，并做相应处理
	switch(gcRecvBuf[0])  //帧标识
	{
	//帧标识0-5，表示更新数据
	case 0:  //更新开始
		ueupdate_init(USERSECTOR,gUENo,SECTORSIZE);  //ueupdate初始化
	case 1:
	case 2:
	case 3:
	case 4:
	case 5:
		uflag = ueupdate_recv(gcRecvBuf,gcRecvLen);
		switch(uflag)
		{
		case 1:  //整体替换更新,跳转BIOS程序后继续执行
			memcpy(gcUpdateFlag,"uart\0",5);
			NVIC_SystemReset();
			break;
		case 4:  //丢帧
			ueupdate_checkGet(buf,&bufLen);
			emuart_sendN(bufLen,buf);  //返回丢帧信息
			break;
		case 6:  //替换更新操作成功
			gFunFlag = 0;  //代码更新完毕，转向用户代码
			break;
		case 7:  //保留更新操作成功
			NVIC_SystemReset(); //系统复位，运行新的User程序
			break;
		default:
			ueupdate_backGet(buf,&bufLen);
			emuart_sendN(bufLen,buf);  //返回信息
			break;
		}
		break;
	case 10:  //上位机串口握手
		if(strncmp((char *)(gcRecvBuf+1),"shake",5) == 0)
		{
			//返回握手帧数据，供上位机判断
			emuart_sendN(sizeof(struct shakeData),(uint_8*)&gShakeData);
		}
		break;
	case 14: //读取gFlashData数据指令
		flash_read_logic((uint_8*)(&gFlashData),127,0,sizeof(struct FlashData));
		emuart_sendN(sizeof(struct FlashData) ,(uint_8*)(&gFlashData));
		break;
	case 16:  //表示更新gFlashData数据指令
		//写入信息前，将原本保存的设备信息再读取一次，防止出错 190226hzx（1/2）--------------------
		flash_read_logic((uint_8*)(&gFlashData),127,0,sizeof(struct FlashData));
		//---------------------------------------------------------------------
		for(i=1,j=0;i<21 && gcRecvBuf[i]!=',';i++)
		{
			gFlashData.userName[j++] = gcRecvBuf[i];
		}
		while(j<20) gFlashData.userName[j++]=0; //尾部设置为0
		for(i++,j=0;i<33 && gcRecvBuf[i]!=',';i++)
		{
			gFlashData.phone[j++] = gcRecvBuf[i];
		}
		while(j<11) gFlashData.phone[j++]=0;  //尾部设置为0
		for(i++,j=0;i<49 && gcRecvBuf[i]!=',';i++)
		{
			gFlashData.serverIP[j++] = gcRecvBuf[i];
		}
		while(j<15) gFlashData.serverIP[j++]=0;  //尾部设置为0
		for(i++,j=0;i<55 && gcRecvBuf[i]!=',';i++)
		{
			gFlashData.serverPort[j++] = gcRecvBuf[i];
		}
		while(j<5) gFlashData.serverPort[j++]=0;
		gFlashData.sendFrequencySec = 0;
		for(i++;i<gcRecvLen;i++)
		{
			gFlashData.sendFrequencySec = (uint_32)(gFlashData.sendFrequencySec*10+(gcRecvBuf[i]-'0'));
		}
		flash_erase(127);
		flash_write(127,0,sizeof(struct FlashData),(uint_8*)(&gFlashData));
		NVIC_SystemReset();
		break;
	//190228-RAM---------（3/3）---------------------------
    //读绝对地址处的RAM数据（128字节）
	case 17:
		//得到地址
		address=(gcRecvBuf[1]<<24)+(gcRecvBuf[2]<<16)+(gcRecvBuf[3]<<8)+gcRecvBuf[4];
		//判断地址的合法性,并返回
		if(ram_read(&buf[1],address,128))
		{
			//地址合法，返回：命令1+读取到的数据
			buf[0]=1;
			emuart_sendN(129,buf);
		}
		else
		{
			//地址不合法，返回：命令0
			buf[0]=0;
			emuart_sendN(129,buf);
		}
		break;
	//------------------------------------------------------
	//190306-Flash---------（1/1）---------------------------HZX
	case 19:
		//求地址
		address=(gcRecvBuf[2]<<24)+(gcRecvBuf[3]<<16)+(gcRecvBuf[4]<<8)+gcRecvBuf[5];
		//写入Flash
		if(address>=(USERSECTOR*SECTORSIZE)&&address<(SECTORNUM*SECTORSIZE))
		{
			//求出要写入的起始数组位置
			address_s=address-address/SECTORSIZE*SECTORSIZE;
			//扇区读取
			flash_read_physical(flashBuf,address/SECTORSIZE*SECTORSIZE,SECTORSIZE);
			for(i=0;i<gcRecvBuf[1];i++) flashBuf[address_s+i]=gcRecvBuf[6+i];
			//扇区擦除
			flash_erase(address/SECTORSIZE); //擦除扇区
			flash_write_physical(address/SECTORSIZE*SECTORSIZE,SECTORSIZE,flashBuf);  //写入Flash
		}

		break;
	//------------------------------------------------------
	}
	gcRecvLen = 0;  //恢复接收状态
UART1_IRQHandler_Exit:
    //-------------------------------
    ENABLE_INTERRUPTS;       //开总中断
}





