Switching Between WinUSB and MassStorage USB Modes

Hi Dat,
I built with your updated code, this is first run, on a Portal.
First button press, switches to WinUSB.
Second button press, exception.

Attaching deployed file.

   Assembly: mscorlib (2.2.0.7000)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.UsbClient (2.2.0.7000)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Native (2.2.0.7000)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.Gpio (2.2.0.7000)  Attaching deployed file.

   Assembly: MscWinUsbSwitch (1.0.0.0)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.Storage (2.2.0.7000)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.Usb (2.2.0.7000)  Resolving.

The debugging target runtime is loading the application assemblies and starting execution.
Ready.

'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\mscorlib.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.Usb.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\GHIElectronics.TinyCLR.Native.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.UsbClient.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.Gpio.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.Storage.dll'
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'f:\src\MscWinUsbSwitch\bin\Debug\pe\..\MscWinUsbSwitch.exe', Symbols loaded.
The thread '<No Name>' (0x2) has exited with code 0 (0x0).
Press PB7 to start testing...
WinUsb Starting... please wait
WinUsb Started
Memory free: 355504
Stop WinUsb... please wait
Please wait for WinUsb stop.... 
WinUsb Stopped
    #### Exception System.InvalidOperationException - CLR_E_INVALID_OPERATION (1) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.UsbClient.Provider.UsbClientControllerApiWrapper::Release [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.UsbClient.Provider.UsbClientControllerApiWrapper::Dispose [IP: 0004] ####
    #### GHIElectronics.TinyCLR.Devices.UsbClient.UsbClientController::Dispose [IP: 0007] ####
    #### MscWinUsbSwitch.Program::Main [IP: 00cd] ####
Exception thrown: 'System.InvalidOperationException' in GHIElectronics.TinyCLR.Devices.UsbClient.dll
An unhandled exception of type 'System.InvalidOperationException' occurred in GHIElectronics.TinyCLR.Devices.UsbClient.dll

I will check, probably I ran this code on fixed version.

But I just found interested thing, with this uSD, it only takes 7 seconds instead of 25 seconds on my home PC. About 4 time faster. I will verify this when back to office.

16GB micro SD MicroSD Card Samsung EVO - Galaxy Note Nintendo Switch LG Android | eBay

That’s interesting. I don’t have any hard data on connection times in MassStorage USB mode with various uSD makes and sizes, my main concern has been that they work reliably with the devices.

Back with the EMX only certain brands would work, and we had a list of which ones could be used.

Common ones were Transcend, Kingston and Verbatim, but then a whole lot of flakey knock-off versions started to appear online and you didn’t know what you were going to get.

I currently have SanDisk Ultra in the 32GB and Samsung Evo Plus in the 64GB.
As our storage requirement would be <10MB/year, even if we didn’t delete the data files after upload at the end of each shift, this is massive over-provisioning!

It would be good to get some data on how not only manufacturer and size, but also partition size and format used impact the time it takes for the device to be recognized by the PC.

Hello, I think I figured out.

Good thing is not on SDCard, not SITCore, follow these steps it will speed up from 25 seconds to 7 seconds. There are two steps, each step reduces ~50% time.

  1. Change GPT to MBR.
  2. Format with 32KB Allocation Unit Size.

Change GPT to MBR
If you already have MBR on your SD then you don’t need this step.

You can use any way that you feel good to change GPT to MBR. I am using the script below:

You can type exit from DISKPART window to close this window.

2 Format with 32KB Allocation Unit Size.

Now, use window to format with 32K Allocation Unit Size. I am using Window 11 but I think Window 10 does same thing. Some cards offer 64K but I don’t see different, so 64K just waste room on the card.

Each SDCard has different result, it will be 1-2 secs different, of course. But basically, if original format:
32G: 26 sec → step1 → 13 sec-> step2 → 7 seconds.
8G/16G: 20 sec → step1-> 10 sec-> step2-> 5 seconds
4G: 15 sec → step1-> 7 sec → step2-> 3 seconds.

I don’t have smaller 2G but small will be faster. With 4GB, I can show the drive on Window 10/11 < 4 seconds. Now it makes sense to me that couple years ago we have 2-4G SDCard, with MBR as default then take only few seconds.

