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

📄 upgrade.cpp

📁 运行环境:DOS, 通过串口升级的下位程序, 需配合上位升级程序FileUpgrade运行, 可用于嵌入式DOS系统中.
💻 CPP
字号:
// Upgrade.cpp: implementation of the CUpgradeFile class.
//
//////////////////////////////////////////////////////////////////////
#include "public.h"
#include "Upgrade.h"

#include "DataPort.h"
extern CDataPort gDataPort;

#include "CrcCode.h"
extern CCrcCode  gCrcCode;

unsigned char mBuffer[10240];
extern unsigned short int	gSecondTimeout;

extern const unsigned short int  gUSecond;

extern void Teststack();
extern unsigned char gArriveAnswerTime;


CUpgradeFile::CUpgradeFile()
{

}
CUpgradeFile::~CUpgradeFile()
{
	DELETE(m_ptrSuccPackMark);
}
/////////////////////////////////////////////////////////////

void CUpgradeFile::SendErrorMessagePackage(unsigned char ErrorCode)
{
	extern unsigned short int	gIntervalTimeout;
	unsigned char SendBuffer[12]={0x0,0x07,0x01,0xB9,ErrorCode};
	cprintf("\r\n\tSend Error Code %02X ",ErrorCode);
	RuningOK();
	gDataPort.SendDataPackage(SendBuffer);
	gIntervalTimeout=18;while(gIntervalTimeout) ;
	gDataPort.SendDataPackage(SendBuffer);
	gIntervalTimeout=9;while(gIntervalTimeout) ;
}

