⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmodemlpc23xx.c

📁 嵌入式ARM芯片LPC23XX上实现固件在线更新用的XModem协议C语言实现
💻 C
字号:

/*
*****************************************Copyright (c)**************************************************
**                               
**
**--------------文件信息--------------------------------------------------------------------------------
** 文件名称: XmodemLPC23xx.c
** 文件标识:
** 描    述: LPC23xx目标板Xmodem协议实现,用RealView 3.0+编译,必须使用ARM方式编译
**           
**
**--------------修改记录--------------------------------------------------------------------------------
**
** 当前版本: 1.0
** 作    者: 
** 完成日期: 2007年5月11日
** 修改内容:
**
** 取代版本:
** 作    者:
** 完成日期:
********************************************************************************************************
*/

#include "config.h"


//定义全局变量 
const BYTE smStartupString[]="Type 'd' download, Others run app.\n\r\0"; 
 

        
//从RS232发送一个字节 
static void UartSendByte(BYTE bChar) 
{ 

  UART1SendByte(bChar);

} 


//从RS232接收一个字节 
static DWORD UartGetByte(BYTE * pbRcvByte) 
{ 

  return UART1GetByte(pbRcvByte);

}
 
//向RS232发送一个字符串 
static void UartSendStr(BYTE *pbStr)
{

  UART1SendStr(pbStr);
    
}



/*
********************************************************************************************************
** 函数名称: WriteOnePageToFlash
** 函数功能:将EMCDCM_DFU_PAGESIZE个字节的数据写入Flash当前扇区的当前位置
** 输入参数: dwDstFlashAddr -- 将要写入的Flash地址
**           
** 输出参数: 
** 返回  值:EMCDCM_OK  --在线设备固件更新成功
**           EMCDCM_ERR --更新失败
** 全局变量:
** 调用模块: 
** 注意事项:
**
**------------------------------------------------------------------------------------------------------
** 修改记录:
** 
** 2007年5月12日,文件编写,原始版本,by
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************
*/ 
static DWORD WriteOnePageToFlash(DWORD dwDstFlashAddr) 
{
  DWORD dwRetc = EMCDCM_ERR;
   
  dwRetc = IAPWriteFlash(dwDstFlashAddr,(DWORD)gv_smFlashWriteBuff,FLASH_WRITE_BUFF_SIZE);

  return dwRetc;
}


/*
********************************************************************************************************
** 函数名称: DFUByXModem
** 函数功能:按照XModem协议更新设备固件
** 输入参数: wBytesPerPackage -- 每个数据包的字节数
** 输出参数: 
** 返回  值:EMCDCM_OK  --在线设备固件更新成功
**           EMCDCM_ERR --更新失败
** 全局变量:
** 调用模块: 
** 注意事项:
**
**------------------------------------------------------------------------------------------------------
** 修改记录:
** 
** 2007年5月12日,文件编写,原始版本,by
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************
*/
DWORD DFUByXModem(WORD wBytesPerPackage) 
{ 
  DWORD dwDstFlashAddr = 0x00000000; 

  WORD i = 0; 

  WORD wTimeCount = 0;     //超时计数器
   
  BYTE bPackageNO = 1;     //包序号
   
  WORD wBuffPosition = 0;  //存放数据缓冲区当前位置

  //DWORD dwCRC = 0;
   
  BYTE bTmpChar = 0x00;

  DWORD dwUartGetRetc = EMCDCM_ERR;

  DWORD dwRetc = EMCDCM_OK;

  UartSendStr((BYTE *)smStartupString);  //向PC机发送开始提示信息

  while(1) 
  { 
    dwUartGetRetc = UartGetByte(&bTmpChar);

    if(EMCDCM_OK == dwUartGetRetc)
    {
      if('d' == bTmpChar)
      {
        break;
      }
    }
    else
    {

    }

  }

  MyMemSet((void *)gv_smFlashWriteBuff,0xFF,FLASH_WRITE_BUFF_SIZE);

  if(EMCDCM_ERR == IAPWriteFlashPrepare(CODE_RUN_START_SECTOR, CODE_RUN_END_SECTOR))
  {
    dwRetc = EMCDCM_ERR;

    return dwRetc;
  }

       
  //每秒向PC机发送一个控制字符“C”,等待控制字〈soh〉 
  while(1)        //receive the start of Xmodem 
  { 
    bTmpChar = 0x00;
    UartGetByte(&bTmpChar);

    if(XMODEM_SOH == bTmpChar)
    {
      break;
    }
    else
    {
      if(++wTimeCount > 500)                         //wait for sometimes 
      {  
        UartSendByte(XMODEM_RECIEVING_WAIT_CHAR);    //send a "C" 
        wTimeCount = 0; 
      }
    }
  }
  

  wBuffPosition = 0;
  //开始接收数据块
  do 
  { 
    bTmpChar = 0x00;

    UartGetByte(&bTmpChar);

    if(bPackageNO == ((BYTE)bTmpChar))
    {
      bTmpChar = 0x00;

      UartGetByte(&bTmpChar);

      if(bPackageNO == ((BYTE)(~bTmpChar)))
      {
        for(i=0; i<wBytesPerPackage; i++)                //接收wPackageBytes个字节数据 
        //for(i=0; i<256; i++)
        { 
          UartGetByte((BYTE *)(gv_smFlashWriteBuff + wBuffPosition));
          wBuffPosition++;
        }

        bTmpChar = 0x00;

        UartGetByte(&bTmpChar);

        bTmpChar = 0x00;

        UartGetByte(&bTmpChar);

        //???????????????
        //if(calcrc(&data[bufferPoint-128],128) == crc)    //CRC校验验证 
        //??????????????????????  后续工作是要与上位机协调做CRC校验
        if(1)
        { 
          //UartSendByte(XMODEM_ACK);        //正确收到一个数据块
          
          //正确接收FLASH_WRITE_BUFF_SIZE个字节的数据            
          if(wBuffPosition == ((WORD)FLASH_WRITE_BUFF_SIZE)) 
          {    

            dwRetc = WriteOnePageToFlash(dwDstFlashAddr);            //收到FLASH_WRITE_BUFF_SIZE字节写入Flash中
            
            if(EMCDCM_ERR == dwRetc)
            {
              return dwRetc;
            } 
             
            MyMemSet((void *)gv_smFlashWriteBuff,0xFF,FLASH_WRITE_BUFF_SIZE);

            dwDstFlashAddr += FLASH_WRITE_BUFF_SIZE;    //Flash地址增加FLASH_WRITE_BUFF_SIZE长度个字节 

            wBuffPosition = 0; 
          }

          UartSendByte(XMODEM_ACK);        //正确收到一个数据块 
            
          bPackageNO++;                    //数据块编号加1 
        }  //end of CRC验证通过 
        else 
        { 
          UartSendByte(XMODEM_NAK);        //要求重发数据块 
        }
         
       
      }
      else //接收包序号不正确
      {
        UartSendByte(XMODEM_NAK);                //要求重发数据块
      }
    }
    else //接收包序号不正确
    {
      UartSendByte(XMODEM_NAK);                //要求重发数据块
    }

    bTmpChar = 0x00;
    UartGetByte(&bTmpChar);

    if(XMODEM_EOT == bTmpChar)
    {
      break;
    }
    else
    {
      while(XMODEM_SOH != bTmpChar)
      {
        bTmpChar = 0x00;
        UartGetByte(&bTmpChar);

        if(XMODEM_EOT == bTmpChar)
        {
          break;
        }
      }//end of 等待包传输开始

    }
     
  }
  while(bTmpChar != XMODEM_EOT);                //循环接收,直到全部发完 

    
  UartSendByte(XMODEM_ACK);                     //通知PC机全部收到 
     
  if(wBuffPosition > 0)
  {
    dwRetc = WriteOnePageToFlash(dwDstFlashAddr);                //把剩余的数据写入Flash中 
  }

  return dwRetc;
    
}
 