Please test this only (try with new project - simple code), make sure you have same result with me. This test result is happened with all SDcard I have now, no matter what branch is, and I am using 2.2.0.7000. You MUST have same result :).

For other issues like memory leak, if you want to test, I am willing to send test fw, but after this, one thing at the time. I don’t want to be confused new-old version.

Did you find the problem here? To get us on the same page I need to be able to run the same code as you, if yours only works with firmware I don’t have I can’t do that.

Re MBR vs GPT, I’ll give it a try.
I’ve just been through this with the uSD card my Tesla uses for TeslaCam/Sentry, with the recommendation being to swap from MBR to GPT to avoid problems with corruption on the drive!

I’ve run a few tests, using 3 different uSD cards on two different PCs, all running on a Portal under debugger.
Test code was a modified version of my WinUSB/MassStorage switch test with the WinUSB removed so it just turns MassStorage on and off, and a timer to see how long things take. I’ll attach the source below.

All uSD cards were partitioned as MBR and formatted as FAT32 with 32k allocation units.

Card 1: 32GB Verbatim
Card 2: 32GB SanDisk Ultra
Card 3: 64GB Samsung EVO Plus partitioned to 2GB

Results:

=

1. 32GB uSD 1 (Verbatim), FAT32, 32k allocation units, FEZ Portal, Windows 10 PC
----------------------------------------------------------------------
Want Mass Storage
MassStorage changed to Attached 0.093 Sec
MassStorage changed to Suspended 0.100 Sec
MassStorage Started 0.107 Sec
MassStorage changed to Default 0.233 Sec
MassStorage changed to Address 0.284 Sec
MassStorage changed to Configured 0.341 Sec
MassStorage changed to Default 15.911 Sec
MassStorage changed to Address 21.007 Sec
MassStorage changed to Configured 21.021 Sec

2. 64GB uSD (Samsung EVO plus) paritioned to 2GB, FAT32, 32k allocation units, FEZ Portal, Windows 10 PC
-------------------------------------------------------------------------------------
Want Mass Storage
MassStorage changed to Attached 0.262 Sec
MassStorage changed to Suspended 0.269 Sec
MassStorage Started 0.276 Sec
MassStorage changed to Default 0.364 Sec
MassStorage changed to Address 0.413 Sec
MassStorage changed to Configured 0.482 Sec
MassStorage changed to Default 21.492 Sec
MassStorage changed to Address 26.588 Sec
MassStorage changed to Configured 26.601 Sec
MassStorage changed to Default 50.002 Sec
MassStorage changed to Address 55.099 Sec
MassStorage changed to Configured 55.113 Sec

3. 32GB uSD 2 (SanDisk Ultra), FAT32, 32k allocation units, FEZ Portal, Windows 10 PC
----------------------------------------------------------------------
MassStorage changed to Attached 0.286 Sec
MassStorage changed to Suspended 0.293 Sec
MassStorage Started 0.300 Sec
MassStorage changed to Default 0.391 Sec
MassStorage changed to Address 0.439 Sec
MassStorage changed to Configured 0.522 Sec
MassStorage changed to Default 16.188 Sec
MassStorage changed to Address 21.286 Sec
MassStorage changed to Configured 21.301 Sec

4. 32GB uSD 2 (SanDisk Ultra), FAT32, 32k allocation units, FEZ Portal, Windows 11 PC
----------------------------------------------------------------------
MassStorage changed to Attached 0.263 Sec
MassStorage changed to Suspended 0.270 Sec
MassStorage Started 0.277 Sec
MassStorage changed to Default 0.361 Sec
MassStorage changed to Address 0.448 Sec
MassStorage changed to Configured 0.491 Sec
MassStorage changed to Default 15.801 Sec
MassStorage changed to Address 20.986 Sec
MassStorage changed to Configured 20.998 Sec

5. 32GB uSD 1 (Verbatim), FAT32, 32k allocation units, FEZ Portal, Windows 11 PC
----------------------------------------------------------------------
Want Mass Storage
MassStorage changed to Attached 0.126 Sec
MassStorage changed to Suspended 0.133 Sec
MassStorage Started 0.139 Sec
MassStorage changed to Default 0.224 Sec
MassStorage changed to Address 0.312 Sec
MassStorage changed to Configured 0.355 Sec
MassStorage changed to Default 15.661 Sec
MassStorage changed to Address 20.850 Sec
MassStorage changed to Configured 20.861 Sec

