How to read a file from Sd card in 4.3

Hello,

I am trying to get a project that worked fine in 4.2 to work in 4.3. I apologize, I cannot seem to find any documentation as to how to use the Sd card now. The code from before does not work, even after fixing the namespace changes. I am using the Fez Raptor board. Here is the code:


           if (!sdCard.IsCardMounted)
                sdCard.Mount();
            GT.StorageDevice storage = sdCard.StorageDevice;
            FileStream stream = storage.Open(fileName, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, (int)stream.Length);
            stream.Close();


The card seems to always be mounted, so sdCard.Mount is not used. Before I didn’t have the if statement, it just always called mount.

When it gets to the .Open line of code, it just throws an IO exception with no other details as to what went wrong.

It has been several months since I worked with the Gadgeteer stuff, but it seems like there used to be code samples in the catalog for each module on how to use it. There isn’t one for the Sd card at least. Have these been moved? I am finding it difficult to find documentation.

I want to use the latest, but this transition to 4.3 has been extremely difficult, every module I add back into my project is taking hours to try and get working again.

Thanks,
Danny

All docs are linked from the NETMF support page. It points to https://www.ghielectronics.com/docs?tags=netmf

One of the tutorials is https://www.ghielectronics.com/docs/51/accessing-folders-and-files

Hello!

Thank you, using that code was helpful. So it seems you do not want to add the SD Module using the designer. This is a bit confusing, perhaps it should be removed from the toolbox?

Thank you very much for the help!
Danny

If you are using Gadgeteer then you can use the “SD module” drivers. This is just another layer on top to make things a bit easier… so it is hop to you, easier or more flexible!

In other words, the SD driver module driver will use the code shown at the link I gave you.

I was using the Gadgeteer SDCard module from the Gadgeteer Designer, in MF 4.2.
The Designer created this statement in program_generated.cs:
this.sdCard = new GTM.GHIElectronics.SDCard(9);

I was using the code shown below in 4.2 and it worked, but in 4.3, it does not work. The sdCard object created by the Designer is passed to the constructor of my SDCardReader class. Now, when the Raptor starts up, the sdCard.IsCardMounted property is false, even when an SD Card is already inserted, the same card that was working in 4.2. The Mounted and UnMounted event handlers do not get called. What is wrong with my code?


using System;
using System.IO;
using System.Text;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTME = Gadgeteer.Modules.GHIElectronics;
using DeviceHive;
using KioskUtility;
using LoggerUtils;

namespace SDCardReaders
{
    public class SDCardReader
    {

        private const string StateParameter = "state";
        private const string DeviceTypeName = "GHI SD Card Reader";
        private GT.Timer sdCardTimer;
        private int sdCardCounter;
        private const int sdCardWaitTime = 3000;    // 3000 ms
        private const int sdCardPollInterval = 100; //100 ms
        private const int sdCardPollCount = sdCardWaitTime / sdCardPollInterval;

        public GTME.SDCard sdCardModule { get; set; }

        /// <summary>
        /// Construct the SDCardReader object
        /// </summary>
        /// <param name="dev"></param>
        /// <param name="_sdCardModule"></param>
        /// <param name="Code"></param>
        public SDCardReader( GTME.SDCard _sdCardModule) 
        {
            sdCardModule = _sdCardModule;
            sdCardModule.Mounted += new GTME.SDCard.MountedEventHandler(sdCard_SDCardMounted);
            sdCardModule.Unmounted += new GTME.SDCard.UnmountedEventHandler(sdCard_SDCardUnmounted);
            sdCardTimer = new GT.Timer(sdCardPollInterval, GT.Timer.BehaviorType.RunContinuously);
            sdCardTimer.Tick += new GT.Timer.TickEventHandler(sdCardTimer_Tick);
            sdCardCounter = 0;
            sdCardTimer.Start();
            Debug.Print("Done Initializing " + Code);
        }

