ZDBMS/code_bootloader/IapIsp.c

789 lines
21 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************************************
Copyright (C), Sinowealth Electronic. Ltd.
Author: Sino
Version: V0.0
Date: 2020/04/26
History:
V2.0 2020/04/26 Preliminary
********************************************************************************/
#include "MCURegister.h"
#include "C51_TYPE.H"
#include "Flash.h"
#include "IapIsp.h"
BOOL bIapIspFlg; //0表示当前执行IAP操作1表示当前执行ISP操作
BOOL bHandsheakOkFlg;
BOOL bUartSndOverFlg;
U16 uiUartRcvChkSum;
U8 ucUartErrCode;
U8 ucUartBufPT;
U32 ulIapDataPtr;
U32 ulIapChksum;
U32 ulIapRecDataLen;
U8 ucIapIndexBk;
U8 ucIapRestCommand;
U8 xdata ucUartBuf[150];
U8 xdata ucIapBuf[MCU_CODE_SECTOR_SIZE];
extern void UARTInit(void);
/*************************************************************************************************
* 函数名: UartSendAck
* 参 数: 无
* 返回值: 无
* 描 述: 当Slave接收完数据并处理完成后开始返回数据
*************************************************************************************************/
void UartSendAck(void)
{
U8 i, DataBak;
U16 CheckSum = 0;
ucUartBuf[LENGTH] = 0x00;
ucUartBuf[COMMAND] = 0x0B;
DataBak = ucUartBuf[SOURCE]; //交换源ID和目标ID
ucUartBuf[SOURCE] = ucUartBuf[TARGET];
ucUartBuf[TARGET] = DataBak;
for(i=2; i<(ucUartBuf[LENGTH]+7); i++)
{
CheckSum += ucUartBuf[i];
}
ucUartBuf[7+ucUartBuf[LENGTH]] = (U8)CheckSum;
ucUartBuf[8+ucUartBuf[LENGTH]] = (U8)(CheckSum>>8);
bUartSndOverFlg = 0;
UartTxEn(ucUartBuf[ucUartBufPT]);
}
/*************************************************************************************************
* 函数名: IapHandShake
* 参 数: 无
* 返回值: 无
* 描 述: 握手协议进入IAP或者ISP烧写流程
bIapIspFlg: 0--IAP操作1--ISP操作
*************************************************************************************************/
void IapHandShake(void)
{
ucUartBuf[INDEXES] = 0;
if(ucUartBuf[DATA]=='I' && ucUartBuf[DATA+1]=='A' && ucUartBuf[DATA+2]=='P')
{
bIapIspFlg = IAP_MODE;
bHandsheakOkFlg = 1;
}
else if(ucUartBuf[DATA]=='I' && ucUartBuf[DATA+1]=='S' && ucUartBuf[DATA+2]=='P')
{
bIapIspFlg = ISP_MODE;
bHandsheakOkFlg = 1;
}
else
{
ucUartBuf[INDEXES] = IAPERROR_HANDSHAKE; //握手失败
bHandsheakOkFlg = 0;
}
}
/*************************************************************************************************
* 函数名: IapBeginAck
* 参 数: 无
* 返回值: 无
* 描 述: IAP或ISP开始操作擦除CODE的备份区30K
*************************************************************************************************/
void IapBeginAck(void)
{
U8 i, SectorNum, McuFlashType;
U32 McuFlashAddr;
ulIapDataPtr = 0;
ulIapChksum = 0;
ulIapRecDataLen = 0;
ulIapRecDataLen = ((U32)ucUartBuf[DATA+3]<<24) //数据长度
| ((U32)ucUartBuf[DATA+2]<<16)
| ((U32)ucUartBuf[DATA+1]<<8)
| (U32)ucUartBuf[DATA];
if(!bHandsheakOkFlg)
{
ucUartBuf[INDEXES] = IAPERROR_HANDSHAKE; //握手失败
}
if((ulIapRecDataLen > IAP_BK_CODE_SIZE) && (bIapIspFlg == IAP_MODE))
{
ucUartBuf[INDEXES] = IAPERROR_SIZE; //如果数据长度不等于IAP和ISP长度则默认为长度异常
}
else if((ulIapRecDataLen > ISP_CODE_SIZE) && (bIapIspFlg == ISP_MODE))
{
ucUartBuf[INDEXES] = IAPERROR_SIZE; //如果数据长度不等于IAP和ISP长度则默认为长度异常
}
else
{
ucUartBuf[INDEXES] = 0; //先预设回复成功
ucIapIndexBk = 0;
//1. 如果当前操作是ISP则先擦除BOOT区的标志然后在BOOT_FLG_ISP_ADD中写ISP_FLG标志0xA5
ucMcuFlashWrValid = 0x55; //设置MCU Code区可操作标志防止误写
McuFlashEraseSector(BOOT_FLG_START_ADDR, MCU_TYPE_CODE);
if(McuFlashBlankCheck(BOOT_FLG_START_ADDR, MCU_TYPE_CODE)) //擦除结束后,需要查空
{
if(bIapIspFlg == ISP_MODE)
{
McuFlashWrOneByte(BOOT_FLG_ISP_ADDR, ISP_FLG, MCU_TYPE_CODE);
if(McuFlashRdOneByte(BOOT_FLG_ISP_ADDR, MCU_TYPE_CODE) != ISP_FLG)
{
ucUartBuf[INDEXES] = IAPERROR_WR; //Write失败
}
}
}
else
{
ucUartBuf[INDEXES] = IAPERROR_ERASE; //Erase失败
}
ucMcuFlashWrValid = 0;
//2. 不管是IAP还是ISP都先擦除程序的所有Sector如果是ISP则还需要擦除EEPROM区
if(ucUartBuf[INDEXES] == 0) //检查ucUartBuf[INDEXES]
{
SectorNum = ulIapRecDataLen/MCU_CODE_SECTOR_SIZE;
for(i=0; i<SectorNum; i++) //先擦除CODE备份区的Sector
{
McuFlashType = MCU_TYPE_CODE; //先默认擦除flash
if(bIapIspFlg == ISP_MODE)
{
McuFlashAddr = ISP_CODE_START_ADDR; //ISP起始地址
}
else
{
McuFlashAddr = IAP_BK_CODE_START_ADDR; //IAP起始地址
}
McuFlashAddr += (U16)i*512; //确定被擦除页起始地址
if(bIapIspFlg == ISP_MODE) //ISP模式下直接擦除EEPROM
{
if(i>=(SectorNum-APP_PARA_SIZE/MCU_CODE_SECTOR_SIZE)) //EEPROM按sector擦除
{
McuFlashType = MCU_TYPE_E2P;
McuFlashAddr = (U16)(i+APP_PARA_SIZE/MCU_CODE_SECTOR_SIZE-SectorNum)*512;
}
}
ucMcuFlashWrValid = 0x55; //设置MCU Code区可操作标志防止误写
McuFlashEraseSector(McuFlashAddr, McuFlashType);
if(!McuFlashBlankCheck(McuFlashAddr, McuFlashType)) //擦除结束后,需要查空
{
ucUartBuf[INDEXES] = IAPERROR_ERASE; //Erase失败
}
ucMcuFlashWrValid = 0;
}
}
else
{
ucUartBuf[INDEXES] = IAPERROR_INDEX;
}
}
}
/*************************************************************************************************
* 函数名: IapWrSector
* 参 数: 无
* 返回值: 无
* 描 述: 写入1个Sector数据
*************************************************************************************************/
BOOL IapWrSector(void)
{
BOOL Result = 1;
U16 i;
U32 McuFlashAddr;
U8 McuFlashType;
for(i=0; i<MCU_CODE_SECTOR_SIZE; i++) //连续写1个sector
{
McuFlashType = MCU_TYPE_CODE;
if(bIapIspFlg == ISP_MODE) //ISP
{
McuFlashAddr = ISP_CODE_START_ADDR + ulIapDataPtr;
if(McuFlashAddr >= (ulIapRecDataLen+BOOT_CODE_SIZE-APP_PARA_SIZE))
{
McuFlashAddr = McuFlashAddr - (ulIapRecDataLen+BOOT_CODE_SIZE-APP_PARA_SIZE);
McuFlashType = MCU_TYPE_E2P; //ISP更新EEPROM区
}
}
else
{
McuFlashAddr = IAP_BK_CODE_START_ADDR + ulIapDataPtr;
}
McuFlashWrOneByte(McuFlashAddr, ucIapBuf[i], McuFlashType);
if(ucIapBuf[i] != McuFlashRdOneByte(McuFlashAddr, McuFlashType))
{
Result = 0;
break;
}
ulIapDataPtr++;
}
return Result;
}
/*************************************************************************************************
* 函数名: IapReceiveData
* 参 数: 无
* 返回值: 无
* 描 述: 接收数据同时将数据写入的MCU CODE区
*************************************************************************************************/
void IapReceiveData(void)
{
U16 i;
U8 j;
U32 McuFlashAddr;
U8 McuFlashType;
bHandsheakOkFlg = 0;
if( ((ucUartBuf[INDEXES]<ucIapIndexBk) || (ucUartBuf[INDEXES]>(ucIapIndexBk+4))) && (ucUartBuf[INDEXES] != 0) ) //yangweilei
{
ucUartBuf[INDEXES] = IAPERROR_INDEX; //数据索引错误,首先判断是否连续,其次判断是否超出范围
}
else
{
ucIapIndexBk = ucUartBuf[INDEXES];
ucUartBuf[INDEXES] = 0;
if(ucUartBuf[LENGTH] == 0)
{
ulIapDataPtr += 512; //如果传递的长度为0表示当前128个字节为0指针加但不写(增加150mS/1K)
}
else
{
j = ucIapIndexBk % 4; //目前暂定sector长度为512bytes每次传输128bytes所以定义为4
for(i=0; i<ucUartBuf[LENGTH]; i++)
{
ucIapBuf[i+(U16)j*ucUartBuf[LENGTH]] = ucUartBuf[DATA+i];
}
if(j == 3) //连续接收满1个sector才进行写入操作
{
ucMcuFlashWrValid = 0x55; //设置MCU Code区可操作标志防止误写
if(!IapWrSector()) //第一次写sector错误则擦除后再写一次
{
if(ulIapDataPtr >= MCU_CODE_SECTOR_SIZE)
{
ulIapDataPtr -= MCU_CODE_SECTOR_SIZE; //指针返回到该Sector起始
}
else
{
ulIapDataPtr = 0;
}
McuFlashType = MCU_TYPE_CODE; //默认是CODE区
if(bIapIspFlg == ISP_MODE) //ISP
{
McuFlashAddr = ISP_CODE_START_ADDR + ulIapDataPtr;
if(McuFlashAddr >= (ulIapRecDataLen+BOOT_CODE_SIZE-APP_PARA_SIZE))
{
McuFlashAddr = McuFlashAddr - (ulIapRecDataLen+BOOT_CODE_SIZE-APP_PARA_SIZE);
McuFlashType = MCU_TYPE_E2P; //ISP更新EEPROM区
}
}
else
{
McuFlashAddr = IAP_BK_CODE_START_ADDR + ulIapDataPtr;
}
ucMcuFlashWrValid = 0x55;
McuFlashEraseSector(McuFlashAddr, McuFlashType);
if(McuFlashBlankCheck(McuFlashAddr, McuFlashType)) //擦除结束后,需要查空
{
if(!IapWrSector()) //如果连续写两次错误,则返回给上位机异常
{
ucUartBuf[INDEXES] = IAPERROR_WR; //写入错误
}
else
{
goto UpdateChksum;
}
}
else
{
ucUartBuf[INDEXES] = IAPERROR_ERASE; //擦除错误
}
}
else //512Bytes写入正确才更新checksum值
{
UpdateChksum:
for(j=0; j<MCU_CODE_SECTOR_SIZE/4; j++) //计算checksum需要按照32bit尽量兼容STM32
{
ulIapChksum += (((U32)ucIapBuf[j*4+3]<<24)
| ((U32)ucIapBuf[j*4+2]<<16)
| ((U32)ucIapBuf[j*4+1]<<8)
| ((U32)ucIapBuf[j*4+0]));
}
}
ucMcuFlashWrValid = 0;
}
}
}
}
/*************************************************************************************************
* 函数名: IapRDataVerify
* 参 数: 无
* 返回值: 无
* 描 述: 验证CheckSum是否正确
*************************************************************************************************/
void IapRDataVerify(void)
{
U32 CheckSum = 0;
CheckSum = ((U32)ucUartBuf[DATA+3]<<24) //获取上位机下发的校验和
| ((U32)ucUartBuf[DATA+2]<<16)
| ((U32)ucUartBuf[DATA+1]<<8)
| ((U32)ucUartBuf[DATA+0]);
if(ulIapChksum != CheckSum) //数据校验失败
{
ucUartBuf[INDEXES] = IAPERROR_CRC;
}
else
{
ucUartBuf[INDEXES] = 0; //数据校验成功
}
}
/*************************************************************************************************
* 函数名: IapCmdReset
* 参 数: 无
* 返回值: 无
* 描 述: 当IAP和ISP正常Program结束之后上位机发送复位指令程序会跳转到0x0000地址
ISP程序会擦除BOOT区的标志区ISP结束
IAP程序会擦除BOOT区的标志区同时将标志区的最后一个字节写0x5AAPP会自动升级
*************************************************************************************************/
void IapCmdReset(void)
{
ucUartBuf[INDEXES] = 0;
ucIapRestCommand = IAP_CMD_RESET;
ucMcuFlashWrValid = 0x55; //设置MCU Code区可操作标志防止误写
McuFlashEraseSector(BOOT_FLG_START_ADDR, MCU_TYPE_CODE);
if(McuFlashBlankCheck(BOOT_FLG_START_ADDR, MCU_TYPE_CODE)) //擦除结束后,需要查空
{
if(bIapIspFlg == IAP_MODE) //IAP升级结束后需要将BOOT区的标志区最后一个字节写0x5A
{
McuFlashWrOneByte(BOOT_FLG_IAP_ADDR, IAP_FLG, MCU_TYPE_CODE);
if(McuFlashRdOneByte(BOOT_FLG_IAP_ADDR, MCU_TYPE_CODE) != IAP_FLG)
{
ucUartBuf[INDEXES] = IAPERROR_WR; //Write失败
ucIapRestCommand = 0;
}
}
}
else
{
ucUartBuf[INDEXES] = IAPERROR_ERASE; //擦除失败
ucIapRestCommand = 0;
}
ucMcuFlashWrValid = 0;
}
/*************************************************************************************************
* 函数名: UartCmdProcess
* 参 数: 无
* 返回值: 无
* 描 述: 处理IAP和ISP的四条命令
*************************************************************************************************/
void UartCmdProcess(void)
{
ucUartBufPT = 0;
if(uiUartRcvChkSum != ((ucUartBuf[ucUartBuf[LENGTH]+8]<<8) + ucUartBuf[ucUartBuf[LENGTH]+7]))
{
ucUartErrCode |= IAPERROR_CHECKSUM;
}
if(ucUartErrCode != 0) //如果有错误代码则不执行命令处理
{
ucUartBuf[INDEXES] = ucUartErrCode;
}
else
{
if(ucUartBuf[COMMAND] == IAP_CMD_HANDSHAKE) //IAP和ISP握手协议上位机连续发两次
{
IapHandShake();
}
else if(ucUartBuf[COMMAND] == IAP_CMD_BEGIN) //开始IAP或ISP并将CODE区/EEP区全部擦除
{
IapBeginAck();
}
else if(ucUartBuf[COMMAND] == IAP_CMD_TRANS) //接收数据、写入、校验
{
IapReceiveData();
}
else if(ucUartBuf[COMMAND] == IAP_CMD_VERIFY) //
{
IapRDataVerify();
}
else if(ucUartBuf[COMMAND] == IAP_CMD_RESET)
{
IapCmdReset();
}
}
UartSendAck();
}
/*************************************************************************************************
* 函数名: BootIapIsp
* 参 数: 无
* 返回值: 无
* 描 述: IAP和ISP函数处理
*************************************************************************************************/
void BootIapIsp(void)
{
ulIapDataPtr = 0;
ulIapChksum = 0;
ucIapRestCommand = 0;
UARTInit();
while(1)
{
#if ((UART_DEFINE >= 1)&&(UART_DEFINE<= 30))
{
if(RI)
{
//BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
ucUartBuf[ucUartBufPT] = SBUF;
ucUartBufPT++;
if(ucUartBufPT >= 140) //该指针不会超过140
{
ucUartBufPT = 0;
}
if(ucUartBufPT == 1)
{
if(ucUartBuf[HEARD1] != 0x5A) //检查帧头是否Wie0x5AA5
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == 2)
{
if(ucUartBuf[HEARD2] != 0xA5)
{
ucUartBufPT = 0;
}
else
{
uiUartRcvChkSum = 0; //帧头判断正确
ucUartErrCode = 0;
}
}
else
{
if(ucUartBufPT < (ucUartBuf[LENGTH]+9))
{
if(ucUartBufPT <= (ucUartBuf[LENGTH]+7))
{
uiUartRcvChkSum += ucUartBuf[ucUartBufPT-1];
}
if(ucUartBufPT == (TARGET+1)) //检查ID
{
if(ucUartBuf[TARGET] != IAP_BMSID)
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == (COMMAND+1)) //检测COMMAND
{
if((ucUartBuf[COMMAND] != IAP_CMD_HANDSHAKE)
&& (ucUartBuf[COMMAND] != IAP_CMD_BEGIN)
&& (ucUartBuf[COMMAND] != IAP_CMD_TRANS)
&& (ucUartBuf[COMMAND] != IAP_CMD_VERIFY)
&& (ucUartBuf[COMMAND] != IAP_CMD_RESET))
{
ucUartErrCode |= IAPERROR_CMD;
}
}
}
else
{
BootMcuWdtClear();
UartCmdProcess();
}
}
RI = 0;
}
if(TI)
{
BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
if(ucUartBufPT >= (ucUartBuf[LENGTH]+8))
{
UartRxEn(); //Allow UART receive data
ucUartBufPT = 0;
ucUartBuf[0] = 0;
ucUartBuf[1] = 0;
ucUartBuf[2] = 0;
bUartSndOverFlg = 1;
}
else
{
ucUartBufPT++;
UartTxEn(ucUartBuf[ucUartBufPT]);
}
TI = 0;
}
if(ucIapRestCommand == IAP_CMD_RESET)
{
BootMcuWdtClear();
if(bUartSndOverFlg) //Reset帧回复结束
{
bUartSndOverFlg = 0;
ucIapRestCommand = 0;
((void(code*)(void))0x0000)();
}
}
}
#elif ((UART_DEFINE >= 31)&&(UART_DEFINE<= 60))
{
INSCON = 0x40;
if(RI1)
{
//BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
ucUartBuf[ucUartBufPT] = SBUF1;
INSCON = 0x00;
ucUartBufPT++;
if(ucUartBufPT >= 140) //该指针不会超过140
{
ucUartBufPT = 0;
}
if(ucUartBufPT == 1)
{
if(ucUartBuf[HEARD1] != 0x5A) //检查帧头是否Wie0x5AA5
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == 2)
{
if(ucUartBuf[HEARD2] != 0xA5)
{
ucUartBufPT = 0;
}
else
{
uiUartRcvChkSum = 0; //帧头判断正确
ucUartErrCode = 0;
}
}
else
{
if(ucUartBufPT < (ucUartBuf[LENGTH]+9))
{
if(ucUartBufPT <= (ucUartBuf[LENGTH]+7))
{
uiUartRcvChkSum += ucUartBuf[ucUartBufPT-1];
}
if(ucUartBufPT == (TARGET+1)) //检查ID
{
if(ucUartBuf[TARGET] != IAP_BMSID)
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == (COMMAND+1)) //检测COMMAND
{
if((ucUartBuf[COMMAND] != IAP_CMD_HANDSHAKE)
&& (ucUartBuf[COMMAND] != IAP_CMD_BEGIN)
&& (ucUartBuf[COMMAND] != IAP_CMD_TRANS)
&& (ucUartBuf[COMMAND] != IAP_CMD_VERIFY)
&& (ucUartBuf[COMMAND] != IAP_CMD_RESET))
{
ucUartErrCode |= IAPERROR_CMD;
}
}
}
else
{
BootMcuWdtClear();
UartCmdProcess();
}
}
INSCON = 0x40;
RI1 = 0;
INSCON = 0x00;
}
INSCON = 0x40;
if(TI1)
{
INSCON = 0x00;
BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
if(ucUartBufPT >= (ucUartBuf[LENGTH]+8))
{
UartRxEn(); //Allow UART receive data
ucUartBufPT = 0;
ucUartBuf[0] = 0;
ucUartBuf[1] = 0;
ucUartBuf[2] = 0;
bUartSndOverFlg = 1;
}
else
{
ucUartBufPT++;
UartTxEn(ucUartBuf[ucUartBufPT]);
}
INSCON = 0x40;
TI1 = 0;
INSCON = 0x00;
}
if(ucIapRestCommand == IAP_CMD_RESET)
{
BootMcuWdtClear();
if(bUartSndOverFlg) //Reset帧回复结束
{
bUartSndOverFlg = 0;
ucIapRestCommand = 0;
((void(code*)(void))0x0000)();
}
}
}
#elif ( UART_DEFINE == 61)
{
INSCON = 0x40;
if(RI2)
{
//BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
ucUartBuf[ucUartBufPT] = SBUF2;
INSCON = 0x00;
ucUartBufPT++;
if(ucUartBufPT >= 140) //该指针不会超过140
{
ucUartBufPT = 0;
}
if(ucUartBufPT == 1)
{
if(ucUartBuf[HEARD1] != 0x5A) //检查帧头是否Wie0x5AA5
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == 2)
{
if(ucUartBuf[HEARD2] != 0xA5)
{
ucUartBufPT = 0;
}
else
{
uiUartRcvChkSum = 0; //帧头判断正确
ucUartErrCode = 0;
}
}
else
{
if(ucUartBufPT < (ucUartBuf[LENGTH]+9))
{
if(ucUartBufPT <= (ucUartBuf[LENGTH]+7))
{
uiUartRcvChkSum += ucUartBuf[ucUartBufPT-1];
}
if(ucUartBufPT == (TARGET+1)) //检查ID
{
if(ucUartBuf[TARGET] != IAP_BMSID)
{
ucUartBufPT = 0;
}
}
else if(ucUartBufPT == (COMMAND+1)) //检测COMMAND
{
if((ucUartBuf[COMMAND] != IAP_CMD_HANDSHAKE)
&& (ucUartBuf[COMMAND] != IAP_CMD_BEGIN)
&& (ucUartBuf[COMMAND] != IAP_CMD_TRANS)
&& (ucUartBuf[COMMAND] != IAP_CMD_VERIFY)
&& (ucUartBuf[COMMAND] != IAP_CMD_RESET))
{
ucUartErrCode |= IAPERROR_CMD;
}
}
}
else
{
BootMcuWdtClear();
UartCmdProcess();
}
}
INSCON = 0x40;
RI2 = 0;
INSCON = 0x00;
}
INSCON = 0x40;
if(TI2)
{
INSCON = 0x00;
BootMcuWdtClear(); //在该程序循环中未接收到UART通讯则判定通讯异常触发看门狗
if(ucUartBufPT >= (ucUartBuf[LENGTH]+8))
{
UartRxEn(); //Allow UART receive data
ucUartBufPT = 0;
ucUartBuf[0] = 0;
ucUartBuf[1] = 0;
ucUartBuf[2] = 0;
bUartSndOverFlg = 1;
}
else
{
ucUartBufPT++;
UartTxEn(ucUartBuf[ucUartBufPT]);
}
INSCON = 0x40;
TI2 = 0;
INSCON = 0x00;
}
if(ucIapRestCommand == IAP_CMD_RESET)
{
BootMcuWdtClear();
if(bUartSndOverFlg) //Reset帧回复结束
{
bUartSndOverFlg = 0;
ucIapRestCommand = 0;
((void(code*)(void))0x0000)();
}
}
}
#endif
}
}