6. 64GB uSD (Samsung EVO plus) paritioned to 2GB, FAT32, 32k allocation units, FEZ Portal, Windows 11 PC
-------------------------------------------------------------------------------------
Want Mass Storage
MassStorage changed to Attached 0.244 Sec
MassStorage changed to Suspended 0.251 Sec
MassStorage Started 0.258 Sec
MassStorage changed to Default 0.341 Sec
MassStorage changed to Address 0.430 Sec
MassStorage changed to Configured 0.468 Sec
MassStorage changed to Default 15.771 Sec
MassStorage changed to Address 20.964 Sec
MassStorage changed to Configured 20.976 Sec

Note that in each case the state change to Configured at around the 20 second mark was when the drive first appeared in the Windows Explorer window.
In each case the device went through another Configured->Default->Address->Configured at around the 50 second mark, I didn’t bother capturing the timing for all of them.

Test code as follows, you can ignore the WinUSB stuff as it isn’t used, but makes it easy to change back to the WinUSB/MassStorage switch problem we are actually trying to solve.

using System;
using System.Diagnostics;
using System.Threading;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Devices.UsbClient;


namespace TinyCLRMassStorageSwitchTest
{
    internal class Program
    {
        static UsbClientController usbclientController;
        static MassStorage ms = null;
        static StorageController sd;
        static WinUsb winUsb = null;
        static UsbClientSetting usbClientSetting;
        static UsbClientSetting MsClientSetting;
        static bool WantUsb = false;
        static bool WantMs = false;


        public const int LeftButton = SC20260.GpioPin.PF10;
        public const int RightButton = SC20260.GpioPin.PF8;
        public const int DownButton = SC20260.GpioPin.PE3;
        public const int UpButton = SC20260.GpioPin.PB7;

        public const int GLedFader = SC20260.GpioPin.PB0;
        public const int RLedFader = SC20260.GpioPin.PB1;

        private static GpioPin ButtonLeft, ButtonRight, ButtonDown, ButtonUp;
        private static GpioPin GLed, RLed;

        static DateTime startTime;

