.Net Micro Framework研究—FATファイルシステム実現探索


今のところNet Micro FrameworkではP/Invoke機能はサポートされていない(WinCEのようにストリーミングドライブを開発することもできない)ため、下位層でドライブレベルでCで直接メモリ(Flash)をファイルシステム開発することはできない.幸い.Net Micro FrameworkではExtendedWeakReferenceクラスが提供されており、ここで割り当てられたTargetオブジェクトはデータをメモリに格納することができる(Flash).
   
   
   
   
  1. [Serializable]  
  2.         private class FlashDatas  
  3.         {  
  4.             //  
  5.             public static byte[] Load(uint index)  
  6.             {  
  7.                 ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(  
  8.                         typeof(FlashDatas),                       // , ,  
  9.                         index,                                    //ID , , ID  
  10.                         ExtendedWeakReference.c_SurviveBoot);// .c_SurviveBoot   
  11.                 return ewr.Target as byte[];  
  12.             }          
  13.    
  14.             //  
  15.             public static void Save(uint index, byte[] data)  
  16.             {  
  17.                 ExtendedWeakReference ewr = ExtendedWeakReference.RecoverOrCreate(typeof(FlashDatas), index, ExtendedWeakReference.c_SurviveBoot);  
  18.                 ewr.Target = data;  
  19.             }  
  20.     }  

上のコードはExtendedWeakReferenceクラスの具体的な使用であり、コードからメモリを直接読み書きすることはできず、クラスを保存することでデータを格納するしかなく、そのデータがどこに格納されているかは分からない.私の最初の考えはクラスを定義し、クラスに大きな配列を定義することでしたが、実際のデバッグでは、この配列はあまり大きくなく、数十Kを超えるとメモリオーバーフローが発生することがわかりました.幸いなことに、このオブジェクトはバイト配列であることができるので、ディスク上のセクタに相当する512バイトサイズのバイト配列を保存するたびに、アクセスの最小単位としてFATファイルシステムを実現する別の考えが生まれました.「FATファイルシステムのいくつかの疑問」(http://yfsoft.blog.51cto.com/1635641/324291)、FAT 16システムを実現するには、一般に少なくとも4 Mの記憶空間が必要であり、FAT 32を実現するには一般的に256 M以上が必要であることが知られている.だから私は簡単にプログラムを作って、実際のハードウェアの中で1024*4個の512バイトの配列メモリにアクセスできるかどうかをテストしました.テストコードは次のとおりです.
   
   
   
   
  1. private const uint SectorSize=512;   //  
  2.         private const uint SecPerClus = 4;   //  
  3.         public static void Main()  
  4.         {   
  5.             Debug.Print("Start");  
  6.             for (uint i = 0; i //1024*4  
  7.             {  
  8.                 byte[] bytData = new byte[SectorSize];  
  9.                 bytData[0] = (byte)(i % 256);  
  10.                 bytData[bytData.Length - 1] = bytData[0];  
  11.                 FlashDatas.Save(i, bytData);  
  12.                Debug.Print(i.ToString() + " Save " + bytData[0].ToString() + " " + bytData[bytData.Length - 1].ToString());  
  13.    
  14.                 //byte[] bytData = FlashDatas.Load(i);  
  15.                 //if (bytData == null)  
  16.                 //{  
  17.                 //    Debug.Print(i.ToString() + " Load Error");  
  18.                 //    break;  
  19.                 //}  
  20.                 //else  
  21.                 //{  
  22.                 //    Debug.Print(i.ToString() + " Load " + bytData[0].ToString() + " " + bytData[bytData.Length - 1].ToString());  
  23.                 //}  
  24.             }  
  25.             Debug.Print("Exit");  
  26.  }  
  27.      

私をがっかりさせたのは、Digiの開発ボードのストレージ数が128個を超えると読み取りに失敗し、新しく持ってきたiPac-9302の開発ボードのほうがよく、512個以内に読み書きに問題はなく、この数を超えるとDigiの開発ボードと同じ問題が発生することです.説明が必要な場合は、読み書きを使用している間に電源を切らなければ、読み書きは成功します.ただし、電源を切って再読み込みすると、読み取りに失敗します.(もちろん、私のテスト中にいろいろな現象が出てきましたが、前のいくつかしか読めませんでした).杜偉は当初FAT 32システムを直接サポートしたいと思っていましたが、FAT 16のサポートは難しいかもしれません.FAT 12システムを実現すれば少し値打ちがありません.しかし、杜偉はシミュレータもデータストレージ機能をサポートしているので、まずシミュレータでこの機能を実現することを提案しました.シミュレータメモリの最大ストレージは1 Mしかサポートされていないとは思わなかったが、最初は構成パラメータが不適切だと思っていたが、シミュレータ関連のコアコードを逆コンパイルしたところ、1 Mはコードの中で死んでいたことが分かった.関連内容は以下の通りである.Microsoftの逆コンパイルSPOT.Emulator.dll、次はキーコードです
   
   
   
   
  1. ------------------------------------------------------------------------  
  2. // 0x10000*16 = 1024*1024  1M 。  
  3. public class FlashManager : MemoryManagerBase  
  4. {  
  5.     // Fields  , 1M  
  6.     private FlashSector[] _flashSectors = new FlashSector[] {   
  7. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.Start),  
  8. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  9. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  10. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  11. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  12. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  13. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  14. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.End),   
  15.    
  16. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.Start),   
  17. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  18. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  19. new FlashSector(0x10000, FlashSectorUsage.Log, FlashSectorPartition.None),   
  20. new FlashSector(0x10000, FlashSectorUsage.StorageA, FlashSectorPartition.None),  
  21. new FlashSector(0x10000, FlashSectorUsage.StorageA, FlashSectorPartition.None),   
  22. new FlashSector(0x10000, FlashSectorUsage.StorageB, FlashSectorPartition.None),   
  23. new FlashSector(0x10000, FlashSectorUsage.StorageB, FlashSectorPartition.End) };  
  24.    
  25. ....  
  26. }  
  27.    
  28. //  
  29. internal override void AllocateMemory()  
  30. {  
  31.         this.ValidateFlashSectorsInternal();  
  32.         uint num = 0;  
  33.         for (int i = 0; i this._flashSectors.Length; i++)  
  34.         {  
  35.             num += this._flashSectors[i].Length;  
  36.         }  
  37.         base._size = num;  
  38.         base.AllocateMemory();    //  ... ...  
  39.         for (int j = 0; j base._size; j++)  
  40.         {  
  41.             base._memory[j] = 0xff;  
  42.         }  
  43.         this.InitializeFlashSectorsInternal();  
  44. }  
  45.    
  46. //  
  47. internal virtual void AllocateMemory()  
  48. {  
  49.         this._memory = new byte[this._size];  
  50.         this._handle = GCHandle.Alloc(this._memory, 3);  
  51. }  

