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


    由于目前.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多元购买了MoxaUPort1110 USB转串口设备(一般的杂牌子的设备大约几十元一个)还真不错,在我笔记本上终于可以直接通过串口对.Net Micro Framework进行调试了。 
  • 相关阅读:
    C# winform 选择文件保存路径
    笔记
    Redis 队列好处
    异步线程
    WebApi 运行原理
    MVC ---- 怎删改查
    如何快速掌握一门新技术/语言/框架...
    膝盖中了一箭之康复篇
    翻译-Salt与Ansible全方位比较
    膝盖中了一箭之手术篇
  • 原文地址:https://www.cnblogs.com/yefanqiu/p/1160636.html
Copyright © 2020-2023  润新知