矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 1478|回复: 21

一个虚拟EEPROM器件,方便调试程序,备忘

[复制链接]
     
发表于 2024-3-20 16:42:24 | 显示全部楼层 |阅读模式
本帖最后由 天天爱玛丽 于 2024-3-20 16:47 编辑

用于在电脑程序中调试带EEPROM的嵌入式程序,实现的虚拟芯片,方便脱离硬件验证程序,
有需要的也可以随便用,估计玩的不会太多,建议linux上调程序用,windows的只读属性有点烦人.
虽然代码中有我自己的数据格式,但是改成需要的格式,对于码农没难度.
xprintf是硬件平台的prinf函数,用prinf就行了,
属于自己备忘,若您感兴趣,欢迎交流.

//24CXX, 1 page = 64 byte, 需16字节对齐
typedef struct
{
    char company[CF_STRING_SZ];
    uint16_t count; //记录条数
    uint16_t max;   //最大条数
    uint16_t lcdsw; //是否启用LCDGUI
    uint16_t magic;
    uint16_t reserved[4];
}cfhead_t;

cfhead_t cfhead;

#define POWER_MAX   100
#define LASER_MAX   100

typedef struct
{
    uint16_t magic;
    uint16_t squeue;
    uint8_t  power, workmode, wavetype, reserved[5];
        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[CF_STRING_SZ];
    char     treat_time_str[CF_STRING_SZ];
    char     treat_freq_str[CF_STRING_SZ];
    char     treat_effect[CF_STRING_SZ];
}cfitem_t;

//quick sort
static void cflist_index_quick_sort(cfitem_t s[], int l, int h)
{
    if (l < h)
    {
        //Swap(s[l], s[(l + r) / 2]);
        int i = l, j = h;
        cfitem_t x = s[l];
        while (i < j)
        {
            while (i < j && s[j].squeue >= x.squeue)
                j--;
            if (i < j)
                s[i++] = s[j];

            while (i < j && s.squeue < x.squeue)
                i++;
            if (i < j)
                s[j--] = 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[1024];
            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[512]; 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[cnt++] = 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);
}

评分

1

查看全部评分

     
发表于 2024-3-20 17:14:22 | 显示全部楼层
不搞个使用范例?思路很好。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2024-3-20 17:51:36 | 显示全部楼层
怪我没说明用法, 应用是这样的,
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:04:35 | 显示全部楼层
本帖最后由 天天爱玛丽 于 2024-3-20 18:54 编辑

傻瓜式的用法了,
每人的业务需求不同,没法兼得,只是提供一种方法,
会玩的人都能玩的很溜,不会玩的人,可以学习
真不行还是老老实实的用硬件调吧,
这个就是为了给上位机的人读写EEPROM数据时,偷懒用的.

正常读写数据只用到下面两个函数,
ee_read_cfitem读一条记录,
ee_write_cfitem写一条记录,

当成微型日志使用也行,挺方便的。
回复 支持 反对

使用道具 举报

     
发表于 2024-3-21 19:06:36 | 显示全部楼层
挺怀念30年前用C语言和汇编编程序的日子
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2024-3-21 23:00:33 | 显示全部楼层
koei 发表于 2024-3-21 19:06
挺怀念30年前用C语言和汇编编程序的日子

30年前,我还在读小学,那时候将家里的黑白电视拆装了很多次.老爸的收音机也被我拆了很多次,最终弄的不响了,为了弄清楚为何不响,后来才喜欢上了电子。
回复 支持 反对

使用道具 举报

发表于 2024-3-22 16:38:44 | 显示全部楼层
不干这一行,只是有点好奇。

1)感觉缺少很多变量或常量的定义。
2)排序是必须的吗?如果必须,那么大一个结构,排序时复制对象太耗时,排序指针或索引可以不?还有,用C库函数qsort省了自己写,调用就行了。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2024-3-22 16:48:12 | 显示全部楼层
本帖最后由 天天爱玛丽 于 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[0]))
#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 17:05:57 | 显示全部楼层
天天爱玛丽 发表于 2024-3-22 16:48
看帖很仔细,赞一个,
我这里仅提供了一种方法,
像常量CF_STRING_SZ之类的,可以定义成16,32,64都行,需 ...