        /// <summary>
        /// Poll the sdCardModule to debounce the IsCardMounted state
        /// Make sure the card is really mounted for X seconds
        /// </summary>
        /// <param name="timer"></param>
        void sdCardTimer_Tick(GT.Timer timer)
        {
            try
            {
                if (!sdCardModule.IsCardMounted)
                {
                    Debug.Print("SD Card is no longer mounted");
                    sdCardCounter = 0;
                    sdCardTimer.Stop();
                    SDCardIsMounted = false;
                }
                else if (++sdCardCounter >= sdCardPollCount)
                {
                    Debug.Print("SD Card is well mounted");
                    sdCardCounter = 0;
                    sdCardTimer.Stop();
                    SDCardIsMounted = true;

                    //PrintSDCardDetails();
                    //ConfigTest();
                }
            }
            catch (Exception ex)
            {
                Debug.Print("Exception in sdCardTimer_Tick() " + ex.ToString());
                KioskUtilities.Reboot();
            }
        }

        private bool SDCardIsMounted = false;

        /// <summary>
        /// Received SD Card un-mounted event from sdCardModule
        /// Stop the Card mounted debounce logic
        /// </summary>
        /// <param name="sender"></param>
        void sdCard_SDCardUnmounted(GTME.SDCard sender, EventArgs e)
        {
            try
            {
                SDCardIsMounted = false;
                sdCardCounter = 0;
                sdCardTimer.Stop();
                Debug.Print("SD Card is Not Mounted Event");
            }
            catch (Exception ex)
            {
                Debug.Print("Exception in sdCard_SDCardUnMounted() " + ex.ToString());
                KioskUtilities.Reboot();
            }

        }

        /// <summary>
        /// Received SD Card mounted event from sdCardModule
        /// Start the card mounted debounce logic
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="_sd"></param>
        void sdCard_SDCardMounted(GTME.SDCard sender, GT.StorageDevice _sd)
        {
            try
            {
                Debug.Print("SD Card is Mounted Event");
                sdCardCounter = 0;
                sdCardTimer.Start();
            }
            catch (Exception ex)
            {
                Debug.Print("Exception in sdCard_SDCardMounted() " + ex.ToString());
                KioskUtilities.Reboot();
            }

        }

        public void PrintSDCardDetails()
        {
            if (IsSDCardMounted)
            {
                VolumeInfo vi = storeDevice.Volume;
                Debug.Print("Volume name = " + vi.Name);
                Debug.Print("IsFormatted = " + vi.IsFormatted.ToString());
                Debug.Print("File system type = " + vi.FileSystem);
                Debug.Print("Free space on disk = " + vi.TotalFreeSpace.ToString());
                Debug.Print("Root directory name = " + storeDevice.RootDirectory);
                Debug.Print("Files in root directory " + storeDevice.ListRootDirectoryFiles());
                Debug.Print("Folders in root directory " + storeDevice.ListRootDirectorySubdirectories());
            }
        }

       

        /// <summary>
        /// Return the debounced SD Card mounted/unmounted state
        /// </summary>
        public bool IsSDCardMounted
        {
            get { return SDCardIsMounted; }
        }

        /// <summary>
        /// Return the StorageDevice object for use in reading and writing
        /// </summary>
        public GT.StorageDevice  storeDevice
        {
            get
            {
                return sdCardModule.StorageDevice;
            }
        }

        /// <summary>
        /// Format the SD Card
        /// </summary>
        public void Format(string Label)
        {
            Debug.Print(" Starting Format of SD Card with label = " + Label);
            storeDevice.Volume.Format("FAT", 0, Label, true);
            Debug.Print(" Format of SD Card Done ");
        }


    }
}



Ok, sorry. But Gus said this:

I take that to mean that I can still use, in 4.3, the Gadgeteer provided object. So this is not correct? What happened to the Gadgeteer Modules documentation?

I created a new Gadgeteer project for MF4.3, with a Raptor and a SD Card module only.

An exception is thrown on this code in program_generated.cs


     private void InitializeModules() {
            this.sdCard = new GTM.GHIElectronics.SDCard(9);
        }

Another exception is thrown when I try to mount the card. The FAT32 formatted card is inserted already.


        void MySDCardMounter()
        {
            sdCard.Mount();
        }

