Possible bug in MassStorage?

Excuse the messiness of the code below. I’m just messing around with auto-detecting USB cable connection, etc. Anyhow, if I instantiate ‘sd’ right before passing it to AttachLun everything works as expected and Windows sees the device/SD card. If I instantiate ‘sd’ in Main then when it is passed to AttachLun Windows ‘sees’ the SD card but it does not report the Volume label and it tells me the card is not formatted.

I guess in most usage cases you would already have the file system attached to the SD card so it would just be a matter of detaching the file system and passing it to AttachLun. I’ll try that next by instantiating ‘sd’ in Main and attaching the file system and then detaching the file system in my ‘attach’ method.

namespace Soigeneris
{
    enum MassStorageState { Dissconnected, Connected, Attached };

    public class Program
    {
        static USBC_MassStorage ms;
        static PersistentStorage sd;
        static ExtendedTimer updateTimer; // checks to see if LCD requires an update every 100ms
        static MassStorageState msState = MassStorageState.Dissconnected;

        public static void Main()
        {
            updateTimer = new ExtendedTimer(new TimerCallback(updateTimerHandler), null, 1000, 1000);

            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() == Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("Current debug interface is USB. It must be changed to something else before proceeding. Refer to your platform user manual to change the debug interface.");

            //sd = new PersistentStorage("SD"); // can't instantiate here
            ms = USBClientController.StandardDevices.StartMassStorage();  // Start MS

            // Assume SD card is connected
            //PersistentStorage sd;
            //try
            //{
            //    sd = new PersistentStorage("SD");
            //}
            //catch
            //{
            //    throw new Exception("SD card not detected");
            //}

            //// wait to connect to PC
            //while (USBClientController.GetState() != USBClientController.State.Running)
            //{
            //    Debug.Print("Waiting to connect to PC...");
            //    Thread.Sleep(1000);
            //}

            //ms.AttachLun(0, sd, " ", " ");

            //// enable host access 
            //ms.EnableLun(0);

            Thread.Sleep(Timeout.Infinite);
        }

        // Check USB cable connection state periodically
        static void updateTimerHandler(object target)
        {
            USBClientController.State crap = USBClientController.GetState();
            Debug.Print("State " + crap.ToString());

            // wait to connect to PC
            if (USBClientController.GetState() == USBClientController.State.Running
                & msState == MassStorageState.Dissconnected)
            {
                Debug.Print("USB cable has been connected.");
                msState = MassStorageState.Connected;
                attach();
            }
            //else if (USBClientController.GetState() != USBClientController.State.Running
            //    & msState != MassStorageState.Dissconnected)
            //{
            //    Debug.Print("USB cable was unplugged!");
            //    msState = MassStorageState.Dissconnected;
            //}
            //else if (USBClientController.GetState() == USBClientController.State.Running
            //    & msState != MassStorageState.Dissconnected)
            //{
            //    Debug.Print("USB cable is attached");
            //}
            //else
            //{
            //    Debug.Print("USB Cable is not connected.");
            //}
        }

        // Attach to PC as mass storage device if SD card is inserted
        static void attach()
        {
            Debug.Print("Making sure SD card is really there.");
            if (PersistentStorage.DetectSDCard())
            {
                sd = new PersistentStorage("SD"); // instantiate here and it works?
                ms.AttachLun(0, sd, " ", " ");
                ms.EnableLun(0); // enable host access
                msState = MassStorageState.Attached;
                Debug.Print("Attached as MassStorage device now.");
            }
            else
            {
                Debug.Print("Please Insert SD card!");
            }
        }

    }
}

It looks the same either way… I am not what I missed.
Can you try something more simple in few lines of code and see if you have problems, like:
main()
{
sd = new PersistantStorage()…
StartMassStorage()…
AttachLun()…
EnableLun()…
Thread.Sleep(-1);
}

That works Mike.

I also tried moving the AttachLun and EnableLun into a seperate static function and call it after instantiating sd and ms and it works fine. Seems to be related to be related to using the timer. If I dispose and newup sd again in my ‘attach’ method it works fine.