大神,可别这么说。我是码农,除了休息日每天都写程序。退休是很多年以后的事,跟这里大多数人不一样的。

平时主要用C++,一般的C程序也能看个大概罢了。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2024-3-22 18:04:07 | 显示全部楼层
用C++,还说不干这一行,原来遇到同行了,
我也是码了20多年了,搞代码越来越不好混
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2024-3-22 22:26:19 | 显示全部楼层
本帖最后由 天天爱玛丽 于 2024-3-22 22:28 编辑
chipset009 发表于 2024-3-22 16:38
不干这一行,只是有点好奇。

1)感觉缺少很多变量或常量的定义。


排序是我业务上,用一个列表控件显示数据,需要根据指定的条件排序。
如果不需要排序,可以不排序,
C排序非常快的,就是简单的拷贝数据块,
用链表、索引、指针肯定效率更高,可以按照这个思路修改读写函数,
我呢,是对简单的数据就用线性数组,毕竟才几十条数据集。
对于GUI系统,控件的管理都会用链表,毕竟各种关系太复杂,链表方便。
对于图片资源、字体资源等,会用哈希表管理,加快名称查找速度,
指针引用,用的地方不多,曾做过一个内存垃圾检测框架,用到了指针索引,
C语言写这个函数啰嗦,应用也难,
C++写各种类啰嗦,但是应用简单,
相比来说,C的效率和灵活性,对应硬件编程来说,灵活度更高,
其他语言不聊了,如果您有感兴趣的语言,也可以聊聊,
我是很多语言都搞点
回复 支持 反对

使用道具 举报

     
发表于 2024-3-25 08:12:33 | 显示全部楼层
chipset009 发表于 2024-3-22 17:05
大神,可别这么说。我是码农,除了休息日每天都写程序。退休是很多年以后的事,跟这里大多数人不一样的。 ...

30多年前用C,和汇编写过一点点程序,那个时候程序小,除了C语言的标准库函数,其他全部自己写,汇编就什么函数库都不能用了。C++流行的时候,不写程序了。不像现在,要在别人的基础上写程序,现在我已经不会写程序了
回复 支持 反对

使用道具 举报

发表于 2024-3-25 08:58:00 | 显示全部楼层
天天爱玛丽 发表于 2024-3-22 22:26
排序是我业务上,用一个列表控件显示数据,需要根据指定的条件排序。
如果不需要排序,可以不排序,
...

我不做那么底层的东西。

我之前也用C,缺点是写程序太繁琐了。C++省了很多敲字,但那些道道全得知道,否则容易写出垃圾代码。
脚本偶尔用一下,很方便的。需要繁重计算的场合用命令式语言C和C++,JAVA嘛,我只能看懂语法。
回复 支持 反对

使用道具 举报

发表于 2024-3-25 09:13:28 | 显示全部楼层
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[folded * 0x78291ACFU >> 26];
#endif
}
回复 支持 反对

使用道具 举报

     
发表于 2024-3-25 11:43:22 | 显示全部楼层
chipset009 发表于 2024-3-25 09:13
我感觉能大量用汇编的都是高手。我汇编非常菜,三行五行的还行,写不了大程序,比如下面这种,算个比特位 ...


我觉得,3条汇编完成一个不复杂的C语言语句,应该没有问题。所以,C和汇编是等价的。现在你们这代程序员写的程序都是讲究可读性的,我那个时候只要能功能行,就OK了,哪里有什么可读性,别人看不懂拉倒,也没有写过大程序 还是你们的程序设计水平高。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-5 15:42

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表