        static void Main()
        {
            var gpio = GpioController.GetDefault();

            // Left button  = set to WinUSB mode
            // Right button = set to MassStorage mode
            ButtonLeft = gpio.OpenPin(LeftButton);
            ButtonLeft.SetDriveMode(GpioPinDriveMode.InputPullUp);
            ButtonLeft.ValueChangedEdge = GpioPinEdge.FallingEdge;
            ButtonLeft.ValueChanged += ButtonLeft_OnInterrupt;
            ButtonRight = gpio.OpenPin(RightButton);
            ButtonRight.SetDriveMode(GpioPinDriveMode.InputPullUp);
            ButtonRight.ValueChangedEdge = GpioPinEdge.FallingEdge;
            ButtonRight.ValueChanged += ButtonRight_OnInterrupt;

            ButtonDown = gpio.OpenPin(DownButton);
            ButtonDown.SetDriveMode(GpioPinDriveMode.InputPullUp);
            ButtonDown.ValueChangedEdge = GpioPinEdge.FallingEdge;
            ButtonDown.ValueChanged += ButtonDown_OnInterrupt;
            ButtonUp = gpio.OpenPin(UpButton);
            ButtonUp.SetDriveMode(GpioPinDriveMode.InputPullUp);
            ButtonUp.ValueChangedEdge = GpioPinEdge.FallingEdge;
            ButtonUp.ValueChanged += ButtonUp_OnInterrupt;

            GLed = gpio.OpenPin(GLedFader);
            RLed = gpio.OpenPin(RLedFader);
            GLed.SetDriveMode(GpioPinDriveMode.Output);
            RLed.SetDriveMode(GpioPinDriveMode.Output);

            usbClientSetting = new UsbClientSetting()
            {
                Mode = UsbClientMode.WinUsb,
                ManufactureName = "C-Born Software Systems",
                ProductName = "Anode Drop Meter",
                SerialNumber = "2",
                //Guid = "{77C99034-2428-424a-8130-DC481841429B}",  // Works with NETMF, Doesn't work with GHI TinyCLR (yet?)
                //Guid = "{88BAE032-5A81-49f0-BC3D-A4FF138216D6}",  // Class GUID "USBDevice"
                Guid = "{a5dcbf10-6530-11d2-901f-00c04fb951ed}",    // Interface GUID GUID_DEVINTERFACE_USB_DEVICE = "Attached to a Hub"
                VendorId = 0x1234,
                ProductId = 0x0002,
                MaxPower = 500,
                InterfaceName = "SitCore Based Anode Meter"
            };

            MsClientSetting = new UsbClientSetting()
            {
                VendorId = 7071,
                ProductId = 61442,
                BcdUsb = 528,
                BcdDevice = 256,
                MaxPower = 250,
                ManufactureName = "C-Born Software Systems",
                ProductName = "Anodemeter uSD",
                SerialNumber = "1",
                InterfaceName = "Mass Storage",
                Mode = UsbClientMode.MassStorage
            };
            
            /* Loop around switching between WinUSB (Left Button) and MassStorage (Right Button)
             * 
             * Note that we can switch from MassStorage to WinUSB with cable plugged in,
             * but only changes from WinUSB to MassStorage if cable unplugged.
             * 
             * Is there something more that needs to be done, or is this a bug in TinyCLR?
             */

            while (true)
            {   
                if(WantUsb)
                {
                    StopMs();
//                    StartWinUsb();
                } else if(WantMs)
                {
//                    StopWinUsb();
                    StartMs();
                }

                CheckUsb();
                Thread.Sleep(100);
            }
        }
        // Start Mass Storage
        static void StartMs()
        {
            if (ms != null) return;
            StartTimer();
            usbclientController = UsbClientController.GetDefault();
            ms = new MassStorage(usbclientController,MsClientSetting);
            //ms = new MassStorage(usbclientController);
            sd = StorageController.FromName(SC20100.StorageController.SdCard);
            ms.DeviceStateChanged += Ms_DeviceStateChanged;
            ms.AttachLogicalUnit(sd.Hdc);
            ms.Enable();
            Debug.WriteLine("MassStorage Started " + ElapsedTime());
        }
        // Stop Mass Storage
        static void StopMs()
        {
            if(ms == null) return;
            ms.Disable();
            ms.RemoveLogicalUnit(sd.Hdc);
            ms.DeviceStateChanged -= Ms_DeviceStateChanged;
            ms.Dispose();
            ms = null;
            Thread.Sleep(5000);
            Debug.WriteLine("MassStorage Stopped");
        }
        // Start WinUSB
        static void StartWinUsb()
        {
            if (winUsb != null) return;
            StartTimer();
            usbclientController = UsbClientController.GetDefault();
            winUsb = new WinUsb(usbclientController, usbClientSetting);
            winUsb.DeviceStateChanged += Usb_DeviceStateChanged;
            winUsb.DataReceived += Usb_DataReceived;
            winUsb.Enable();
            Debug.WriteLine("WinUsb Started");
        }
        //Stop WinUSB
        static void StopWinUsb()
        {
            if (winUsb == null) return;
            winUsb.Disable();
            winUsb.DeviceStateChanged -= Usb_DeviceStateChanged;
            winUsb.DataReceived -= Usb_DataReceived;
            winUsb.Dispose();
            winUsb = null;
            Thread.Sleep(5000);
            Debug.WriteLine("WinUsb Stopped");
        }

        //******** Event Handlers **********
        static void ButtonLeft_OnInterrupt(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            Debug.WriteLine("Want WinUSB Mode");
            WantMs = false;
            WantUsb = true;  
        }
        static void ButtonRight_OnInterrupt(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            Debug.WriteLine("Want Mass Storage");
            WantUsb = false;
            WantMs = true;
        }
        static void ButtonDown_OnInterrupt(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            Debug.WriteLine("Want Mass Storage");
            WantUsb = false;
            WantMs = true;
        }
        static void ButtonUp_OnInterrupt(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            Debug.WriteLine("Want WinUSB Mode");
            WantMs = false;
            WantUsb = true;
        }