Another tidbit of information. I changed things around so that the ‘attach’ just sets a flag to indicates that the USB cable is connected. So the main thread just hangs out in a while loop until it sees the flag. This works! It has to be something related to trying to do this stuff via the timer thread even though the variables used are all in scope.

I wonder what would happen if I instantiate sd from the timer thread?

            sd = new PersistentStorage("SD");
            ms = USBClientController.StandardDevices.StartMassStorage();  // Start MS
            ms.AttachLun(0, sd, " ", " ");
            sd.MountFileSystem();

            while (attached == false)
            {
                
            }

            Debug.Print("Will now enable");
            sd.UnmountFileSystem();
            ms.EnableLun(0);

maybe it is the PersistentStorage.DetectSDCard() in timer thread
Try the code without it.

That was it Mike…if I remove the PersistentStorage.DetactSDCard() it works fine. Any idea why it is causing problems?

Edit: I have tried this again this morning and the USBClientController DOES indeed change when the USB cable is unplugged.

Here is something else I just noticed.

This: USBClientController.GetState(), will change state when the USB cable is plugged in, but not when the USB cable is removed. Full test program is below.

    public class Program
    {
        static USBC_MassStorage ms;
        static PersistentStorage sd;

        public static void Main()
        {
            sd = new PersistentStorage("SD");
            ms = USBClientController.StandardDevices.StartMassStorage();  // Start MS
            ms.AttachLun(0, sd, " ", " ");
            ms.EnableLun(0);

            // wait to connect to PC
            while (true)
            {
                Debug.Print("State " + USBClientController.GetState().ToString());
                Thread.Sleep(1000);
            }

            //Storage myStorage = new Storage();
            //Thread.Sleep(Timeout.Infinite);
        }

    }

Not sure if Detect SD is the problem. We will test here and see what we can find out.

I’ve been playing with this again and it seems that IFF you call “PersistentStorage.DetectSDCard()” from a separate thread if screws things up. If I don’t call it the USBClientController state changes as it should. I think the only option I have not tried is declaring

        static USBC_MassStorage ms;
        static PersistentStorage sd;

in a separate class and instantiating them from the ExtendedTimer event in that same class. Then I could provide references to the main thread for the SD card or not depending on the USB cable connection state.

BTW, I have also noticed that you cannot have two ‘code’ tags in the same post.

… that you could not have…

Seems like this one was the daily joke :wink:

#1

static USBC_MassStorage ms;
static PersistentStorage sd;

#2

 static USBC_MassStorage ms;
static PersistentStorage sd;

Tanks Josh :wink:

Surprise?

Well, it is definitely something to do with calling DetectSDCard in the update timer thread. Interestingly enough I created a second timer that fires every 500ms and just have it update a flag to indicated if the SD card is inserted or not, it works fine. The test code is below, the basic idea is to be able to automatically detect the state of the SD card and USB connection so that events can be fired that other parts of the program can respond to.

 using System;
using System.IO;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.Hardware;

namespace Soigeneris
{
    enum MassStorageState { Default, Connected, Dissconnected, Attached };
    enum SDState { Default, Empty, Inserted, Removed };

    public class Storage
    {
        static USBC_MassStorage ms;
        static PersistentStorage sd;
        static ExtendedTimer updateTimer;
        static ExtendedTimer sdTimer;
        static MassStorageState msState = MassStorageState.Default;
        static SDState sdState = SDState.Default;
        static bool sdInserted = false;
        USBClientController.State lastState = USBClientController.State.Default;

        public Storage()
        {
            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() == Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("ERROR: Current debug interface is USB!");

            updateTimer = new ExtendedTimer(new TimerCallback(updateTimerHandler), null, 2000, 1000);
            sdTimer = new ExtendedTimer(new TimerCallback(sdTimerHandler), null, 1000, 500);
            ms = USBClientController.StandardDevices.StartMassStorage();
        }

