采用文件映射的方式模拟flash的读写

在开发一些单片机程序时,写应用的人常常会用到读写flash的接口,一些单片机调试的时候并不是很方便,而写应用的人一般不了解flash的底层驱动,这就给调试造成了困难;另外写驱动和写应用为了能同步进行,一般写驱动的人应提供给写应用的人标准的接口。
为了能使写应用的人能在集成IDE下开发代码,并且不受硬件的限制,本文写了一段以文件映射的方式来模拟flash读写的代码,当然大家也可以以读写文件的方式来模拟flash的读写操作。
以下代码仅供学习交流,代码并不太规范,不喜勿喷。

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

unsigned int EEP_BEGIN;
#define EEP_INIT_VAL              0xFF
#define EEP_PAGE_LEN              0x200
#define EEP_PAGE_COUN             128
#define EEP_LEN                   (EEP_PAGE_LEN*EEP_PAGE_COUN)


#define SETWORD(buffer, val)   \
	do      \
	{       \
		(buffer)[0] = (unsigned char)((val) >> 8);       \
		(buffer)[1] = (unsigned char)(val);              \
	}while(0)

#define SETDWORD(buffer, val)     \
	do      \
	{       \
		(buffer)[0] = (unsigned char)((val) >> 24);      \
		(buffer)[1] = (unsigned char)((val) >> 16);      \
		(buffer)[2] = (unsigned char)((val) >> 8);       \
		(buffer)[3] = (unsigned char)(val);              \
	}while(0)

unsigned int _filesize;

static void HexToStr(const unsigned char *buf,int len, char *ptr)
{
	for(int i = 0; i < len; i++)
	{
		sprintf(ptr, "%02X",buf[i]);
		ptr += 2;
	}
}


static void ArrayToStr(const unsigned char *buf, int len, char *str)
{
	int i;
	for(i=0; i<len; i++)
	{
		sprintf(str, "%02X", buf[i]);
		str[2] = ' ';
		str += 3;
	}
	*(--str) = '\0';
}

static void StrToArray(char *str, unsigned char *buf, int len)
{
	unsigned char tmpbuf[4];
	int i;
	for(i=0; i<len; i++)
	{
		sscanf(&str[i*3], "%x", (unsigned int*)tmpbuf);
		buf[i] = tmpbuf[0];
	}
}

static void AddrToStr(const unsigned int addr, char *str)
{
	unsigned char tmpbuf[4];
	SETDWORD(tmpbuf, addr);

	HexToStr(tmpbuf, 4, str);
	str[8] = ':';
	str[9] = ' ';
	str[10] = '\0';
}

static unsigned int getpos(unsigned int Addr)
{
	char AddrStr[11];
	unsigned int i = 0;
	AddrToStr(Addr, AddrStr);

	while(i < EEP_LEN/16-1)
	{
		if(memcmp(AddrStr, (char*)(EEP_BEGIN+i*59), 8)==0)
			return EEP_BEGIN+i*59;
		i++;
	}
	return 0;
}

//创建一个EEP_LEN大小的文件
static int CreatFlashFile(const char *filepath)
{
	char AddrStr[10+48];
	char DataStr[48];
	unsigned char buf[16];
	unsigned int addr;
	memset(buf, EEP_INIT_VAL, sizeof(buf));

	FILE *fp = fopen(filepath, "w");
	if(fp == NULL)
		return -1;

	ArrayToStr(buf, sizeof(buf), DataStr);
	
	for(addr = 0; addr<EEP_LEN; addr+=16)
	{
		AddrToStr(addr, AddrStr);
		strcat(AddrStr, DataStr);
		fwrite(AddrStr, sizeof(AddrStr), 1, fp);
		fprintf(fp,"%s","\n");
	}
	fclose(fp);
	printf("%s\n", "creat file success.\r\n");
	return 0;
}

//映射flash文件,并且修改地址
int InitFlashFile(const char *filepath)
{
	struct stat sb;
	int fd;
	char *addr;

	fd = open(filepath, O_RDWR);
	if(fd == -1)
		return -1;

	if(fstat(fd, &sb) == -1)
		return -1;

	_filesize = (unsigned int)sb.st_size;
	printf("file size is %d.\n", _filesize);

	addr = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(addr == MAP_FAILED)
		return -1;

	EEP_BEGIN = (unsigned int)addr;

	close(fd);
	printf("EEP_BEGIN is %x.\n", (unsigned int)addr);

	unsigned int FA;
	char AddrStr[10];
	for(FA = EEP_BEGIN; FA<EEP_BEGIN+EEP_LEN; FA+=16,addr+=59)
	{
		AddrToStr(FA, AddrStr);
		memcpy(addr, AddrStr, sizeof(AddrStr));
	}
	if(msync((char*)EEP_BEGIN, sb.st_size, MS_SYNC) < 0)
		return -1;
	printf("%s\n", "mmap success.");
	return 0;
}

void EraseFlashPage(unsigned int Addr)
{
	char AddrStr[10+48];
	char DataStr[48];
	unsigned int FileAddr;
	unsigned char buf[16];

	if(Addr%16)
		return;

	if((Addr+EEP_PAGE_LEN) > ((unsigned int)EEP_BEGIN+EEP_LEN)) //
		return;

	FileAddr = getpos(Addr);
	if(FileAddr == 0)
	{
		printf("%s\n", "get poserr.");
		return;
	}
	
	unsigned char i;
	memset(buf, EEP_INIT_VAL, 16);
	for(i=0;i<EEP_PAGE_LEN/16; i++)
	{
		AddrToStr(Addr+i*16, AddrStr);
		ArrayToStr(buf, 16, DataStr);
		strcat(AddrStr, DataStr);
		memcpy((char*)(FileAddr+i*59), AddrStr, sizeof(AddrStr));
	}

	msync((char*)EEP_BEGIN, _filesize, MS_SYNC);
}