        private static void Ms_DeviceStateChanged(RawDevice sender, DeviceState state)
        {
            Debug.WriteLine("MassStorage changed to " + GetEnumName(state) + " " + ElapsedTime());
        }
        private static void Usb_DeviceStateChanged(RawDevice sender, DeviceState state)
        {
            Debug.WriteLine("WinUsb changed to " + GetEnumName(state));
        }
        private static void Usb_DataReceived(RawDevice sender, uint count)
        {
            Debug.WriteLine("Data received:" + count);
        }


        // WinUSB Send/Receive - Echo back characters received, incremented by 1
        static void CheckUsb()
        {
            if ((winUsb != null) && (winUsb.DeviceState == DeviceState.Configured))
            {
                var len = winUsb.Stream.BytesToRead;
                if (len > 0)
                {
                    var dataR = new byte[len];
                    var dataW = new byte[len];
                    int read = winUsb.Stream.Read(dataR);

                    for (var i = 0; i < read; i++)
                    {
                        dataW[i] = (byte)(dataR[i] + 1);
                    }
                    winUsb.Stream.Write(dataW);
                }
            }
        }
        static string GetEnumName(DeviceState state)
        {
            switch (state)
            {
                case DeviceState.Detached: return "Detached";
                case DeviceState.Attached: return "Attached";
                case DeviceState.Powered: return "Powered";
                case DeviceState.Default: return "Default";
                case DeviceState.Address: return "Address";
                case DeviceState.Configured: return "Configured";
                case DeviceState.Suspended: return "Suspended";
                default: return state.ToString(); // Fallback to default ToString() behavior
            }
        }

        static string ElapsedTime()
        {
            TimeSpan elapsed = DateTime.Now - startTime;
            return elapsed.TotalSeconds.ToString("F3") + " Sec";
            //return elapsed.ToString();
        }
        static void StartTimer()
        {
            startTime = DateTime.Now;
        }
    }
}

Your test is complex for testing this, make new project and just few lines of code.

I don’t have device here so I can’t give you the “run” example, but ideally is:

static void main() 
{
     startMsc();
}

That is it. Disconnect / reconnect usb cable, hold mode button to make sure device is in serial mode, and you can check time on your watch to see how long PC show a new drive. After PC show new drive, make sure you can read/write into the drive.

StartMsc should be simple like this:

static void StartMs()
        {
           
            usbclientController = UsbClientController.GetDefault();
            ms = new MassStorage(usbclientController);
            sd = StorageController.FromName(SC20100.StorageController.SdCard);
            ms.DeviceStateChanged += Ms_DeviceStateChanged;
            ms.AttachLogicalUnit(sd.Hdc);
            ms.Enable();
            Debug.WriteLine("MassStorage Started");
        }

Can you tell me the reason you use BcdUsb = 528?
Try with 4,8,16, 32GB. I don’t have 64 so I am not sure how 64G is but smaller will be faster. Are they switched to MBR yet?

Hi Dat,

I ran the tests using a version of your simple code (only corrected so it would compile and not immediately terminate), see below for reference.

Windows 11 box is a fast new PC with 32GB RAM and running no other load
Windows 10 box is an older PC with 24GB RAM, running many processes including VMs, so expect to be slower.

uSD all partitioned MBR, formatted FAT32, 32K allocation unit
I managed to find one old 8GB uSD, which was the fastest, although the Samsung 64GB formatted to have only a 2GB partition came close. As mentioned previously, 64GB is the smallest I can find to buy these days.

Tests with Simple Msc Code and stopwatch
========================================
Time from plugging Portal in until drive appears in Explorer window

1. Windows 11
64GB Samsung EVO	27.24 Sec
32GB Verbatim     32.19 Sec
32GB Sandisk      30.59 Sec
 8GB Unbranded    25.66 Sec (New to test, MBR, FAT32, 32K Allocation Unit Size)
 
2. Windows 10
64GB Samsung EVO	29.26 Sec
32GB Verbatim     33.72 Sec
32GB Sandisk      35.77 Sec
 8GB Unbranded    29.52 Sec 

Code used:

using System;
using System.Diagnostics;
using System.Threading;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Storage;
using GHIElectronics.TinyCLR.Devices.UsbClient;

