.Net Micro Framework研究—FAT文件系统实现探索

简介: 由于目前.Net Micro Framework并不支持P/Invoke功能,所以在底层在驱动层面用C直接对存储器(Flash)进行文件系统开发是行不通的。幸好.Net Micro Framework提供了ExtendedWeakReference类,其中赋值Target对象可以把数据存放到存储器上

由于目前.Net Micro Framework并不支持P/Invoke功能(也无法像WinCE一样开发流式驱动),所以在底层在驱动层面用C直接对存储器(Flash)进行文件系统开发是行不通的。幸好.Net Micro Framework提供了ExtendedWeakReference类,其中赋值Target对象可以把数据存放到存储器上(Flash)。

[Serializable]
        private class FlashDatas
        {
            //调入数据
            public static byte[] Load(uint index)
            {
                ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(
                        typeof(FlashDatas),                       //类型,任意类都可以,其名称起到一个索引作用
                        index,                                    //ID号,这个数据比较有用,不同ID号代表不同数据
                        ExtendedWeakReference.c_SurviveBoot);//该标志和.c_SurviveBoot 区别不大
                return ewr.Target as byte[];
            }        
 
            //保存数据
            public static void Save(uint index, byte[] data)
            {
                ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(typeof(FlashDatas), index, ExtendedWeakReference.c_SurviveBoot);
                ewr.Target = data;
            }
    }

上面的代码就是ExtendedWeakReference类的具体使用,从代码可以看出我们无法直接对存储器进行读写,只能通过保存类的方式对数据进行存储,至于该数据存放到何处,那是无从得知的。
我最初的想法是定义一个类,类中定义一个大数组,不过实际调试发现,该数组不能太大,超过几十K就会出现内存溢出。幸好该对象可以是字节数组,所以我产生了另一个想法,每次保存一个512字节大小的字节数组,相当于磁盘上的一个扇区,以此为存取的最小单位,实现FAT文件系统。
在我博客上曾写了一篇关于FAT文件系统的文章,如《FAT文件系统几点释疑》(http://blog.csdn.net/yefanqiu/archive/2008/03/13/2176340.aspx),我们知道要实现FAT16系统一般至少需要4M存储空间,实现FAT32一般需要256M空间以上。所以我简单的做了一个程序,在实际硬件中测试一下存取1024*4个512字节的数组内存是否可行。
测试代码如下:

private const uint SectorSize=512;   //扇区大小
        private const uint SecPerClus = 4;   //一个簇包含的扇区数
        public static void Main()
        { 
            Debug.Print("Start");
            for (uint i = 0; i < 512; i++)    //1024*4
            {
                byte[] bytData = new byte[SectorSize];
                bytData[0] = (byte)(i % 256);
                bytData[bytData.Length - 1] = bytData[0];
                FlashDatas.Save(i, bytData);
               Debug.Print(i.ToString() + " Save " + bytData[0].ToString() + " " + bytData[bytData.Length - 1].ToString());
 
                //byte[] bytData = FlashDatas.Load(i);
                //if (bytData == null)
                //{
                //    Debug.Print(i.ToString() + " Load Error");
                //    break;
                //}
                //else
                //{
                //    Debug.Print(i.ToString() + " Load " + bytData[0].ToString() + " " + bytData[bytData.Length - 1].ToString());
                //}
            }
            Debug.Print("Exit");
 }

让我失望的是,Digi的开发板存储个数一旦超过128个就会出现读失败,新拿来的iPac-9302开发板要好一些,512个之内读写没有什么问题,超过这个数就会出现和Digi开发板一样的问题。需要说明的时,在使用读写的过程中如果不断电,读写都会成功的。一但断电重新读取,读就会失败。(当然在我测试过程中出现了各种各样不同的现象,如只能成功读取前几个)。
杜伟当初还想直接支持FAT32系统呢,目前恐怕FAT16的支持都很困难了,如果实现FAT12系统就有点不值当了。不过杜伟建议说模拟器也支持数据存储功能,所以先在模拟器中实现该功能。
没有想到,模拟器存储器最大存储仅支持1M,开始我还以为我配置参数不当呢,后来反编译了模拟器相关的核心代码,发现1M在代码中就已经写死了,相关内容如下。
反编译 Microsoft.SPOT.Emulator.dll,下面是关键代码

------------------------------------------------------------------------
//内存大小0x10000*16 = 1024*1024 也就是1M空间。
public class FlashManager : MemoryManagerBase
{
    // Fields 存储空间已经写死,就是1M
    private FlashSector[] _flashSectors = new FlashSector[] { 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.Start),
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.End), 
 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.Start), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.StorageA, FlashSectorPartition.None),
