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

📄 kw_fat32.c

📁 linux下数据下载器的设计与实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************************************** 
 Copyright (C), 1988-1999, Xi'an Keyway Control & Measurement Technology Co., Ltd
 FileName: kw_nand.c 
 Description     :nandflash 接口模块。      
 Version         :1.0 
 Function List   :    
 History:         // 历史修改记录 
      <author>      <time>        <version >       <desc> 
      LigangWang    07/08/08       1.0             build this moudle   
*************************************************************************************/

#include "globals.h"

DWORD xdata 	FM_ptr_fats;         			// FAT区首地址
DWORD xdata     FM_ptr_data;         			// 数据区首地址
DWORD xdata     FM_ptr_root;					// 目录区首地址
DWORD xdata		FM_dirs_fat;					// FAT中目录数
WORD  xdata     FM_sectors_fat;					// 每个FAT区扇区数
BYTE  xdata     FM_num_fats;					// FAT区数量
DWORD xdata     FM_unuse_clus;					// 未使用簇数量
BYTE  xdata     FM_sectors_clus;				// 每簇扇区数

DWORD xdata     FM_CurrentDirLBA;				// 当前打开文件的目录LBA地址
DWORD xdata     FM_CurrentFileLength;			// 当前打开文件长度
Dir_tag xdata * FM_pCurrentDir;					// 当前文件名所在目录表页中偏移

BYTE xdata      FM_DataBuff1[MAX_RS232_BUFF];	// 数据缓冲区1 用于接收RS232数据				   
BYTE xdata      FM_DataBuff2[MAX_RS232_BUFF];	// 数据缓冲区2 用于接收RS232数据
WORD xdata		FM_DPointer1;					// 数据缓冲区1 索引
WORD xdata		FM_DPointer2;					// 数据缓冲区2 索引
BYTE xdata      FM_CurrentBuff;					// 数据缓冲指示,用于标识当前缓冲区
BYTE xdata		FM_FileName[12];				// 文件名,标识最后一个文件名
BYTE xdata		FM_FileName_F[12];				// 文件名,标识第一个文件名



/************************************************************************************* 
  Function:       FM_fat_install
  Description:    安装FAT文件系统
  Called By:      
  Input:          N/A
  Output:         N/A
  Return:         1:成功 0:失败
  Others:         系统初始化时调用,仅调用一次,用于初始化FAT文件系统
  				  读取系统参数、创建并打开数据文件
*************************************************************************************/				   
bit FM_fat_install (void)
{    
	NM_ReadPage(MBR_ADDRESS);											//读取MBR信息

    FM_ptr_fats = 0x01;
    if ((EP6FIFOBUF[0] == 0xEB) && (EP6FIFOBUF[2] == 0x90)) 			//检查跳转标志
    {
    	if ((EP6FIFOBUF[21] & 0xF0) == 0xF0)  							//检查媒体类型
    	{
      		if ((EP6FIFOBUF[510] == 0x55) && (EP6FIFOBUF[511] == 0xAA)) //检查结束标志
      		{
        		FM_ptr_fats = 0x00000000;            					//OK,FAT信息正确
      		}                                       
      		else
      		{
        		return 0;												//FAT信息错误
      		}
    	}
  	}

	if (FM_ptr_fats)                     								//FAT信息错误,返回
	{
		return 0;
 	}

 	//检查FAT16文件系统 
	FM_sectors_clus = EP6FIFOBUF[13];									//offset = 13: 每簇扇区数;
	((BYTE*)&FM_ptr_fats)[3] = EP6FIFOBUF[14];							//offset = 14: LSB of reserved sector.;
	((BYTE*)&FM_ptr_fats)[2] = EP6FIFOBUF[15];  						//offset = 15: MSB of reserved sector.;
	((BYTE*)&FM_ptr_fats)[1] = 0;
	((BYTE*)&FM_ptr_fats)[0] = 0;


	((BYTE*)&FM_sectors_fat)[1] = EP6FIFOBUF[22];
	((BYTE*)&FM_sectors_fat)[0] = EP6FIFOBUF[23];

	
	//获取根目录: root = reserved sectors + num of FATs * sectors per FAT
	FM_num_fats = EP6FIFOBUF[16];										//offset 16: FAT区数量

	FM_ptr_root = FM_ptr_fats + FM_num_fats * FM_sectors_fat;

	((BYTE*)&FM_dirs_fat)[3] = EP6FIFOBUF[17];							//获取每FAT区目录数量
	((BYTE*)&FM_dirs_fat)[2] = EP6FIFOBUF[18]; 
    ((BYTE*)&FM_dirs_fat)[1] = 0;
	((BYTE*)&FM_dirs_fat)[0] = 0;

	//获取数据区: data = FM_ptr_root +(32 * dir in FAT)/Byte per sector;
	FM_ptr_data = FM_ptr_root + (32 * FM_dirs_fat) / 512;

	FM_DPointer1 = FM_DPointer2 = 0;
	FM_CurrentBuff = 0;

	//FAT安装成功
	FM_DeleteFileInRoot("KWSYSTEM.LOG");
    if(CM_ReadConfigToParam() == 0)										//读取配置参数
	{
		CM_SetConfigParameterDefault();									//如果配置参数错误则使用默认参数
	}

	if(CM_ConfigParameter.RTC_Valid == 1)								//如果配置参数中RTC时间有效
	{
		RM_SetRTCTime();												//则设置RTC时间
	}
	FM_CreateNewFileName();												//创建新文件名称,保存于FM_FileName
	FM_OpenFileInRoot(FM_FileName);										//打开新文件
	return 0;
}