void WriteFlashPage(unsigned int Addr, const unsigned char *buf)
{
	char AddrStr[10+48];
	char DataStr[48];
	unsigned int FileAddr;

	if(Addr%16)
		return;

	if((Addr+EEP_PAGE_LEN) > ((unsigned int)EEP_BEGIN+EEP_LEN)) //
		return;

	FileAddr = getpos(Addr);
	if(FileAddr == 0)
	{
		printf("%s\n", "get poserr.");
		return;
	}
	
	unsigned char i;
	for(i=0;i<EEP_PAGE_LEN/16; i++)
	{
		AddrToStr(Addr+i*16, AddrStr);
		ArrayToStr(buf+i*16, 16, DataStr);
		strcat(AddrStr, DataStr);
		memcpy((char*)(FileAddr+i*59), AddrStr, sizeof(AddrStr));
	}

	msync((char*)EEP_BEGIN, _filesize, MS_SYNC);
}

void ReadFlashPage(unsigned int Addr, unsigned char *buf)
{
	char tmpbuf[59];
	
	if(Addr%16)
		return;
	if ((Addr + EEP_PAGE_LEN) > ((unsigned int)EEP_BEGIN + EEP_LEN))
		return;

	unsigned int FileAddr = getpos(Addr);

	unsigned char i;
	unsigned char Tbuf[16];
	for(i=0;i<EEP_PAGE_LEN/16; i++)
	{
		memcpy(tmpbuf, (char*)(FileAddr+i*59), 59);
		StrToArray(&tmpbuf[10], Tbuf, 16);
		memcpy(buf+i*16, Tbuf, 16);
	}
}


int main(int argc, char *argv[])
{
	if(argc < 2)
	{
		printf("%s\n", "value cnt err.");
		return -1;
	}

	if(CreatFlashFile(argv[1])<0)
	{
		printf("%s\n", "creat file error");
		return -1;
	}
	if(InitFlashFile(argv[1])<0)
	{
		printf("%s\n", "init file error");
		return -1;
	}

	unsigned char buf[EEP_PAGE_LEN];
	unsigned char rbuf[EEP_PAGE_LEN];
	unsigned int i;
	for(i=0; i<EEP_PAGE_LEN; i++)
		buf[i] = i;

 	WriteFlashPage(EEP_BEGIN+EEP_PAGE_LEN, buf);

 	ReadFlashPage(EEP_BEGIN+EEP_PAGE_LEN, rbuf);

 	if(memcmp(buf, rbuf, EEP_PAGE_LEN) != 0)
 	{
 		printf("%s\n", "WR flash error.");
 		return -1;
 	}

 	EraseFlashPage(EEP_BEGIN+EEP_PAGE_LEN);
 	ReadFlashPage(EEP_BEGIN+EEP_PAGE_LEN, rbuf);
 	for(i=0; i<EEP_PAGE_LEN; i++)
 		if(rbuf[i] != 0xff)
 		{
 			printf("%s\n", "erase flash error.");
 			return -1;
 		}

	printf("%s\n", "init flash success.");
	if(munmap((char*)EEP_BEGIN, _filesize) < 0)
	{
		printf("%s\n", "munmap err.");
		return -1;
	}

	exit(EXIT_SUCCESS);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于大文件读写操作,Qt提供了多种方法,其中一种常用的方法是使用内存映射(Memory Mapping)技术。 内存映射允许将文件的内容映射到进程的地址空间中,从而可以直接通过内存访问文件的内容,而不需要显式地进行读写操作。这种方式可以提高读写效率,并且对于大文件的处理更为高效。 在Qt中,可以使用QFile和QIODevice类提供的内存映射功能来实现大文件读写操作。具体步骤如下: 1. 打开文件:使用QFile类打开要进行内存映射文件。 ```cpp QFile file("path/to/file"); if (file.open(QIODevice::ReadWrite)) { // 文件打开成功 } ``` 2. 创建内存映射:使用QFile的map()函数创建一个QMemoryMappedFile对象,并将其指定为读写模式或只读模式。 ```cpp QMemoryMappedFile memFile; if (memFile.open()) { if (memFile.map(&file, QMemoryMappedFile::ReadWrite)) { // 内存映射创建成功 } } ``` 3. 获取映射的数据指针:通过QMemoryMappedFile对象的data()函数获取映射的数据指针。 ```cpp char* data = static_cast<char*>(memFile.data()); ``` 4. 进行读写操作:可以直接通过data指针对文件内容进行读写操作,类似于普通的内存操作。 ```cpp // 写入数据 memcpy(data, "Hello, world!", 14); // 读取数据 QString content = QString::fromUtf8(data); ``` 5. 解除内存映射和关闭文件:完成读写操作后,需要解除内存映射并关闭文件。 ```cpp memFile.unmap(); file.close(); ``` 需要注意的是,使用内存映射技术需要谨慎处理文件大小和内存占用,避免因为大文件或者内存限制而导致程序崩溃或性能问题。此外,还需要注意处理文件不存在或者无法打开的异常情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值