new FlashSector(0x10000, FlashSectorUsage.StorageA, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.StorageB, FlashSectorPartition.None), 
new FlashSector(0x10000, FlashSectorUsage.StorageB, FlashSectorPartition.End) };
 
....
}
 
//分配内存
internal override void AllocateMemory()
{
        this.ValidateFlashSectorsInternal();
        uint num = 0;
        for (int i = 0; i < this._flashSectors.Length; i++)
        {
            num += this._flashSectors[i].Length;
        }
        base._size = num;
        base.AllocateMemory();    //分配内存 ... ...
        for (int j = 0; j < base._size; j++)
        {
            base._memory[j] = 0xff;
        }
        this.InitializeFlashSectorsInternal();
}
 
//分配内存
internal virtual void AllocateMemory()
{
        this._memory = new byte[this._size];
        this._handle = GCHandle.Alloc(this._memory, 3);
}

此外模拟器在运行结束时,不能保证执行重载的UninitializeComponent函数,所以无法保存内存的数据,代码如下。

/// <summary>
        /// Called by the emulator after all components were setup and registered
        /// </summary>
        public override void InitializeComponent()
        {
            base.InitializeComponent(); 
            _form = new YFEmulatorForm(this.Emulator);
            _form.OnInitializeComponent();
 
            //Launch the UI thread.
            Thread uiThread = new Thread(RunForm);
            uiThread.SetApartmentState(ApartmentState.STA);
            uiThread.Start();
 
            //读Flash数据
            EmulatorFlashPersistance.Load(this);
 
            //必须添加这句,否则不会执行UninitializeComponent方法
            Application.DoEvents();     //这是我添的
        }
        
       
        /// <summary>
        /// Called by the emulator after the program exits
        /// </summary>
        public override void UninitializeComponent()    //这个函数不能保证会运行
        {
            //保存数据
            EmulatorFlashPersistance.Save(this);        //所以无法保存最后的结果
            Application.DoEvents(); //保存数据 
 
            base.UninitializeComponent();
            //When the Micro Framework is shutting down, inform the the WinForm application 
            //to exit as well.
            Application.Exit();
        }

目前该工作的开展对我来说,实在是一个不小的挑战。由于国内研究.Net Micro Framework不多,不仅没有人进行深层次的讨论,也少见相关资料,所以.Net Micro Framework推广真是任重而道远啊。
附记:在我上两篇关于串口部署的文章又有了新的进展,最近花了300多元购买了Moxa的UPort1110 USB转串口设备(一般的杂牌子的设备大约几十元一个)还真不错,在我笔记本上终于可以直接通过串口对.Net Micro Framework进行调试了。 

相关文章
|
30天前
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
36 1
|
14天前
|
开发框架 缓存 监控
NET Framework 到 .NET 5/6 的迁移是重大的升级
本文详细介绍了从 .NET Framework 4.8 迁移到 .NET 5/6 的过程,通过具体案例分析了迁移策略与最佳实践,包括技术栈评估、代码迁移、依赖项更新及数据库访问层的调整,强调了分阶段迁移、保持代码可维护性及性能监控的重要性。
38 3
|
21天前
|
机器学习/深度学习 编解码 算法
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
《nnU-Net: 自适应框架用于基于U-Net的医学图像分割》是一篇2018年的论文,发表在Nature上。该研究提出了一种自适应的医学图像分割框架nnU-Net,能够自动调整模型的超参数以适应不同的数据集。通过2D和3D U-Net及级联U-Net的组合,nnU-Net在10个医学分割数据集上取得了卓越的性能,无需手动调整。该方法强调数据增强、预处理和训练策略等技巧,为医学图像分割提供了一个强大的解决方案。
53 0
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
3月前
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
105 2
|
3月前
|
开发框架 JSON 监控
实战指南:从 .NET Framework 迁移到 .NET 5/6 的策略与最佳实践
【8月更文挑战第28天】从 .NET Framework 迁移到 .NET 5/6 是一次重要的技术升级,涉及开发环境与应用架构的改进。本文通过具体案例分析,介绍迁移策略与最佳实践,帮助开发者顺利完成转变。
68 1
|
3月前
|
缓存 程序员
封装一个给 .NET Framework 用的内存缓存帮助类
封装一个给 .NET Framework 用的内存缓存帮助类
|
4月前
|
开发框架 前端开发 JavaScript
基于SqlSugar的数据库访问处理的封装,支持.net FrameWork和.net core的项目调用
基于SqlSugar的数据库访问处理的封装,支持.net FrameWork和.net core的项目调用
|
3月前
|
XML JSON 程序员
总结一下 .NET FrameWork 和 .NET Core 创建的项目的不同点
总结一下 .NET FrameWork 和 .NET Core 创建的项目的不同点
|
3月前
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了