namespace TinyCLRSimpleMSTest
{
    internal class Program
    {
        static void Main()
        {
            StartMs();

            for (;;)
            {
                Thread.Sleep(1000);
            }
        }
        static void StartMs()
        {
            var usbclientController = UsbClientController.GetDefault();
            var ms = new MassStorage(usbclientController);
            var sd = StorageController.FromName(SC20100.StorageController.SdCard);
            //ms.DeviceStateChanged += Ms_DeviceStateChanged;
            ms.AttachLogicalUnit(sd.Hdc);
            ms.Enable();
            Debug.WriteLine("MassStorage Started");
        }
    }
}

Could you try running my previous example code when you get into work? It isn’t really that complex!
I’m using the two buttons on the Portal, the other two (from our hardware, coming from EMX and G120) can be ignored.
Pay attention to the way the MassStorage cycles through various states. Something isn’t right there.
If you are watching on device Manager it looks like it sees it come and go and return again, too. Which slows the whole recognition thing down. Clients are reporting that it can appear as a drive on their PC, then disappear, then come back (or not). I’ve just got another three of the TinyCLR versions back for “repair”, we don’t have these problems with the NETMF based versions (EMX and G120)

Regarding the BcdUsb = 528, that comes from the default setting in the GHI USBclient

#region Assembly GHIElectronics.TinyCLR.Devices.UsbClient, Version=2.2.0.7000, Culture=neutral, PublicKeyToken=null
// F:\src\TinyCLRMassStorageSwitchTest\packages\GHIElectronics.TinyCLR.Devices.UsbClient.2.2.0.7000\lib\net48\GHIElectronics.TinyCLR.Devices.UsbClient.dll
// Decompiled with ICSharpCode.Decompiler 8.1.1.7464
#endregion

namespace GHIElectronics.TinyCLR.Devices.UsbClient;

public class UsbClientSetting
{
    public UsbClientMode Mode { get; set; }

    public string ManufactureName { get; set; }

    public string ProductName { get; set; }

    public string SerialNumber { get; set; }

    public string Guid { get; set; }

    public ushort ProductId { get; set; }

    public ushort VendorId { get; set; } = 7071;


    public ushort BcdUsb { get; set; } = 528;


    public ushort BcdDevice { get; set; }

    public ushort MaxPower { get; set; }

    public string InterfaceName { get; set; }
}

It defines the USB standard compliance as 2.10 (528 = 0x210) for our WinUSB
Not used in the MassStorage code we are looking at now, however.

1 Like

This movie will help me to tell you everything: (11) PXL 20240315 132257887 - YouTube

I ran your code exactly, not modify anything. You can see, about 3-4 seconds, new drive opens on Window and I can copy/delete file as well. I switched to WinUSB, then back Msc, it just works and same speed.

What I can see the different between your PC and my PC is, on your PC, seems it enumerate the device multiple times to get it done, on my PC, just need only one time.

On my PC, only one Configured :

Want Mass Storage
MassStorage changed to Attached 0.094 Sec
MassStorage changed to Suspended 0.101 Sec
MassStorage Started 0.108 Sec
MassStorage changed to Default 0.195 Sec
MassStorage changed to Address 0.251 Sec
MassStorage changed to Configured 0.273 Sec

On your PC, need two configured

Want Mass Storage
MassStorage changed to Attached 0.093 Sec
MassStorage changed to Suspended 0.100 Sec
MassStorage Started 0.107 Sec
MassStorage changed to Default 0.233 Sec
MassStorage changed to Address 0.284 Sec
MassStorage changed to Configured 0.341 Sec
MassStorage changed to Default 15.911 Sec
MassStorage changed to Address 21.007 Sec
MassStorage changed to Configured 21.021 Sec

We will look a bit more to see if anything we can do.

Clients are reporting that it can appear as a drive on their PC, then disappear, then come back (or not)

This could be different issue. Do you see this issue on Portal now? I haven’t seen this issue happen on mine. But I have seen a lot from… my phone (also use type C). When my phone has this issue, I try different USB port on PC or change a different cable.

Is your client using custom board?

Hi Dat,

Thanks for doing that test, hopefully it has put us on the road to a solution!

Just to re-state the problems, we have

  1. The inability (at least on some PCs) to switch between MassStorage and WinUSB modes without a reboot or power cycle
  2. Slow and inconsistent MassStorage connection (again on some PCs)