//从数据包获得升级数据参数0=OK 1=ERROR
short CUpgradeFile::ReadUpgradeParameter(const unsigned char *ptrData)
{
	m_UnSuccFileCount=*(ptrData+0);//最后文件(标识)
	m_UprModel=*(ptrData+1);//升级模式 1=单工  2=其他
	m_lFileLen=ftonl(ptrData+2);//升级文件长度
	m_uPackageSize=ftons(ptrData+6);//升级文件每包大小
	m_uPackageCount=ftons(ptrData+8);;//升级包数。
	m_lFileCrcCode1=ftonl(ptrData+10);//升级文件最终校验码
	m_lFileCrcCode2=ftonl(ptrData+14);//升级文件最终校验码
	memcpy(m_strFileName,ptrData+18,64);//升级文件名
	m_strFileName[64]=0;	
	if(m_lFileCrcCode1!=m_lFileCrcCode2 
		|| m_uPackageSize==0
		|| m_uPackageSize%512!=0
		|| (m_lFileLen+m_uPackageSize-1)/m_uPackageSize!=m_uPackageCount
		|| strlen(m_strFileName)==0)
	{
		m_lFileLen=m_uPackageSize=m_uPackageCount=0;
		m_strFileName[0]=0;
		return 1;
	}
	return 0;
}
short CUpgradeFile::CheckDiskFreeSpace(unsigned long newFileLen)//0=OK 1=不足
{
	struct dfree free;
	getdfree(getdisk()+1, &free);//获得当前磁盘的基本信息。

	//每族字节数.每一文件按簇分配,不足一簇使用一簇
	unsigned short BytesPerCluster=free.df_bsec*free.df_sclus;
	newFileLen=(newFileLen+BytesPerCluster-1)/BytesPerCluster;//升级文件占有簇数
	if(free.df_avail<newFileLen) return 1;
	return 0;
}
/////////////////////////////////////////////////////////////
void CUpgradeFile::CreateSuccMarkFile()
{
	FILE *fp;
	cprintf("\r\n  ----Create Succ Mark File \\\\uprade!!.OK----");
	fp=fopen(constUpgradeOKFileName,"w");
	fprintf(fp,"OK");
	fclose(fp);
}
//主动发送连接信息(计算机编号)和上位通信协商,每550毫秒发送一次,等待0xB1协议或等待50秒。
short CUpgradeFile::Operate_SendB0_WaitB1()//发送B0等待连接协商
{
	extern  unsigned long GetCurComputerNo();
	static unsigned long ComputerNo=GetCurComputerNo();
	unsigned char SendBuffer[16]={0x0,0x0A,0x01,0xB0};
	*(unsigned long*)(SendBuffer+4)=ftonl(ComputerNo);

	cprintf("\r\nWait Connect.");
	int k=12;
	unsigned char ReturnCode;
	while(k)
	{
		RuningOK();
		gDataPort.SendDataPackage(SendBuffer);

		ReturnCode=gDataPort.ReceiveDataPackage(mBuffer);
		if(ReturnCode==0xB1)
		{
			cprintf("..OK. ");
			return 0;
		}
		else if(ReturnCode==0xB9)
		{
			cprintf("\r\n...Fail(Recv Stop Command).");
			return 1;
		}
		k--;
		cprintf("%u ",k);
	}
	cprintf("..Fail(Over Time). ");
	return 1;
}
//收到B1协商数据,建立文件等等。直到收到B2数据包为止。
short CUpgradeFile::Operate_SendB1_WaitB2()//发送B1等待传输数据
{
	unsigned char SendBuffer[12]={0x0,0x07,0x01,0xB1,0xF0};
	unsigned char ReturnCode;
	if(mBuffer[3]!=0xB1) return 1;

	//准备建立升级文件
	ReturnCode=Handle_0xB1();
	if(ReturnCode) {SendErrorMessagePackage(ReturnCode);return 1;}
	DELETE(m_ptrSuccPackMark);
	m_ptrSuccPackMark=new char[m_uPackageCount];
	if(m_ptrSuccPackMark==NULL){SendErrorMessagePackage(0xF1);return 1;}
	memset(m_ptrSuccPackMark,0,m_uPackageCount);
	m_SuccPackCount=0;
	m_CurRecvFileIndex=0;

	//产生wenjianOK,等待发送数据
	gDataPort.SendDataPackage(SendBuffer);//发送

	gSecondTimeout=60;
	while(gSecondTimeout)
	{
		RuningOK();
		ReturnCode=gDataPort.ReceiveDataPackage(mBuffer);
		if(ReturnCode==0xB2) return 0;
		else if(ReturnCode==0xB9)
		{
			cprintf("\r\n...Fail(Recv Stop Command).");
			return 1;
		}
		else if(ReturnCode) gDataPort.SendDataPackage(SendBuffer);//发送
		else cprintf("+");
	}
	cprintf("..Fail(Over Time). ");
	SendErrorMessagePackage(0xF1);
	return 1;
}
//收到数据包回答是否学要需要数据,直到所有数据全部收到。只能接受B2或B9。
short CUpgradeFile::Operate_SendB2_WaitTransDataEND()//发送B2等待传输数据或新协商
{
	unsigned char ReturnCode;
HAVE_NEW_DATA:
	if(mBuffer[3]==0xB2)//肯定是数据包B2协议。本来是多余,为了防止程序有错
	{
		Handle_0xB2();
		if(m_SuccPackCount==m_uPackageCount) return 0;//升级数据接受完成,等待校验。
		Handle_Answer_0xB2();
	}

	//等待新数据
	gSecondTimeout=60;
	for(;;)
	{
		RuningOK();
		if(gSecondTimeout==0)
		{
			cprintf("...Over Time.");
			SendErrorMessagePackage(0xF1);
			break;
		}
		ReturnCode=gDataPort.ReceiveDataPackage(mBuffer);
		if(ReturnCode==0xB2) goto HAVE_NEW_DATA;
		else if(ReturnCode==0xB9)
		{
			cprintf("\r\n...Fail(Recv Stop Command).");
			break;
		}
		else if(ReturnCode)
		{
			SendErrorMessagePackage(0xF2);
			break;
		}
		else cprintf("+");
	}
	return 1;
}
//数据已经接受完成,等待检验文件CRC码,等待新的协商
short CUpgradeFile::Operate_SendTransDataEND_WaitB1()//发送传输数据结束等待新文件协商
{
	unsigned char  ReturnCode;
	//回答数据包

	unsigned char SendBuffer[12]={0x0,0x0A,0x01,0xB2};
	*(unsigned short *)(SendBuffer+4)=ftons(m_SuccPackCount);//正确包数
	*(unsigned short *)(SendBuffer+6)=0L;//需重发包数

	//校验文件CRC码。
	FCLOSE(ptrFile);
	if(CheckFileCrcCode())	//文件校验码错
	{
		cprintf("\r\nFile CRC Error");
		SendErrorMessagePackage(0xF7);
		return 1;
	}

	cprintf("\r\nFile %s Uprgade OK!!!",m_strFileName);
	DELETE(m_ptrSuccPackMark);
	gDataPort.SendDataPackage(SendBuffer);
	cprintf("%4c",'O');

	//如果是最后一个文件。
	if(m_UnSuccFileCount==0)//最后一文件。
	{
		CreateSuccMarkFile();
		gSecondTimeout=20;
		while(gSecondTimeout)
		{
			ReturnCode=gDataPort.ReceiveDataPackage(mBuffer);
			if(ReturnCode==0xB9) break;
			else if(ReturnCode)
			{
				gDataPort.SendDataPackage(SendBuffer);
				cprintf("%4c",'O');
			}
			else cprintf("+");
		}
		cprintf("\r\nUprgade Succeed!!!");
		return 1;
	}
	gSecondTimeout=60;
	for(;;)
	{
		if(gSecondTimeout==0)
		{
			cprintf("..Fail(Over Time). ");
			SendErrorMessagePackage(0xF1);
			break;
		}
		ReturnCode=gDataPort.ReceiveDataPackage(mBuffer);
		if(ReturnCode==0xB1) return 0;
		else if(ReturnCode==0xB9)
		{
			cprintf("\r\n...Fail(Recv Stop Command).");
			break;
		}
		else if(ReturnCode)
		{
			gDataPort.SendDataPackage(SendBuffer);
			cprintf("%4c",'A');
		}
		else cprintf("+");
	}

	return 1;
}
void CUpgradeFile::Start()
{
	Teststack();
	//删除文件 \\uprade!!.OK
	unlink(constUpgradeOKFileName);	//删除文件uprade!!.OK
	m_ptrSuccPackMark=NULL;
	m_SuccPackCount=0;

	if(Operate_SendB0_WaitB1()) return ;

	RuningOK();
	for(;;)
	{
		RuningOK();
		if(Operate_SendB1_WaitB2()) return ;//返回数据B2协议,发送B1等待传输数据
		if(Operate_SendB2_WaitTransDataEND()) return ;//发送B2等待传输数据结束,
		if(Operate_SendTransDataEND_WaitB1()) return;//校验文件CRC,发送传输数据结束等待新文件协商
	}
	DELETE(m_ptrSuccPackMark);	
	FCLOSE(ptrFile);
	cprintf("\r\n");
}
////////////////////////////////////////////////////////////////////
//F1=错误或人为停止升级、F2=协议(未知)错误
//F3=产生文件错误、F4=升级磁盘空间不够、F5=磁盘读写错误、
unsigned char CUpgradeFile::Handle_0xB1()//返回0=OK,其它=错误码
{
	//从0xB1协议数据mBuffer中获得升级参数。
	if(ReadUpgradeParameter(mBuffer+4)) return 0xF2;//F2=协议(未知)错误

	//产生一个升级空文件
	cprintf("\r\n   Create Upgrade File %s..",m_strFileName);
	cprintf("\r\n(%u)Len %lu,PackageSize %u ,PackCount %u,Name:%s",m_UnSuccFileCount,m_lFileLen,	m_uPackageSize,m_uPackageCount,m_strFileName);
	if(m_lFileLen==0 ||m_uPackageCount==0)
	{
			 cprintf("\r\n\t!!!FileLen=0,Upgrade Fail!!! ");
			 return 0xF8;//升级文件,包数不能为0
	}

	ptrFile=fopen(m_strFileName,"wb");
	if(!ptrFile)
	{
		cprintf("..Error(File Name Error).");
		return 0xF3;//F3=产生文件错误
	}

	RuningOK();
	//检查磁盘空间是否够。
	if(CheckDiskFreeSpace(m_lFileLen))
	{
		FCLOSE(ptrFile);
		unlink(m_strFileName);
		cprintf("..Error(disk Free Space too small).");
		return 0xF4;//F4=升级磁盘空间不够
	}
	cprintf("..OK");

	//产生给定大小的磁盘文件
	unsigned long k=m_lFileLen;
	memset(mBuffer,0,2048);
	while(k>=2048)
	{
		RuningOK();
		if(fwrite(mBuffer,2048,1,ptrFile)!=1) goto CREATE_ERROR_END;
		k-=2048;
	}
	if(k) if(fwrite(mBuffer,(unsigned short)k,1,ptrFile)!=1) goto CREATE_ERROR_END;
	FCLOSE(ptrFile);
	
	//检验产生文件大小是否成功,并打开读写。
	ptrFile=fopen(m_strFileName,"rb+");
	if(ptrFile)
	{
		fseek(ptrFile,0,SEEK_END);
		if(ftell(ptrFile)!=(long)m_lFileLen) goto CREATE_ERROR_END;
	}
	cprintf("\r\n  Waiting Transmit File Data(Succ Count): \r\n");
	return 0;
CREATE_ERROR_END:
	FCLOSE(ptrFile);
	unlink(m_strFileName);
	cprintf("\r\n...Disk have Error!!!!");
	return 0xF5;//F5=磁盘读写错误
}