Using mainboard GHI Electronics FEZ Raptor version 1.0
#### Exception System.Exception - 0xffffffff (1) ####
#### Message:
#### GHI.IO.Storage.SDCard::NativeConstructor [IP: 0000] ####
#### GHI.IO.Storage.SDCard::.ctor [IP: 0017] ####
#### GHIElectronics.Gadgeteer.FEZRaptor::MountStorageDevice [IP: 0019] ####
#### Gadgeteer.Modules.GHIElectronics.SDCard::Mount [IP: 0016] ####
#### SDCardTest.Program::InitializeModules [IP: 0007] ####
A first chance exception of type ‘System.Exception’ occurred in GHI.Hardware.dll
SD Card is inserted = True
SD Card is mounted = False
#### Exception System.Exception - 0xffffffff (4) ####
#### Message:
#### GHI.IO.Storage.SDCard::NativeConstructor [IP: 0000] ####
#### GHI.IO.Storage.SDCard::.ctor [IP: 0017] ####
#### GHIElectronics.Gadgeteer.FEZRaptor::MountStorageDevice [IP: 0019] ####
#### Gadgeteer.Modules.GHIElectronics.SDCard::Mount [IP: 0016] ####
A first chance exception of type ‘System.Exception’ occurred in GHI.Hardware.dll
The thread ‘’ (0x4) has exited with code 0 (0x0).
Program Started
The thread ‘’ (0x3) has exited with code 0 (0x0).

So it looks like I have to use the Tutorial code that Gus linked to.

I also had problems trying to use the auto-generated code. Instead I did not use it and instead used my own constructor, and did not pass a socket number:


mySd = new GHI.IO.Storage.SDCard();

Then I didn’t use the events, I simply did this:


            Debug.Print("Started Music");
            fileName = "\\SD\\" + fileName;
            if (!mySd.Mounted)
                mySd.Mount();
            _musicStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            var length = (int)_musicStream.Length;
            var buffer = new byte[length];
            _musicStream.Read(buffer, 0, buffer.Length);
            music.SetVolume(255, 255);
            music.Play(buffer);


Then in the Music_Finished event:


            Debug.Print("Finished Music");
            _musicStream.Close();
            mySd.Unmount();

Hope this helps!

This did not work for me, I changed the Designer code to be as you suggested:


        /// <summary>The SD Card module using socket 9 of the mainboard.</summary>
        //private Gadgeteer.Modules.GHIElectronics.SDCard sdCard;
        private GHI.IO.Storage.SDCard sdCard;


private void InitializeModules() {
            //this.sdCard = new GTM.GHIElectronics.SDCard(9);
            this.sdCard = new GHI.IO.Storage.SDCard();
        } 

The call to the constructor SDCard() threw an exception:

Using mainboard GHI Electronics FEZ Raptor version 1.0
#### Exception System.Exception - 0xffffffff (1) ####
#### Message:
#### GHI.IO.Storage.SDCard::NativeConstructor [IP: 0000] ####
#### GHI.IO.Storage.SDCard::.ctor [IP: 0017] ####
#### SDCardTest.Program::InitializeModules [IP: 0005] ####
A first chance exception of type ‘System.Exception’ occurred in GHI.Hardware.dll
An unhandled exception of type ‘System.Exception’ occurred in GHI.Hardware.dll

Are you using MF 4.2 or 4.3? Raptor board?

I got it to work by creating sdCard() in a thread


   public partial class Program
    {
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            /*******************************************************************************************
            Modules added in the Program.gadgeteer designer view are used by typing 
            their name followed by a period, e.g.  button.  or  camera.
            
            Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
                button.ButtonPressed +=<tab><tab>
            
            If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
                GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
                timer.Tick +=<tab><tab>
                timer.Start();
            *******************************************************************************************/

            new Thread(sdCardTest).Start();

            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");
        }


        void sdCardTest()
        {

         // if necessary, check that SD is present here...

         SDCard sd_card = new SDCard();
 
         sd_card.Mount();
         bool fs_ready = false;
         RemovableMedia.Insert += (a, b) =>
         {
             fs_ready = true;
         };
         while (! fs_ready ) {
             System.Threading.Thread.Sleep(1);
         }

         // Assume only one storage device is available
          // and that the media is formatted
         string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;
         FileStream FileHandle = new FileStream(rootDirectory +
                                       @ "\hello.txt", FileMode.Create);
         byte[] data =
            Encoding.UTF8.GetBytes("This string will go in the file!");
         FileHandle.Write(data, 0, data.Length);
         FileHandle.Close();

         sd_card.Unmount();
        }
    }