It is possible that these are connected, and possibly 2) is caused by 1), and may also have helped to hide it’s diagnosis.

After seeing your test results, using identical hardware and software to what I was using, I tried the tests on a few more PCs. These were running Windows Home rather than Windows Pro, and were not connected to a Domain. This may or may not be of significance, more on that later.

However on these PCs I saw what you were seeing, the connection was almost immediate, directory came up on Windows Explorer in 4 seconds, there was no dropping in and out.

But what I also noticed (thanks to the stability of the connection) was that when the call was made to stop the MassStorage, it didn’t go away on the PC! In fact it only went away when the program was restarted, power was cycled, or the connection was pulled.

I then took a look to see if there was a way to force the connection to be dropped (some documentation would be nice) and the only thing I could think to try was a Dispose() on the UsbClientController, as that was the only other method I could see on it (no Stop() for example). However that just caused an exception in the DLL.

So I’m hopeful that if this issue can be fixed, it could solve problem 1), but that still leaves 2)

My first thought was that it could be a difference between Windows Pro and Windows Home. My test machines were all Windows Pro, attached to a domain, same as our clients, and they all had the problem. Yet all the Windows Home PCs I tried, from Windows 10 back to Windows Vista, worked perfectly, as per your video.
Added to that, the first thing the IT specialists at corporate thought of was Group Policy limitations on USB connections to PCs.
Now my test PCs don’t have any specific Group Policy restrictions, but perhaps just the fact they can be applied adds overhead to the USB connection, timing,etc?
I’m sure NETMF would have been tested on the full range of PC configurations, but TinyCLR perhaps not so much? Can you confirm you’ve tested this, or give it a test if not?

Ok, so my second thought went along these lines.
What if the repeated switching between MassStorage and WinUSB when MassStorage was still actually running caused a buildup of crap (technical term) in the registry that left Windows completely confused when it saw the device, hence it taking a long time to recognize it, and drop it in and out a few times?
This would apply to my test boxes, and also the corporate gateway servers, as they would have been exposed to the faulty meter software multiple times as users tried to get the early versions to work.

Hopefully some testing can confirm which of these (if either) is the cause of 2), and new firmware can fix 1)

Thanks,
David

However on these PCs I saw what you were seeing, the connection was almost immediate, directory came up on Windows Explorer in 4 seconds,

So why it was slow and enumerate two times on your PC before? I would like to know so I can setup same as yours and we will be on same page.

Sorry, I thought I had stated my current two hypotheses in my post. These were:

  1. So far all PCs tested and having the problem are Windows Pro and attached to a domain. PCs without the problem are Windows Home (and standalone). Does your testing on various hardware and software configurations confirm or negate this observation?

  2. So far all PCs having this problem have been exposed to the apparent firmware bug where MassStorage doesn’t stop when requested. Having a device claiming to be connected as WinUSB while at the same time connected as MassStorage may have caused “confusion” in the Windows registry settings, leading to the observed fault.

Hypothesis 1 you should be able to rule in or out based on either your previous compliance test results, or some simple testing with appropriately configured PCs.

For hypothesis 2, you could try messing up a PC by testing switching between modes with old versions of the firmware, or perhaps identify the registry settings that could be compromised, and how best to clear/reset them, and I can try it here for you?

There has to be a simple explanation, if neither of those two are the cause I’m sure someone here will come up with it.

For me, as mentioned previously I’m about to head overseas for a couple of months for a much needed vacation. I have four of these SC20 based meters on my desk that the plant “needs fixed urgently”, 20 Linux based furnace control systems needing a software update, two plants chasing new project proposals (one using a GHI module), I’ve only booked half my flights and the first few days accommodation, so I don’t have a lot of time to spare on testing.
I’m now 65 (and supposed to be retired?) but after 45 years playing with these tiny devices I’m still having fun. Not sure I’ll feel that way when I get back home!

Can you please tell us more a bit detail “attached to a domain”?

If you mean network then all our testing on PC they connect to network, and ready to access internet.

The video we show here using Win11 Pro, not Home. But Home also gives same result.

The video doesn’t mean “No no we could not reproduce, it is done”, it means we are working on the problem seriously. We don’t just read your post and answer “could not reproduce”.