        // Check USB cable connection state periodically
        void updateTimerHandler(object target)
        {
            USBClientController.State newState = USBClientController.GetState();
            if (newState != lastState)
            {
                Debug.Print("State " + newState.ToString());
                lastState = newState;
            }

            // SD card inserted so mount file system
            if (!sdInserted & sdState == SDState.Default)
            {
                Debug.Print("SD card has not yet been inserted, first pass");
                sdState = SDState.Empty;
            }
            else if (sdInserted & sdState != SDState.Inserted)
            {
                Debug.Print("SD card has been inserted");
                sd = new PersistentStorage("SD");
                sd.MountFileSystem();
                sdState = SDState.Inserted;
            }
            else if (!sdInserted & sdState == SDState.Inserted)
            {
                Debug.Print("SD card has been removed");
                try
                {
                    sd.UnmountFileSystem();
                }
                catch
                {
                    Debug.Print("SD file system was not moounted");
                }
                sd.Dispose();
                sdState = SDState.Removed;
            }

            // wait to connect to PC
            USBClientController.State USBState = USBClientController.GetState();
            if (USBState != USBClientController.State.Running & msState == MassStorageState.Default)
            {
                Debug.Print("USB Cable has not yet been attached");
                msState = MassStorageState.Dissconnected;
            }
            else if (USBState == USBClientController.State.Running & msState == MassStorageState.Dissconnected)
            {
                Debug.Print("USB cable has been connected");
                msState = MassStorageState.Connected;
                attach();
            }
            else if (USBState != USBClientController.State.Running & msState == MassStorageState.Connected)
            {
                Debug.Print("USB cable has been dissconnected");
                msState = MassStorageState.Dissconnected;
            }

        }

        // Attach to PC as mass storage device if SD card is inserted
        void attach()
        {
            if (sdState == SDState.Inserted)
            {
                sd.UnmountFileSystem();
                ms.AttachLun(0, sd, " ", " ");
                ms.EnableLun(0); // enable host access
                msState = MassStorageState.Attached;
                Debug.Print("Attached as MassStorage device now.");
            }
            else
            {
                Debug.Print("SD Card is not inserted, cannot create MSD");
            }
        }

        void sdTimerHandler(object target)
        {
            sdInserted = PersistentStorage.DetectSDCard();
        }

    }
}

We cannot reproduce the problem here. It could’ve been a simple bug in your C# application.
If you can make a small application that reproduces the problem, we can look into it.

Here is a simple example, there are two methods of attaching the lun. Comment/uncomment the proper lines to use either ‘attach1()’ or ‘attach2’. If you use ‘attach190’ you must re-new sd or it will not actually create the mass storage device properly. If you just don’t use the ‘PersistentStorage.DetectSDCard())’ method as shown in ‘attach2()’ then it works fine.

using System;
using System.IO;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.Hardware;

namespace SDDetectError
{
    enum MassStorageState { Dissconnected, Connected, Attached };

    public class Program
    {
        static USBC_MassStorage ms;
        static PersistentStorage sd;
        static ExtendedTimer updateTimer; // checks to see if LCD requires an update every 100ms
        static MassStorageState msState = MassStorageState.Dissconnected;

        public static void Main()
        {
            updateTimer = new ExtendedTimer(new TimerCallback(updateTimerHandler), null, 1000, 1000);

            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() == Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("Current debug interface is USB. It must be changed to something else before proceeding. Refer to your platform user manual to change the debug interface.");

            ms = USBClientController.StandardDevices.StartMassStorage();  // Start MS
            sd = new PersistentStorage("SD");
            ms.AttachLun(0, sd, " ", " "); // uncomment for attach2

            Thread.Sleep(Timeout.Infinite);
        }

        // Check USB cable connection state periodically
        static void updateTimerHandler(object target)
        {
            USBClientController.State state = USBClientController.GetState();
            Debug.Print("State " + state.ToString());

            // wait to connect to PC
            if (state == USBClientController.State.Running
                & msState == MassStorageState.Dissconnected)
            {
                Debug.Print("USB cable has been connected.");
                msState = MassStorageState.Connected;
                //attach1(); // comment out one of these and use the other
                attach2(); // to use attach2 you must also uncomment the ms.attach line in Main()
            }
        }

        // Attach to PC as mass storage device if SD card is inserted
        static void attach1()
        {
            Debug.Print("Making sure SD card is really there.");
            if (PersistentStorage.DetectSDCard())
            {
                // re-new SD here and you'll get a mass storage device
                sd.Dispose();
                sd = new PersistentStorage("SD"); // instantiate here and it works?
                ms.AttachLun(0, sd, " ", " ");


                ms.EnableLun(0); // enable host access
                msState = MassStorageState.Attached;
                Debug.Print("Attached as MassStorage device now.");
            }
            else
            {
                Debug.Print("Please Insert SD card!");
            }
        }