short CUpgradeFile::Handle_Check_0xB1()//返回0=和上次协商一致,1=不一致
{
	const unsigned char *ptrData=mBuffer+4;
	if(m_UnSuccFileCount==*(ptrData+0)
	&&m_UprModel==*(ptrData+1)
	&&m_lFileLen==ftonl(ptrData+2)
	&&m_uPackageSize==ftons(ptrData+6)
	&&m_uPackageCount==ftons(ptrData+8)
	&&m_lFileCrcCode1==ftonl(ptrData+10)
	&&m_lFileCrcCode2==ftonl(ptrData+14)
	&& stricmp(m_strFileName,(char*)(ptrData+18))==0
	) return 0;

	return 1;
}

short CUpgradeFile::Handle_0xB2()//0=数据OK  其它=错误。
{
	unsigned short int  FileDataLen=((mBuffer[0]<<8)|mBuffer[1])-6-2;
	unsigned short int FileIndex=((mBuffer[4]<<8)|mBuffer[5]);
	unsigned char *ptrFileData=(mBuffer+6);

	if(FileIndex>=m_uPackageCount)
	{
		return 1;
	}
	else if(FileIndex==m_uPackageCount-1)  //最后一包
	{
		if(m_lFileLen!=(m_uPackageCount-1)*(unsigned long)m_uPackageSize+FileDataLen) return 1;
		gArriveAnswerTime=0;
	}
	else//其他包
	{
		if(FileDataLen!=m_uPackageSize ) return 1;
	}

	if(m_ptrSuccPackMark[FileIndex]==0)
	{
		m_SuccPackCount++;
		m_ptrSuccPackMark[FileIndex]=1;
		fseek(ptrFile,(long)FileIndex*m_uPackageSize,SEEK_SET);
		fwrite(ptrFileData,FileDataLen,1,ptrFile);
		cprintf("%4u",m_SuccPackCount);
	}
	m_CurRecvFileIndex=FileIndex;
	return 0;
}

