Files
2023-02-01 14:19:13 +08:00

401 lines
13 KiB
C

/********************************** (C) COPYRIGHT *******************************
* File Name : IAP_Task.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/05/25
* Description : IAP related functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "wchnet.h"
#include "IAP_Task.h"
__attribute__((__aligned__(4))) u8 dataDealBuf[RECE_BUF_LEN] = {0};
ethDataDeal dataDeal = { //Ring buffer parameter initialization
.readIndex = 0,
.writeIndex = 0,
.buffUsedLen = 0,
.dataBuff = dataDealBuf,
};
u32 fileDataLen = 0; //IAP file data length
u32 fileCheckSum = 0; //IAP file data checksum
u32 flashProgramLen = 0; //length of data written to backup area
iapFileHeader iapPara; //IAP file parameters
extern u8 SocketId;
/*********************************************************************
* @fn IAP_EEPROM_ERASE
*
* @brief erase Data-Flash block, minimal block is 256B
*
* @param Page_Address - the address of the page being erased.
* Length - Erased data length
*
* @return none
*/
void IAP_EEPROM_ERASE(uint32_t Page_Address, u32 Length)
{
u32 NbrOfPage, EraseCounter;
FLASH_Unlock_Fast();
NbrOfPage = Length / FLASH_PAGE_SIZE;
for (EraseCounter = 0; EraseCounter < NbrOfPage; EraseCounter++) {
FLASH_ErasePage_Fast( Page_Address + (FLASH_PAGE_SIZE * EraseCounter)); //Erase 256B
}
FLASH_Lock_Fast();
}
/*********************************************************************
* @fn IAP_EEPROM_WRITE
*
* @brief write Data-Flash data block
*
* @param StartAddr - the address of the page being written.
* Buffer - data buff
* Length - written data length
*
* @return FLASH_Status
*/
void IAP_EEPROM_WRITE( u32 StartAddr, u8 *Buffer, u32 Length )
{
u32 address = StartAddr;
u32 *p_buff = (u32 *)Buffer;
u16 pageNum = Length / FLASH_PAGE_SIZE;
u16 lastDataNum = Length % FLASH_PAGE_SIZE;
u16 i;
if(pageNum){ //write by page(256B)
FLASH_Unlock_Fast();
for(i = 0; i < pageNum; i++)
FLASH_ProgramPage_Fast((address + FLASH_PAGE_SIZE * i),(p_buff + (FLASH_PAGE_SIZE / 4) * i));
FLASH_Lock_Fast();
}
if(lastDataNum){ //write by a half word(2B)
u8 *p_buff1 = Buffer + FLASH_PAGE_SIZE * pageNum;
address = StartAddr + FLASH_PAGE_SIZE * pageNum;
FLASH_Unlock();
for(i = 0; i < lastDataNum; i += 2)
FLASH_ProgramHalfWord((address + i), *(u16 *)(p_buff1 + i));
FLASH_Lock();
}
}
/*********************************************************************
* @fn IAP_EEPROM_READ
*
* @brief read Data-Flash data block
*
* @param StartAddr - the address of the page being read.
* Buffer - data buff
* Length - read data length
*
* @return none
*/
void IAP_EEPROM_READ( u32 StartAddr, u8 *Buffer, u32 Length )
{
u32 address = StartAddr;
u32 *p_buff = (u32 *)Buffer;
while(address < (StartAddr + Length))
{
*p_buff = (*(u32 *)address);
address += 4;
p_buff++;
}
}
/*********************************************************************
* @fn IAP_EEPROM_ERASE_44k
*
* @brief erase Data-Flash block, minimal block is 4KB.
* This function is used to erase USER and BACKUP area.
*
* @param Page_Address - the address of the page being erased.
*
* @return none
*/
void IAP_EEPROM_ERASE_44k(u32 StartAddr)
{
u8 i = 0;
FLASH_Unlock();
for(i = 0; i < USER_IMAGE_MAX_SIZE / FLASH_BLOCK_SIZE; i++)
FLASH_ErasePage(StartAddr + i * FLASH_BLOCK_SIZE);
FLASH_Lock();
}
/*********************************************************************
* @fn IAPParaInit
*
* @brief IAP parameters initialize
*
* @return none
*/
void IAPParaInit(void)
{
iapPara.iapFileCheckSum = 0;
memset(iapPara.iapFileFlag, 0,sizeof(iapPara.iapFileFlag));
iapPara.iapFileLen = 0;
dataDeal.buffUsedLen = 0;
dataDeal.dataBuff = dataDealBuf;
dataDeal.readIndex = 0;
dataDeal.writeIndex = 0;
fileDataLen = 0;
fileCheckSum = 0;
flashProgramLen = 0;
}
/*********************************************************************
* @fn IAPFileParaCheck
*
* @brief Verify upgrade file parameters.
*
* @param id - socket id.
*
* @return none
*/
void IAPFileParaCheck(u8 id)
{
u32 len;
u8 *pBuff = NULL;
len = WCHNET_SocketRecvLen(id,NULL);
if(BIN_INF_LEN <= len){ //The first 512 bytes are the bin file parameters
u8 buffIndex;
u32 recLen = BIN_INF_LEN;
pBuff = malloc(recLen);
WCHNET_SocketRecv(id,pBuff,&recLen);
memcpy(iapPara.iapFileFlag, pBuff, 8);
buffIndex = 8;
iapPara.iapFileLen |= *(pBuff + buffIndex++);
iapPara.iapFileLen |= *(pBuff + buffIndex++) << 8;
iapPara.iapFileLen |= *(pBuff + buffIndex++) << 16;
iapPara.iapFileLen |= *(pBuff + buffIndex++) << 24;
iapPara.iapFileCheckSum |= *(pBuff + buffIndex++);
iapPara.iapFileCheckSum |= *(pBuff + buffIndex++) << 8;
iapPara.iapFileCheckSum |= *(pBuff + buffIndex++) << 16;
iapPara.iapFileCheckSum |= *(pBuff + buffIndex++) << 24;
fileDataLen += recLen;
free(pBuff);
if(memcmp(iapPara.iapFileFlag, FILE_FLAG, strlen(FILE_FLAG))){
printf("The file's flag is wrong!\r\n");
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
}
}
/*Ring buffer data distribution*/
//first case
/**start******************readIndex********************writeIndex***************end**
******| writable area |*******| readable area |********| writable area |****/
//second case
/**start******************writeIndex********************readIndex***************end**
******| readable area |********| writable area |*******| readable area |****/
/*********************************************************************
* @fn receUpdatedFile
*
* @brief ETH receive data and save it to ring buff.
*
* @param id - socket id.
*
* @return none
*/
void receUpdatedFile(u8 id)
{
u32 len, remainLen, recLen;
int8_t receive_state = -1;
len = WCHNET_SocketRecvLen(id,NULL); //query length
if( dataDeal.buffUsedLen < RECE_BUF_LEN ) //Ring buffer has free space
{
if(dataDeal.readIndex <= dataDeal.writeIndex){
remainLen = RECE_BUF_LEN - dataDeal.writeIndex;
if(len <= remainLen){
recLen = len;
}
else{
recLen = remainLen;
}
receive_state = WCHNET_SocketRecv(id,&dataDeal.dataBuff[dataDeal.writeIndex],&recLen);
if(receive_state == WCHNET_ERR_SUCCESS){
dataDeal.writeIndex = (dataDeal.writeIndex + recLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen += recLen;
fileDataLen += recLen;
if(len > remainLen){
remainLen = RECE_BUF_LEN - dataDeal.buffUsedLen;
len -= recLen;
if(len <= remainLen){
remainLen = len;
}
receive_state = WCHNET_SocketRecv(id,&dataDeal.dataBuff[dataDeal.writeIndex],&remainLen);
if(receive_state == WCHNET_ERR_SUCCESS){
dataDeal.writeIndex = (dataDeal.writeIndex + remainLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen += remainLen;
fileDataLen += remainLen;
}
}
}
}
else{
remainLen = dataDeal.readIndex - dataDeal.writeIndex;
if(len <= remainLen){
remainLen = len;
}
receive_state = WCHNET_SocketRecv(id,&dataDeal.dataBuff[dataDeal.writeIndex],&remainLen);
if(receive_state == WCHNET_ERR_SUCCESS){
dataDeal.writeIndex = (dataDeal.writeIndex + remainLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen += remainLen;
fileDataLen += remainLen;
}
}
}
else
{
printf("ETH receive buff busy\n");
}
}
/*********************************************************************
* @fn saveUpdatedFile
*
* @brief Save the upgrade file to the backup area.
*
* @return none
*/
void saveUpdatedFile(void)
{
u8 *pBuff = NULL, pageCnt = 0;
u16 writableDataLen = 0, tempLen = 0;
u32 remainLen = 0;
if(dataDeal.buffUsedLen){
pageCnt = dataDeal.buffUsedLen / FLASH_PAGE_SIZE; // Calculate the number of data pages
if(pageCnt){
writableDataLen = pageCnt * FLASH_PAGE_SIZE; //at least one page
}
else if(iapPara.iapFileLen == fileDataLen){ //Extract data that is less than one page at the end of the file
writableDataLen = dataDeal.buffUsedLen;
}
else return;
pBuff = malloc(writableDataLen);
if(dataDeal.writeIndex <= dataDeal.readIndex){
remainLen = RECE_BUF_LEN - dataDeal.readIndex;
if(writableDataLen <= remainLen){
tempLen = writableDataLen;
}
else{
tempLen = remainLen;
}
memcpy(pBuff, &dataDeal.dataBuff[dataDeal.readIndex], tempLen);
dataDeal.readIndex = (dataDeal.readIndex + tempLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen -= tempLen;
if(remainLen < writableDataLen){
remainLen = writableDataLen - tempLen;
memcpy((pBuff + tempLen), &dataDeal.dataBuff[dataDeal.readIndex], remainLen);
dataDeal.readIndex = (dataDeal.readIndex + remainLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen -= remainLen;
}
IAP_EEPROM_WRITE((BACKUP_IMAGE_START_ADD + flashProgramLen), pBuff, writableDataLen );
}
else{
memcpy(pBuff, &dataDeal.dataBuff[dataDeal.readIndex], writableDataLen);
dataDeal.readIndex = (dataDeal.readIndex + writableDataLen)%RECE_BUF_LEN;
dataDeal.buffUsedLen -= writableDataLen;
IAP_EEPROM_WRITE((BACKUP_IMAGE_START_ADD + flashProgramLen), pBuff, writableDataLen );
}
flashProgramLen += writableDataLen;
for(u16 i = 0; i < (writableDataLen / 4); i++) //Calculate checksum
fileCheckSum += *((u32 *)pBuff + i);
/*Calculate the checksum of data less than 4 bytes at the end of the file*/
if((writableDataLen % 4) != 0){
u8 lastDataLen = writableDataLen % 4;
u8 temBuff[4] = {0};
memcpy(temBuff, (pBuff + writableDataLen - lastDataLen), lastDataLen);
fileCheckSum += *(u32 *)temBuff;
}
free(pBuff);
/*After the data is saved, compare the checksum. If the checksum is correct,
* update the upgrade flag. Disconnect if checksum error.*/
if(iapPara.iapFileLen == (flashProgramLen + BIN_INF_LEN)){
if(fileCheckSum == iapPara.iapFileCheckSum){
printf("FileCheckSum is right!\r\n");
u32 updateFlag = IMAGE_FLAG_UPDATE;
IAP_EEPROM_ERASE(UPDATA_FLAG_STORAGE_ADD, FLASH_PAGE_SIZE);
IAP_EEPROM_WRITE(UPDATA_FLAG_STORAGE_ADD, (u8 *)&updateFlag, 4);
WCHNET_SocketClose(SocketId, TCP_CLOSE_RST);
NVIC_SystemReset();
}
else{
printf("FileCheckSum is wrong!\r\n");
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
}
}
}
/*********************************************************************
* @fn IAPCopyFlashDeal
*
* @brief Move the BACKUP area code to the USER area.
* Write in 2KB units.
*
* @return upgrade status
*/
u8 IAPCopyFlashDeal(void)
{
u16 i,j;
u32 *pBuf;
u32 flashAddr;
u32 updataBuff[READ_DATA_LEN / 4];
pBuf = updataBuff;
IAP_EEPROM_ERASE_44k(USER_IMAGE_START_ADD);
for(i = 0; i < (BACKUP_IMAGE_MAX_SIZE / READ_DATA_LEN); i++)
{
flashAddr = USER_IMAGE_START_ADD + i * READ_DATA_LEN;
IAP_EEPROM_READ((flashAddr + USER_IMAGE_MAX_SIZE), (u8 *)pBuf, READ_DATA_LEN);
IAP_EEPROM_WRITE(flashAddr, (u8 *)pBuf, READ_DATA_LEN);
//Check data
for(j = 0; j < (READ_DATA_LEN / 4); j++){
if(pBuf[j] != *(u32 *)(flashAddr + 4 * j))
return NoREADY;
}
}
IAP_EEPROM_ERASE_44k(BACKUP_IMAGE_START_ADD);
return READY;
}