/************************************************************************************* 
  Function:       FM_GetFreeClu
  Description:    用于从文件分配表中获取一个空簇
  Called By:      
  Input:          N/A
  Output:         N/A
  Return:         空簇地址,0则表示没有空簇
  Others:         找到空簇后,将该簇设置为0xFFFF,标识占用
*************************************************************************************/
WORD FM_GetFreeClu()
{
	DWORD xdata i,j;
	WORD xdata * pTmp;
	WORD xdata FreeClu = 0;
	for(i = 0; i < FM_sectors_fat; i++)				//读取所有文件分配区
	{
		NM_ReadPage(FM_ptr_fats + i);				//读取一个扇区
		pTmp = (WORD * )(&EP6FIFOBUF[0]);			//从扇区开始地址查找
		for(j=0;j<512/2;j++)						//扇区512字节,簇地址为Word型
		{
			if(*pTmp == 0x0000)						//找到空簇,设置占有标志,并回写
			{
				*pTmp = 0xffff;						
				NM_WritePages(FM_ptr_fats + i);
				return FreeClu;
			}
			FreeClu += 1;							//簇地址递增
			pTmp++;									//下一簇号
		}
	}
	return 0;
}

/************************************************************************************* 
  Function:       FM_OpenFileInRoot
  Description:    打开根目录一个文件,若文件不存在则创建
  Called By:      
  Input:          sFileName @ char *: 文件名
  Output:         N/A
  Return:         文件目录指针,NULL则创建(打开)失败
  Others:         
*************************************************************************************/
Dir_tag *  FM_OpenFileInRoot(char * sFileName)
{
	WORD xdata i,j,StartClu;
	DWORD xdata tmpLBA = 0;
	Dir_tag xdata * pDir = 0;
	FM_pCurrentDir = 0;

	for(i=0; i<((32 * FM_dirs_fat) / 512); i++)	
	{
		NM_ReadPage(FM_ptr_root + i);				//读取目录表
		pDir = ((Dir_tag * ) (& EP6FIFOBUF[0]));	//指向第一个目录

		for(j=0;j<16;j++)							//每扇区有16个目录
		{
			if(pDir->FileName[0] == 0x00 			//跳过空项及以删除项
				||  pDir->FileName[0] == 0xe5)	
			{
				if(FM_pCurrentDir == 0)				//如果当前文件为空则记录该项的偏移及LBA
				{									//后面创建文件要用到。
					FM_pCurrentDir = pDir;
					tmpLBA = FM_ptr_root + i;
				}
				pDir ++;
				continue;
			}
			if(pDir->attribute & 0x18)				//如果时目录则跳过
			{
				pDir ++;
				continue;
			}
			
			//比较文件名是否相同,这个代码要修改
			if(    sFileName[0] == pDir->FileName[0] && sFileName[1] == pDir->FileName[1]
				&& sFileName[2] == pDir->FileName[2] && sFileName[3] == pDir->FileName[3]			
				&& sFileName[4] == pDir->FileName[4] && sFileName[5] == pDir->FileName[5]			
				&& sFileName[6] == pDir->FileName[6] && sFileName[7] == pDir->FileName[7]			
				&& pDir->ExtName[0] == sFileName[9] && pDir->ExtName[1] == sFileName[10]
				&& pDir->ExtName[2] == sFileName[11])
			{
				FM_CurrentDirLBA = FM_ptr_root + i;
				FM_pCurrentDir = pDir;
				return pDir;						//文件找到,返回目录项
			}
		    pDir ++;
		}
	}
	
	//当文件无法找到,即文件不存在,则创建

	if(tmpLBA != 0)									//LBA地址不为0说明前面找到了一个空目录项
	{
		
		StartClu = FM_GetFreeClu();					//分配一个空簇
		while(StartClu == 0 || StartClu > 0xf900)	
		{
			FM_DeleteFirstFile();					//若无法分配空簇则删除文件
			StartClu = FM_GetFreeClu();
		}

		
		FM_CurrentDirLBA = tmpLBA;					//保存扇区 LBA地址

		NM_ReadPage(FM_CurrentDirLBA);				//打开目录项所在LBA扇区
		
		for(i=0;i<8;i++)							//复制文件名
			FM_pCurrentDir->FileName[i] = sFileName[i];

		FM_pCurrentDir->ExtName[0] = sFileName[9];	//扩展名
		FM_pCurrentDir->ExtName[1] = sFileName[10];
		FM_pCurrentDir->ExtName[2] = sFileName[11];

		FM_pCurrentDir->StartClus[0] = StartClu & 0xff;			//设置起始簇地址
		FM_pCurrentDir->StartClus[1] = (StartClu >>8 )& 0xff;

		FM_pCurrentDir->FileLength[0] = 0;			//设置新文件长度为0
		FM_pCurrentDir->FileLength[1] = 0;
		FM_pCurrentDir->FileLength[2] = 0;
		FM_pCurrentDir->FileLength[3] = 0;

		FM_pCurrentDir->attribute = 0;				//设置文件属性

		RM_ReadRTCTime();							//获取RTC时间
		i = RM_GetTimeForFAT();
		FM_pCurrentDir->time[0] = i&0xff;			//设置文件时间
		FM_pCurrentDir->time[1] = (i>>8)&0xff;
		i = RM_GetDateForFAT();
		FM_pCurrentDir->date[0] = i&0xff;			//设置文件日期
		FM_pCurrentDir->date[1] = (i>>8)&0xff;
		
		NM_WritePages(FM_CurrentDirLBA);			//写文件到目录项中
		return FM_pCurrentDir;		
	}
	return 0;
}