short CUpgradeFile::Handle_Answer_0xB2()//每5秒会一包数据包。单工没收到一包就就回一包
{
	short ReSendCount=0;
	if(m_SuccPackCount<(m_CurRecvFileIndex+1))//需重发包数
	{
		unsigned short *ptrReSendIndex=(unsigned short *)(mBuffer+8);
		unsigned short int i;
		for(i=0;i<=m_CurRecvFileIndex && ReSendCount<16;i++)
		{
			if(m_ptrSuccPackMark[i]==0)
			{
				*ptrReSendIndex=ftons(i);
				ptrReSendIndex++;
				ReSendCount++;
			}
		}
	}
	*(unsigned short *)mBuffer=ftons(6+4+ReSendCount*2);//长度
	mBuffer[2]=0x01;
	mBuffer[3]=0xB2;
	*(unsigned short *)(mBuffer+4)=ftons(m_SuccPackCount);//正确包数
	*(unsigned short *)(mBuffer+6)=ftons(ReSendCount);//需重发包数
	gDataPort.SendDataPackage(mBuffer);
	cprintf("%4c",'A');
    return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
short CUpgradeFile::CheckFileCrcCode()//0=OK 1=错误
{
	unsigned long CrcCode=0;
	long k=0;

	FILE *fp;
	fp=fopen(m_strFileName,"rb");
	if(!fp) return 1;

	fseek(fp,0,SEEK_END);
	if(ftell(fp)!=(long)m_lFileLen) {FCLOSE(fp);return 1;}

	fseek(fp,0,SEEK_SET);
	for(k=m_lFileLen;k>=2048;k-=2048)
	{
		RuningOK();
		fread(mBuffer,2048,1,fp);
		CrcCode=gCrcCode.Crc32Mtt(mBuffer,2048,CrcCode);
	}
	if(k) fread(mBuffer,(short)k,1,fp);
	CrcCode=gCrcCode.Crc32Mtt(mBuffer,k,CrcCode);
	FCLOSE(fp);
//	cprintf("\r\nCRC=%lX CRc1=%lX CRC2=%lX",CrcCode,m_lFileCrcCode1,m_lFileCrcCode2);
	if(CrcCode==m_lFileCrcCode1 && CrcCode==m_lFileCrcCode2) return 0;
	return 1;
}


⌨️ 快捷键说明

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