また、シミュレータは、運転終了時に、リロードされたUninitializeComponent関数を実行する保証がないため、メモリのデータを保存できません.コードは以下の通りです. 
   
   
   
   
  1. ///   
  2.         /// Called by the emulator after all components were setup and registered  
  3.         ///   
  4.         public override void InitializeComponent()  
  5.         {  
  6.             base.InitializeComponent();   
  7.             _form = new YFEmulatorForm(this.Emulator);  
  8.             _form.OnInitializeComponent();  
  9.    
  10.             //Launch the UI thread.  
  11.             Thread uiThread = new Thread(RunForm);  
  12.             uiThread.SetApartmentState(ApartmentState.STA);  
  13.             uiThread.Start();  
  14.    
  15.             // Flash  
  16.             EmulatorFlashPersistance.Load(this);  
  17.    
  18.             // , UninitializeComponent  
  19.             Application.DoEvents();     //  
  20.         }  
  21.           
  22.          
  23.         ///   
  24.         /// Called by the emulator after the program exits  
  25.         ///   
  26.         public override void UninitializeComponent()    //  
  27.         {  
  28.             //  
  29.             EmulatorFlashPersistance.Save(this);        //  
  30.             Application.DoEvents(); //    
  31.    
  32.             base.UninitializeComponent();  
  33.             //When the Micro Framework is shutting down, inform the the WinForm application   
  34.             //to exit as well.  
  35.             Application.Exit();  
  36.         }  

今の仕事の展開は私にとって、本当に小さな挑戦です.国内研究のためNet Micro Frameworkは多くなく、深い議論を行う人がいないだけでなく、関連資料も少ないため、Net Micro Frameworkの普及は大変ですね.付記:私の前の2編のシリアルポートの配置に関する文章はまた新しい進展があって、最近300元余りを使ってMoxaのUPort 1110 USBシリアルポート設備(普通の雑牌の設備は約数十元で1つ)を購入して本当に悪くなくて、私のノートパソコンの上でやっと直接シリアルポートを通じて.Net Micro Frameworkをデバッグすることができます.