/************************************************************************************* 
  Function:       FM_GetNextClus
  Description:    获取指定簇的下一簇
  Called By:      
  Input:          c @ WORD: 当前簇
  Output:         N/A
  Return:         下簇地址
  Others:         
*************************************************************************************/
WORD FM_GetNextClus(WORD c)
{
	WORD xdata * pTmp;

	NM_ReadPage(FM_ptr_fats+((c>>8)&0xff));							//计算当前簇LBA地址并读取
	pTmp = (WORD *)EP6FIFOBUF;										//获取簇号
	return (pTmp[c&0xff]>>8 & 0xff) | (pTmp[c&0xff]<<8 & 0xff00);	//自己排列
}

/************************************************************************************* 
  Function:       FM_GetFormatedSize
  Description:    计算剩余容量,簇数量
  Called By:      
  Input:          N/A
  Output:         N/A
  Return:         void
  Others:         该函数不使用
*************************************************************************************/
/*
void FM_GetFormatedSize()
{
	DWORD xdata i,j;
	WORD xdata * pTmp;
	FM_unuse_clus = 0;
	for(i = 0; i < FM_sectors_fat; i++)
	{
		NM_ReadPage(FM_ptr_fats + i);
		pTmp = (WORD * )(&EP6FIFOBUF[0]);
		for(j=0;j<512/2;j++)
		{
			if(*pTmp == 0x0000)
				FM_unuse_clus++;
			pTmp++;
		}
	}
}
*/