/*
********************************************************************************************************
** 函数名称: DevFirmwareUpdate
** 函数功能:按照XModem协议更新设备固件入口函数
** 输入参数: 
** 输出参数: 
** 返回  值:
**           
** 全局变量:
** 调用模块: 
** 注意事项:
**
**------------------------------------------------------------------------------------------------------
** 修改记录:
** 
** 2007年5月15日,文件编写,原始版本,by
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************
*/
void DevFirmwareUpdate(void)
{
  DWORD dwRetc = EMCDCM_OK;

  if(NO_BACKUP_CODE == gv_DevCfg.commonCfg.bBackupCodeFlag)
  {
    dwRetc = CopyRunToBackup();

    if(EMCDCM_OK == dwRetc)
    {
      //Log4c("DevFirmwareUpdate()","CopyRunToBackup() succeed",COMMON_C_LOG_INFO);

      gv_DevCfg.commonCfg.bBackupCodeFlag = HAS_BACKUP_CODE;

      dwRetc = SaveDevCfg();   //是否需要申请对gv_smFlashWriteBuff的控制?

      if(EMCDCM_OK == dwRetc)
      {
        //Log4c("DevFirmwareUpdate()","SaveDevCfg() succeed!",COMMON_C_LOG_INFO);
        //进入更新流程

      }
      else
      {
        Log4c("DevFirmwareUpdate()","SaveDevCfg() error!",COMMON_C_LOG_FATAL);

        //todo:通知上位机进行写配置信息失败需人工干预

      }

    }
    else
    {
      Log4c("DevFirmwareUpdate()","CopyRunToBackup() error",COMMON_C_LOG_FATAL);
      
      //todo:通知上位机备份代码时写Flash出错,需要人工干预,本次不执行更新;

      //Reset();
    }
    
  }


  dwRetc = DFUByXModem(128);
  
  if(EMCDCM_OK == dwRetc)
  {
    //修改运行标志为试运行
    gv_DevCfg.commonCfg.bRunningState = TRY_RUNNING;

    dwRetc = SaveDevCfg();  //是否需要申请对gv_smFlashWriteBuff的控制?

    if(EMCDCM_OK == dwRetc)
    {

      Reset();

    }
    else
    { 
      Log4c("DevFirmwareUpdate()","SaveDevCfg()",COMMON_C_LOG_FATAL);

      //todo:通知写配置信息失败,需人工干预

    }

  }//endof 更新成功
  else
  {
    Log4c("DevFirmwareUpdate()","DFUByXModem() error",COMMON_C_LOG_ERR);

    if(HAS_BACKUP_CODE == gv_DevCfg.commonCfg.bBackupCodeFlag)
    {
      dwRetc = CopyBackupToRun();

      if(EMCDCM_OK == dwRetc)
      {
        //system will be restarted,so it cant go to here
      }
      else
      {
        Log4c("DevFirmwareUpdate()","CopyBackupToRun() error",COMMON_C_LOG_FATAL);

        //todo:通知更新失败,将备份区代码复制到运行区出错,需人工干预

      }

    }//endof 备份区有代码
    else
    {
      Log4c("DevFirmwareUpdate()","DFUByXModem() error! but no backup code!",COMMON_C_LOG_FATAL);

      //todo:通知更新失败,需人工干预

    }

  }//endof DFUByXModem()自动更新失败
     
}

/*******************************************************************************************************
**                            End Of File
********************************************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -