一个虚拟EEPROM器件,方便调试程序,备忘
本帖最后由 天天爱玛丽 于 2024-3-20 16:47 编辑用于在电脑程序中调试带EEPROM的嵌入式程序,实现的虚拟芯片,方便脱离硬件验证程序,
有需要的也可以随便用,估计玩的不会太多,建议linux上调程序用,windows的只读属性有点烦人.
虽然代码中有我自己的数据格式,但是改成需要的格式,对于码农没难度.
xprintf是硬件平台的prinf函数,用prinf就行了,
属于自己备忘,若您感兴趣,欢迎交流.
//24CXX, 1 page = 64 byte, 需16字节对齐
typedef struct
{
char company;
uint16_t count; //记录条数
uint16_t max; //最大条数
uint16_t lcdsw; //是否启用LCDGUI
uint16_t magic;
uint16_t reserved;
}cfhead_t;
cfhead_t cfhead;
#define POWER_MAX 100
#define LASER_MAX 100
typedef struct
{
uint16_t magic;
uint16_t squeue;
uint8_tpower, workmode, wavetype, reserved;
uint16_t zhongpin;
uint16_t tiaofu;
uint16_t interval_keep;
uint16_t interval_pause;
uint16_t surge_up, surge_keep, surge_down, surge_pause;
uint16_t time;
uint16_t eindex;
char name;
char treat_time_str;
char treat_freq_str;
char treat_effect;
}cfitem_t;
//quick sort
static void cflist_index_quick_sort(cfitem_t s[], int l, int h)
{
if (l < h)
{
//Swap(s, s[(l + r) / 2]);
int i = l, j = h;
cfitem_t x = s;
while (i < j)
{
while (i < j && s.squeue >= x.squeue)
j--;
if (i < j)
s = s;
while (i < j && s.squeue < x.squeue)
i++;
if (i < j)
s = s;
}
s = x;
cflist_index_quick_sort(s, l, i - 1);
cflist_index_quick_sort(s, i + 1, h);
}
}
void ee_default_when_non_exist(void)
{
int fd = open(eeprom, O_RDONLY);
if (fd < 3)
{
//windwos, after creation, manually remove read-only flag.
fd = open(eeprom, O_RDWR | O_CREAT | O_BINARY, 0777);
if (fd >= 3)
{
char buf;
memset(buf, 0xFF, 1024);
int count = GX_COUNT(chufang_preset);
for (int i = 0; i < count; i++)
{
write(fd, buf, CF_ITEM_SZ);
}
close(fd);
}
} else {
close(fd);
}
}
uint16_t ee_read_magic(int fd, uint16_t index)
{
uint16_t magic = 0;
off_t offset = CFLIST_ADDR + CF_MAGIC_OFS + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
read(fd, &magic, 2);
return magic;
}
uint16_t ee_read_squeue(int fd, uint16_t index)
{
uint16_t squeue = 0;
off_t offset = CFLIST_ADDR + CF_SQUEUE_OFS + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
read(fd, &squeue, 2);
return squeue;
}
void ee_write_squeue(int fd, uint16_t index, uint16_t squ)
{
off_t offset = CFLIST_ADDR + CF_SQUEUE_OFS + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
write(fd, &squ, 2);
}
uint16_t ee_get_freeed_index(void)
{
uint16_t index = 0xFFFF;
int fd = open(eeprom, O_RDONLY);
if (fd < 3) return index;
/* get a free index in cflist */
for (int i = 0; i<CHUFANG_MAX; i++)
{
if (ee_read_magic(fd, i) != MEDI_MAGIC) {
index = i;
xprintf("freeed index %d\n", index);
break;
}
}
close(fd);
return index;
}
/*
* cfhead_t header, 64B
* cfitem_t cflist; 64B per item
* others
*/
void ee_read_cflist(void)
{
cfhead_t header;
cfitem_t item;
int fd = 0;
int cnt = 0;
#if 1
ee_default_when_non_exist();
#endif
fd = open(eeprom, O_RDWR|O_BINARY);
if (fd < 3) {
xprintf("open eeprom failed\n");
return;
}
lseek(fd, 0, SEEK_SET);
read(fd, &header, CF_HEAD_SZ);//read header
#if DEBUG_EEPROM==1
xprintf("eeprom read header at %04X:\n", 0x0000);
for (int i = 0; i<CF_ITEM_SZ; i++) {
xprintf("%02X ", *(((uint8_t*)&header) + i));
if (i>0 && i % 16 == 15) xprintf("\n");
}
xprintf("\n");
#endif
if (header.magic == MEDI_MAGIC)
{
memset(&cfhead, 0, CF_HEAD_SZ);
cfhead = header;
xprintf("read chufang header. headsz:%d\n", CF_HEAD_SZ);
xprintf("read chufang list. itemsz:%d\n", CF_ITEM_SZ);
for (int i = 0; i<CHUFANG_MAX; i++)
{
if (ee_read_magic(fd, i) == MEDI_MAGIC)
{
ee_read_cfitem(i, &item);
item.eindex = i;
cflist = item;
#if DEBUG_EEPROM==1 //DEBUG
xprintf("readin item(%d).power = %d\n", i, item.power);
xprintf(" item(%d).mode = %d\n", i, item.mode);
xprintf(" item(%d).zhongpin = %d\n", i, item.zhongpin);
xprintf(" item(%d).tiaofu = %d\n", i, item.tiaofu);
xprintf(" item(%d).interval_keep= %d\n", i, item.interval_keep);
xprintf(" item(%d).interval_pause = %d\n", i, item.interval_pause);
xprintf(" item(%d).surge_up = %d\n", i, item.surge_up);
xprintf(" item(%d).surge_keep = %d\n", i, item.surge_keep);
xprintf(" item(%d).surge_down = %d\n", i, item.surge_down);
xprintf(" item(%d).surge_pause = %d\n", i, item.surge_pause);
xprintf(" item(%d).time = %d\n", i, item.time);
xprintf(" item(%d).eindex = %d\n", i, item.eindex);
xprintf(" item(%d).squeue = %d\n", i, item.squeue);
xprintf("\n");
#endif
#if DEBUG_EEPROM==1
xprintf("eeprom %d sequeue=%d\n", i, item.squeue);
#endif
}
}
cfhead.count = cnt; /* use to query chufang list */
//quick sort by index
xprintf("cflist quick sort by squeue\n");
cflist_index_quick_sort(cflist, 0, cnt - 1);
close(fd);
}
else
{ //new eeprom, setup a default chufang list
cnt = GX_COUNT(chufang_preset);
xprintf("new eeprom. headsz:%d, cnt:%d\n", CF_HEAD_SZ, cnt);
memset(&header, 0, CF_HEAD_SZ);
sprintf(header.company, "%s", "1234567890ABCDEFG");
header.count = cnt;
header.max = CHUFANG_MAX;
header.magic = MEDI_MAGIC;
lseek(fd, 0, SEEK_SET);
write(fd, &header, CF_HEAD_SZ);
#if DEBUG_EEPROM==1
xprintf("preset chufang header.\n");
for (int i = 0; i<headsz; i++) {
xprintf("%02X ", *(((uint8_t*)&header) + i));
if (i>0 && i % 16 == 15) xprintf("\n");
}
xprintf("\n");
#endif
//use preset chufang list
xprintf("preset chufang list. itemsz:%d\n", CF_ITEM_SZ);
for (int i = 0; i<cnt; i++)
{
item = chufang_preset;
item.eindex = i;
item.squeue = i;
item.magic = MEDI_MAGIC;
#if DEBUG_EEPROM==1 //DEBUG
xprintf("preset item(%d).power = %d\n", i, item.power);
xprintf(" item(%d).mode = %d\n", i, item.mode);
xprintf(" item(%d).zhongpin = %d\n", i, item.zhongpin);
xprintf(" item(%d).tiaofu = %d\n", i, item.tiaofu);
xprintf(" item(%d).interval_keep= %d\n", i, item.interval_keep);
xprintf(" item(%d).interval_pause = %d\n", i, item.interval_pause);
xprintf(" item(%d).surge_up = %d\n", i, item.surge_up);
xprintf(" item(%d).surge_keep = %d\n", i, item.surge_keep);
xprintf(" item(%d).surge_down = %d\n", i, item.surge_down);
xprintf(" item(%d).surge_pause = %d\n", i, item.surge_pause);
xprintf(" item(%d).time = %d\n", i, item.time);
xprintf("\n");
#endif
write(fd, &item, CF_ITEM_SZ);
cflist = item;
}
close(fd);
system("sync");
}
}
void ee_mark_invalid(uint16_t index)
{
int fd = open(eeprom, O_RDWR | O_BINARY);
if (fd < 3) {
xprintf("open eeprom failed\n");
return;
}
xprintf("eeprom mark %d as invalid\n", index);
//off_t offset = CFLIST_ADDR + index * CF_ITEM_SZ;
off_t offset = CFLIST_ADDR + CF_MAGIC_OFS + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
cfitem_t item;
memset(&item, 0xFF, CF_ITEM_SZ);
write(fd, &item, CF_ITEM_SZ);
close(fd);
}
void ee_read_cfitem(uint16_t index, cfitem_t *item)
{
int fd = open(eeprom, O_RDONLY);
if (fd < 3)
return;
off_t offset = CFLIST_ADDR + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
read(fd, item, CF_ITEM_SZ);
if (item->power > POWER_MAX)
item->power = POWER_MAX;
close(fd);
}
void ee_write_cfitem(uint16_t index, cfitem_t *item)
{
int fd = open(eeprom, O_RDWR | O_BINARY);
if (fd < 3) {
xprintf("open eeprom failed\n");
return;
}
off_t offset = CFLIST_ADDR + index * CF_ITEM_SZ;
lseek(fd, offset, SEEK_SET);
write(fd, item, CF_ITEM_SZ);
#if 0
xprintf("write at %d:\n", index);
for (int i = 0; i<CF_ITEM_SZ; i++) {
xprintf("%02X ", *(((uint8_t*)item) + i));
if (i>0 && i % 16 == 15) xprintf("\n");
}
xprintf("\n");
#endif
system("sync");
close(fd);
}
uint16_t cflist_get_squeue(uint16_t index)
{
listbox_t *lbox = chufang_lbox_get();
for (uint16_t i = 0; i < lbox->item_count; i++)
{
if (lbox->items.data == index) {
return i;
}
}
return 0xFFFF;
}
void ee_squeue_index_sync(void)
{
int fd = open(eeprom, O_RDWR | O_BINARY);
if (fd < 3) {
xprintf("open eeprom failed\n");
return;
}
xprintf("ee_squeue_index_sync\n");//DEBUG
for (uint16_t i = 0; i<CHUFANG_MAX; i++)
{
if (ee_read_magic(fd, i) == MEDI_MAGIC)
{
uint16_t squeue = cflist_get_squeue(i);
ee_write_squeue(fd, i, squeue);
}
}
close(fd);
}
不搞个使用范例?思路很好。 怪我没说明用法, 应用是这样的,
ee_read_cflist()是读取接口,可以读取虚拟EE文件里的数据,我是按照我的数据格式定义了数据,换成用户自己的即可.
用户可以定义一个数组
const cfitem_t chufang_preset[] =
{
{
.name = "first item",
.workmode = 0,
.wavetype = 0,
.zhongpin = 4000, //Hz
.tiaofu = 100, //Hz
.power = 10,
.interval_keep = 2, .interval_pause = 2,
.surge_up = 0, .surge_keep = 0, .surge_down = 0, .surge_pause = 0,
.time = 12,
.treat_time_str = "12",
.treat_freq_str = "this is a string.",
.treat_effect = "I am a virtual eeprom.",
},
};
在第一次使用时,可以自动创建一个虚拟EEPROM,以后的操作就会针对改虚拟EEPROM进行. 本帖最后由 天天爱玛丽 于 2024-3-20 18:54 编辑
傻瓜式的用法了,
每人的业务需求不同,没法兼得,只是提供一种方法,
会玩的人都能玩的很溜,不会玩的人,可以学习
真不行还是老老实实的用硬件调吧,
这个就是为了给上位机的人读写EEPROM数据时,偷懒用的.
正常读写数据只用到下面两个函数,
ee_read_cfitem读一条记录,
ee_write_cfitem写一条记录,
当成微型日志使用也行,挺方便的。
挺怀念30年前用C语言和汇编编程序的日子 koei 发表于 2024-3-21 19:06
挺怀念30年前用C语言和汇编编程序的日子
30年前,我还在读小学,那时候将家里的黑白电视拆装了很多次.老爸的收音机也被我拆了很多次,最终弄的不响了,为了弄清楚为何不响,后来才喜欢上了电子。 不干这一行,只是有点好奇。
1)感觉缺少很多变量或常量的定义。
2)排序是必须的吗?如果必须,那么大一个结构,排序时复制对象太耗时,排序指针或索引可以不?还有,用C库函数qsort省了自己写,调用就行了。 本帖最后由 天天爱玛丽 于 2024-3-22 16:56 编辑
chipset009 发表于 2024-3-22 16:38
不干这一行,只是有点好奇。
1)感觉缺少很多变量或常量的定义。
看帖很仔细,赞一个,
我这里仅提供了一种方法,
像常量CF_STRING_SZ之类的,可以定义成16,32,64都行,需要根据自己的业务定,所以我没给出,经常堆码都知道怎么处理,
仅读写数据只需要read/write即可,其他函数都是跟具体业务相关了,每个人的需求都不一样的.
对你前两天的发言印象深刻,很有条理,以后不妨花点时间玩玩编程,C语言就行.
你的疑问很好,下面补全一些常量定义:
#define GX_COUNT(A) (sizeof(A)/sizeof(A))
#define DEBUG_EEPROM 0 //print eeprom debug info
#define VLIST_NUMS 32 //view numbers
#define CHUFANG_MAX 1000
#define MEDI_MAGIC 0x5678
#define CF_HEAD_SZ sizeof(cfhead_t)
#define CF_ITEM_SZ sizeof(cfitem_t) //64 //chufang info size
#define CFLIST_ADDR CF_HEAD_SZ //chufang area offset 天天爱玛丽 发表于 2024-3-22 16:48
看帖很仔细,赞一个,
我这里仅提供了一种方法,
像常量CF_STRING_SZ之类的,可以定义成16,32,64都行,需 ...
大神,可别这么说。我是码农,除了休息日每天都写程序。退休是很多年以后的事,跟这里大多数人不一样的。
平时主要用C++,一般的C程序也能看个大概罢了。 用C++,还说不干这一行,原来遇到同行了,:D
我也是码了20多年了,搞代码越来越不好混:L
本帖最后由 天天爱玛丽 于 2024-3-22 22:28 编辑
chipset009 发表于 2024-3-22 16:38
不干这一行,只是有点好奇。
1)感觉缺少很多变量或常量的定义。
排序是我业务上,用一个列表控件显示数据,需要根据指定的条件排序。
如果不需要排序,可以不排序,
C排序非常快的,就是简单的拷贝数据块,
用链表、索引、指针肯定效率更高,可以按照这个思路修改读写函数,
我呢,是对简单的数据就用线性数组,毕竟才几十条数据集。
对于GUI系统,控件的管理都会用链表,毕竟各种关系太复杂,链表方便。
对于图片资源、字体资源等,会用哈希表管理,加快名称查找速度,
指针引用,用的地方不多,曾做过一个内存垃圾检测框架,用到了指针索引,
C语言写这个函数啰嗦,应用也难,
C++写各种类啰嗦,但是应用简单,
相比来说,C的效率和灵活性,对应硬件编程来说,灵活度更高,
其他语言不聊了,如果您有感兴趣的语言,也可以聊聊,
我是很多语言都搞点 chipset009 发表于 2024-3-22 17:05
大神,可别这么说。我是码农,除了休息日每天都写程序。退休是很多年以后的事,跟这里大多数人不一样的。 ...
30多年前用C,和汇编写过一点点程序,那个时候程序小,除了C语言的标准库函数,其他全部自己写,汇编就什么函数库都不能用了。C++流行的时候,不写程序了。不像现在,要在别人的基础上写程序,现在我已经不会写程序了 天天爱玛丽 发表于 2024-3-22 22:26
排序是我业务上,用一个列表控件显示数据,需要根据指定的条件排序。
如果不需要排序,可以不排序,
...
我不做那么底层的东西。
我之前也用C,缺点是写程序太繁琐了。C++省了很多敲字,但那些道道全得知道,否则容易写出垃圾代码。
脚本偶尔用一下,很方便的。需要繁重计算的场合用命令式语言C和C++,JAVA嘛,我只能看懂语法。 koei 发表于 2024-3-25 08:12
30多年前用C,和汇编写过一点点程序,那个时候程序小,除了C语言的标准库函数,其他全部自己写,汇编就什 ...
我感觉能大量用汇编的都是高手。我汇编非常菜,三行五行的还行,写不了大程序,比如下面这种,算个比特位之类的。
long bit_scan_forward(uint64_t n)
{
#ifdef __GNUG__
#if (defined __amd64) || (defined __x86_64__)
asm volatile("bsfq %0, %0" : "=r" (n) : "0" (n));
return n;
#elif (defined __i386__)
int32_t x1;
int32_t x2;
asm volatile("bsfl %0, %0\n" "jnz 1f\n" "bsf %1, %0\n" "jz 1f\n" "addl $32, %0\n"
"1:" : "=&q" (x1), "=&q" (x2) : "1" ((int32_t)(n >> 32)), "0" ((int32_t)n));
return x1;
#endif
#else
// when 0, the returned value is set to zero
if(0 == n)
return n;
n ^= n - 1U;
uint32_t folded = static_cast<uint32_t>(n) ^ (n >> 32);
return Lsb64Table;
#endif
} chipset009 发表于 2024-3-25 09:13
我感觉能大量用汇编的都是高手。我汇编非常菜,三行五行的还行,写不了大程序,比如下面这种,算个比特位 ...
我觉得,3条汇编完成一个不复杂的C语言语句,应该没有问题。所以,C和汇编是等价的。现在你们这代程序员写的程序都是讲究可读性的,我那个时候只要能功能行,就OK了,哪里有什么可读性,别人看不懂拉倒,也没有写过大程序;P 还是你们的程序设计水平高。
页:
[1]
2