/************************************************************************************* 
  Function:       FM_DeleteCluLink
  Description:    删除簇链,用于删除文件
  Called By:      
  Input:          nStart@Word:簇链起始号
  Output:         N/A
  Return:         void
  Others:         无意义
*************************************************************************************/
bit FM_DeleteCluLink(WORD nStart)
{
	WORD xdata nTmp;
	WORD xdata * pBuffStart = (WORD *)EP6FIFOBUF;
	NM_ReadPage(FM_ptr_fats+((nStart>>8)&0xff));			//获取首簇LBA,并读取
	while(nStart != 0xffff)									//直到簇链结束
	{
		if(pBuffStart[nStart & 0xff] == 0xffff)				//若下簇为簇链尾
		{
			pBuffStart[nStart & 0xff] = 0x0000;				//置空
			NM_WritePages(FM_ptr_fats+((nStart>>8)&0xff));	//回写
			return 1;
		}
		else
		{	
			//如果当前簇和下一簇都在同一扇区,则直接置空当前簇
			if(((nStart >> 8)&0xff) == (pBuffStart[nStart&0xff] & 0xff))
			{
				nTmp = (pBuffStart[nStart&0xff]>>8 & 0xff) | (pBuffStart[nStart&0xff]<<8 & 0xff00);
				pBuffStart[nStart&0xff] = 0x0000;
				nStart = nTmp;
			}
			//否则,置空当前簇,并读取下簇LBA扇区
			else
			{
				nTmp = (pBuffStart[nStart&0xff]>>8 & 0xff) | (pBuffStart[nStart&0xff]<<8 & 0xff00);
				pBuffStart[nStart&0xff] = 0x0000;
				NM_WritePages(FM_ptr_fats+((nStart>>8)&0xff));
				nStart = nTmp;
				NM_ReadPage(FM_ptr_fats+((nStart>>8)&0xff));
			}
		}
	}
}

/************************************************************************************* 
  Function:       FM_DeleteFileInRoot
  Description:    删除根目录文件
  Called By:      
  Input:          sFileName@BYTE*:文件名
  Output:         N/A
  Return:         1:成功,0:失败
  Others:         无意义
*************************************************************************************/
bit FM_DeleteFileInRoot(BYTE * sFileName)
{
	DWORD xdata i,j;
	Dir_tag xdata * pDir;

	//首先找到文件,具体可参考打开文件代码
	for(i=0; i<((32 * FM_dirs_fat) / 512); i++)
	{
		NM_ReadPage(FM_ptr_root + i);
		pDir = ((Dir_tag * ) (& EP6FIFOBUF[0]));

		for(j=0;j<16;j++)
		{
			if(pDir->FileName[0] == 0x00 ||  pDir->FileName[0] == 0xe5)	//FileName[0]
			{
				pDir ++;
				continue;
			}
			if(pDir->attribute & 0x18)
			{
				pDir ++;
				continue;
			}
			if(    sFileName[0] == pDir->FileName[0] && sFileName[1] == pDir->FileName[1]
				&& sFileName[2] == pDir->FileName[2] && sFileName[3] == pDir->FileName[3]			
				&& sFileName[4] == pDir->FileName[4] && sFileName[5] == pDir->FileName[5]			
				&& sFileName[6] == pDir->FileName[6] && sFileName[7] == pDir->FileName[7]			
				&& sFileName[9] == pDir->ExtName[0] && sFileName[10] == pDir->ExtName[1]
				&& sFileName[11] == pDir->ExtName[2] )
			{
				//文件被找到

⌨️ 快捷键说明

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