        static void attach2()
        {
            ms.EnableLun(0); // enable host access
            msState = MassStorageState.Attached;
            Debug.Print("Attached as MassStorage device now.");

        }

    }

}

This is still working fine here. Where do you see the problem? Of Course if you eject and insert the SD card, you will have problems because this is not handled in code…
Other than this, maybe DetectSDCard messing up the SD card you are using try other brands.

If you comment out the ‘sd.dispose’ and the ‘sd = new’ then the attach one method will not work. I’m not removing/reinstalling the SD card. The SD card is inserted, the program is run in debug mode, and the USB cable is plugged in.

To avoid confusion of what to comment out for each attach method, here is the version that exhibits the problem.

To duplicate error

  1. Plug in SD card
  2. Run program in debug mode
  3. Plug-in USB cable

Using this method I never see the FEZ appear properly as an MSD. If you let it set for about a minute a dialog box pops up on the PC that says the device must be formatted before it can be used. I’m using VS2008 Pro, the GHI Beta SDK, and Win7 with a Transcend 2 GB uSD card.

This could be an issue with a particualr uSD card BUT if I call ‘PersistentStorage.DetectSDCard’ in a seperate thread then everything is fine. If you do all of this in the same function, i.e. don’t use the timer thread, it works fine. The problem seems to be when calling ‘PersistentStorage.DetectSDCard’ in the same timer thread that the ms.attach in done in.

using System;
using System.IO;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.USBClient;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.Hardware;

namespace SDDetectError
{
    enum MassStorageState { Dissconnected, Connected, Attached };

    public class Program
    {
        static USBC_MassStorage ms;
        static PersistentStorage sd;
        static ExtendedTimer updateTimer; // checks to see if LCD requires an update every 100ms
        static MassStorageState msState = MassStorageState.Dissconnected;

        public static void Main()
        {
            updateTimer = new ExtendedTimer(new TimerCallback(updateTimerHandler), null, 1000, 1000);

            // Check debug interface
            if (Configuration.DebugInterface.GetCurrent() == Configuration.DebugInterface.Port.USB1)
                throw new InvalidOperationException("Current debug interface is USB. It must be changed to something else before proceeding. Refer to your platform user manual to change the debug interface.");

            ms = USBClientController.StandardDevices.StartMassStorage();  // Start MS
            sd = new PersistentStorage("SD");
            ms.AttachLun(0, sd, " ", " "); // uncomment for attach2

            Thread.Sleep(Timeout.Infinite);
        }

        // Check USB cable connection state periodically
        static void updateTimerHandler(object target)
        {
            USBClientController.State state = USBClientController.GetState();
            Debug.Print("State " + state.ToString());

            // wait to connect to PC
            if (state == USBClientController.State.Running
                & msState == MassStorageState.Dissconnected)
            {
                Debug.Print("USB cable has been connected.");
                msState = MassStorageState.Connected;
                attach1(); // comment out one of these and use the other
            }
        }

        // Attach to PC as mass storage device if SD card is inserted
        static void attach1()
        {
            Debug.Print("Making sure SD card is really there.");
            if (PersistentStorage.DetectSDCard())
            {
                ms.EnableLun(0); // enable host access
                msState = MassStorageState.Attached;
                Debug.Print("Attached as MassStorage device now.");
            }
            else
            {
                Debug.Print("Please Insert SD card!");
            }
        }

    }

}

Thank you, we found the problem.
The first time DetectSDCard() runs, it resets the SD card power, so it messing it up.
Put this at the start of your program and it should fine.
PersistentStorage.DetectSDCard();

Cool! I had tried all sorts of combinations to determine the problem but had not hit on that. It explains why when I was calling PersistentStorage.DetectSDCard(); in a separate timer thread, that fired twice as often as the main timer thread things worked properly. Now I can rework my class that fires events when the state of the SD card and/or USB Client state.

Thanks!