So far I don’t think problem at Pro or 10Home version.

As you said, “Window Pro + attached domain”, how about Window Home + attached domain? is the issue happened?
How about window Pro standalone? And Window Pro here is 10 or 11?

In normal test, we don’t see issue as you know, it has to plus “something”, do you agree? And we are working together to find out what “something” is. “Something” you give us, it is most important to help us see and fix the issue faster.

Example, on those PC, they may install some other softwares, and cause issue, possible?
You have some computers, some work, some not, can you please spend a bit more time to see what is different between them?

Anyway, we will look into it more, but it would be great if you have something new to us.

And, have you tried uninstall/ reinstall the device? Do they need INF driver file or not?

And, can you find unused PC and try install new fresh Window OS and try? It does not take too long, about 10min for installing and next 10, 15min to update latest drivers. That is good way to know if it is really Window 10, 11, Pro or Home, standalone or attached domain problem or if any thirdparty software issue.

Sure.
A Windows Domain is a network management system used in businesses or organizations to centralize administration of computers and other devices. It allows for centralized user account management, security policies, and resource sharing across the network. In a domain, a server running Windows Server operating system acts as the domain controller, managing the domain’s security and user account information. Computers and devices that join the domain can be managed collectively, enabling users to log in with their credentials on any domain-connected computer and access resources based on their permissions.

Windows Home PCs can’t attach to (join) a Domain, you require Pro or above, although Pro can also be used standalone.
Here at C-Born we show 41 PCs of various types in our Domain ‘CBORN’, with the number of Home and standalone unknown as the don’t show up in the list. Of course these days most of these are virtual machines.
Corporate side will show many thousands of PCs, in multiple Domains organized in Forests, based on geographical location and/or usage type (commercial, process control, etc)

These are all subject to top-down control by something called ‘Group Policy’, which can enforce things such as which drivers can be installed and by whom, what devices can attach to USB, etc.

This means there are things that the head of IT at a local plant with hundreds of PCs and servers can’t control or even see. At times even the head of IT for the country has to wait for some specialist chap in a plant in Canada to wake up and change a setting for him.

So it is no wonder the first thing the IT chaps say when we get a strange case like this (different behaviour on different PCs) is “It must be Group Policy!” :slight_smile:

The really nice thing about the TinyCLR implementation compared to the older NETMF one is that they use the built-in MassStorage and WinUSB drivers, so we don’t have to install anyhing with .INF files or the like.

Doing that was becoming more difficult with every new version of Windows as they ramped up security.

I made a new install of Windows 10 Pro on a fresh SSD.
Tested as standalone and then joined to a Domain, no difference, so I think that rules that theory out.

I tested directly connected to a USB 2 port, using the code on the Portal where you can turn MassStorage on and off.
When turned on, the connection comes up very quickly, like in your video, and is stable.
When MassStorage is turned off, the PC comes up with a “USB Device Not Recognized” message dialog, and Device Manager shows “Unknown USB Device (Device Descriptor Request Failed)”.
This indicates that USB is not being fully shut down?

I now have three Windows 10 Pro systems I can test on. One is that clean build, another has the old manually installed WinUSB driver and can work with EMX and G120 version meters, one is an older build which doesn’t have the manually installed driver, but has seen various versions of the SC20 device with previous firmware.

There is some indication that the connection response varies depending on whether the connection is direct to a USB 2 or a USB 3 port, and also between direct and via a USB 2 or USB 3 hub. I need to make some more formal tests to nail that down.

In the cases I showed previously where the connection appears to be made quickly, then drops, comes back again, and may repeat that again, if you watch in Device Manager the Drive appears almost immediately, but doesn’t come up in Windows Explorer. Then after some time Device Manager does a refresh (Device disappears) and immediately another refresh (Device is back) and now it appears in Windows Explorer.

Next step is to play with various hardware configurations, maybe see if the problems follows specific hardware (PC onboard USB devices, USB 2 vs 3, different hubs) or software. Perhaps load a complete new OS on one of the PCs currently failing. But I won’t have time for that until I get back.

Priority now is to patch up the hardware on units I have, get the best possible SW/FW version on them, and get them back to the plant. If you have a version of firmware with any fixes that may help, even if not complete or ready to release (2.2.0.7100?) that would be great.