G400D ethernet fails with the debugger attached

I have tried a few more things to try to isolate the exact process to duplicate the failure, but I’m afraid there seems to be quite a random element to it all:

  • I tried upgrading to 2016 R1 prerelease and suddenly everything starting working the first time I ran the project in Debug mode. If I stop the program and restart it never works again.
  • I have tried running the same application on a Windows 7/VS 2013 environment on a different PC & network - same result.
  • I have tried attaching the MFDeploy debugger to the device but it makes no difference to if the network works or not.
  • I have tried the whole process in DHCP mode - same behaviour
  • When the ethernet works the first time the Debugger is attached, the EthernetBuiltIn constructor takes notably longer to step over than when the ethernet no longer works:


- The failing Debug behaviour can be resolved by a full tinybooter/firmware update (as mentioned by leforban in a previous thread) and the debugger will work once (in 2016 R1 Prerelease)
-I then tried JayJay's suggestion of running the code in a seperate Thread:


```cs
public static void Main()
        {
            try
            {
                Thread.Sleep(5000); 
                Thread ethernetThread = new Thread(EthernetThread);
                ethernetThread.Start();

                Thread.Sleep(-1);               
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }
        }

        private static void EthernetThread()
        {
            DateTime now = DateTime.Now;

            using (GHI.Networking.EthernetBuiltIn ethernet = new GHI.Networking.EthernetBuiltIn())
            {
                Debug.Print("Ethernet constructor time (ms) = " + ((DateTime.Now - now).Ticks / TimeSpan.TicksPerMillisecond));

                ethernet.Open();

                ethernet.EnableStaticIP("192.168.1.133", "255.255.255.0", "0.0.0.0");

                Thread.Sleep(10000); //accept pings for this time

                ethernet.Close();
            }
        }}

This seems to result in a more frequently working Ethernet interface when I reboot the device and restarted the debugger at least 5 times but failures do still occur. With this code though the failure is “recoverable” so to speak in that if I run the debugger and the code fails, the next time I run it it might work again. The Thread.Sleep at the beginning of the main thread also seems to impact the failure rate.

Most interestingly is the measured time taken to create the Ethernet constructor - when working, this typically takes about 1-2 seconds. When broken, the outputted measured time is 0ms?

Can anyone else verify this?

I haven’t tried all of the variations you did, but Ethernet reliably fails for me under the debugger on my G400 devices (multiple), and works fine with the debugger detached. The same code works fine on my G120E devices. I’m currently in the middle of a move, so I can’t do much more testing until at least the weekend.

@ AlexTZA - When Ethernet fails, can you dispose of the interface and recreate it in a loop to see if it ever starts to work while in the same debugging session?

@ John - yes, good idea. I rewrote the code as follows:

 public static void Main()
        {
            try
            {              
                long constructorTime = 0;

                GHI.Networking.EthernetBuiltIn ethernet= null;

                while (constructorTime == 0)
                {
                    DateTime now = DateTime.Now;

                    ethernet = new GHI.Networking.EthernetBuiltIn();
                    
                    constructorTime = ((DateTime.Now - now).Ticks / TimeSpan.TicksPerMillisecond);

                    Debug.Print("Ethernet constructor time (ms) = " + constructorTime);

                    if (constructorTime == 0)
                    {
                        ethernet.Dispose();
                    }
                }

                if (ethernet != null)
                {
                    ethernet.Open();

                    //ethernet.EnableStaticIP("192.168.1.133", "255.255.255.0", "0.0.0.0");
                    ethernet.EnableDhcp();
                    ethernet.EnableDynamicDns();

                    Debug.Print("Obtaining IP Address...");
                   
                    while (ethernet.IPAddress == "0.0.0.0")
                    {
                        Thread.Sleep(1000);
                    }

                    Debug.Print("IP Address is : " + ethernet.IPAddress);                                        
                }

                Thread.Sleep(-1);               
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }
        }  

This seems to get the Ethernet up and running even if it fails to “construct” properly the first time. I’ve run this on the G400HDR and several of our own boards and this seems to be a reliable workaround…for now :slight_smile:

1 Like

@ AlexTZA - Glad to see it working. We will take another look to see if we can narrow it down the root cause with this latest information.

Sounds like a race condition is happening somewhere in the code since time affects how it runs/fails.
remember when the debugger is attached code runs a whole lot faster than when it is not attached. so code is being executed much faster (due to a bug in the debug.print() which is why it always works while not in debug mode/slow mode.

cheers,
Jay
Jay.

I just tried the code shown by AlexTZA above.

It does not work on my G400-D Dev Board.
Hangs forever in while loop

while (ethernet.IPAddress == “0.0.0.0”) { }

Same issue I have been fighting.

As a side note. I tried this using a G400-D v1.3 and v1.2 from a old G400HDR

The code I was using and fighting would run on my G120E developer board without issue

I forgot to mention I am using firmware 4.3.8.0

@ willgeorge -
Did you update GHI Loader + TinyBooter?

Anyway,

First, please try this cases and share to us your result.
After deployed new code below, disconnect completely and reconnect power.
Please test both cases: With/without debugger attached.
Of course, press the button to start testing.

static InputPort button = new InputPort((Cpu.Pin)((3 * 32 + 8)), false, Port.ResistorMode.PullUp); // G400Dev Board - PD8
        static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 14), false); // G400Dev Board - PD14
        public static void Main()
        {
            while (button.Read())
            {
                led.Write(!led.Read());
                Thread.Sleep(100);
            }
            
            try
            {                
                GHI.Networking.EthernetBuiltIn ethernet = new GHI.Networking.EthernetBuiltIn();
                
                ethernet.NetworkInterface.EnableStaticIP("x.x.x.x", "255.255.255.0", "x.x.x.x");

                ethernet.Open();

                Thread.Sleep(-1);
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }

        }

@ Jay Jay - it was after I read your first post suggesting a race condition while I was testing that this seemed like a strong possibility considering the random/time dependant behaviour I was seeing. Thanks for the input!

@ willgeorge - I had a similar issue with one of our custom boards except there the physical interface has an issue as the Ethernet does not work in Debug or Release mode. Also, I believe with the v1.2 of the G400D the onboard Ethernet did not work at all which would explain the failure in that case.

Hi , I can confirm that the code from @ AlextZA works on my board.
The first time round in the loop, it fails, but it works thereafter.

@ Dat -
Sorry for the delay. I tried to post a reply yesterday but when I hit Submit my browser crashed and I got locket out of the form. Could not update password after several tries. Tried again this morning and finally got back in.

@ Dat -
Yes, I have updated my firmware.

Loader (TinyBooter) version information:
4.3.8.0 on this computer.
4.3.8.0 on this device.

The Loader (TinyBooter) is up to date. <<<

Firmware (TinyCLR) version information:
4.3.8.0 on this computer.
4.3.8.0 on this device.

The Firmware (TinyCLR) is up to date. <<<
Please wait for the device to reboot… Done.

I tried your code and it ran without issues using debug or when deployed.
Not sure what you wanted, but to me all I proved is that the button works in either case.

Begin - Blue on, Green is blinking.
Press SELECT button - Blue ON, Green stops blinking - Green may be OFF or ON

I used static address of my router.
ethernet.EnableStaticIP(“10.0.0.2”, “255.255.255.0”, “10.0.0.1”); //My router

The code works the same way even without the Ethernet cable attached.

I was using code for NTP Time and the code works ONLY IF I use a static IP.

My issue is if I want to use a non staticIP.

Such as using.
ethernet.Open();
ethernet.EnableDhcp();
ethernet.EnableDynamicDns();

In this case I never receive a IP Address update.

The code hangs forever in…
while (ethernet.IPAddress == “0.0.0.0”)
{

}

I should note also that I used an event: However, I never receive this event.
I also use a NetworkAvailabilityChanged event which I DO receive.


NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;

// Never received
static void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
    netAddressChanged = true;  // A static bool to test if event was received
}
//
static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
	netIsAvailable = true;  // A static bool to test if event was received
}
//

My gut feel is that this is a speed/timing issue because the following while passes.
netAddressChanged bool is true but I never see the event 
NetworkChange_NetworkAddressChanged when debugging

while (!netIsAvailable && netAddressChanged)
{
	// this passes
}
//

while (ethernet.IPAddress == "0.0.0.0")
{
        //Hangs here forever
}

Thanks,

Dumbfounded

After posting my reply I ran some code that was failing and guess what… It worked while debugger attached and when only deployed.

Maybe getting kicked out of here for awhile (browser crash and password problem) did some good.
I was not using a static IP and the test code ran as expected.

This was partial code of the original and I will keep adding code back and see if I can find what causes it to fail.

Code that worked



using System;
using GHI.Processor;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Net.NetworkInformation;
using Microsoft.SPOT.Presentation; //
using Microsoft.SPOT.Presentation.Media;
using MSPM = Microsoft.SPOT.Presentation.Media;

using System.Net;
using System.Net.Sockets;
using System.Threading;

using GHI.Networking;  // WiFiRS9110 - EthernetBuiltIn
using GHI.Pins;
using G400 = GHI.Pins.G400;

/*
 Using firmware 4.3.8.0
 NETMF 4.3
 Windows 10 Pro
 Visual Studio 2013 Pro
*/

/*
 My G400D Dev Board 1.2 has a battery installed.
 See GHI Support/Documents/Real Time Clock (RTC)
 for additional usage and exception checks
*/

// Original code by Peter. See:
// https: //www.ghielectronics.com/community/codeshare/entry/962

namespace EthernetNetTimeG400D
{

    public class Program
    {

        private const string NTP_ADDRESS = "us.pool.ntp.org"; // Your country?

        // UTC -6 hours Central Standard. Use -(60 * 5) for Daylight savings
        private const int NTP_TIME_OFFSET = -(60 * 6); // Your offset required

        private static GHI.Networking.EthernetBuiltIn ethernet = null;

        private static OutputPort led1 = null; // Blue
        private static OutputPort led2 = null; // Green
        private static OutputPort led3 = null; // Orange
        private static OutputPort led4 = null; // Red

        private static Font fontSmall = null;
        private static Font fontLarge = null;

        private static Bitmap bmp;
        private static MSPM.Color backColor;

        //Set this bool true to save internet time received to the RealTimeClock
        private static bool saveTimeToHardwareClock = false;

        // If pin PA26 is grounded we will save internet time received to the RealTimeClock
        private static InputPort saveTime = new InputPort(G400D.Gpio.PA26, false, Port.ResistorMode.PullUp);

        private static bool isavail = false;

        public static void Main()
        {
            fontLarge = Resources.GetFont(Resources.FontResources.NinaB);
            fontSmall = Resources.GetFont(Resources.FontResources.small);

            bmp = new Bitmap(SystemMetrics.ScreenWidth, SystemMetrics.ScreenHeight);
            backColor = ColorUtility.ColorFromRGB(0X00, 0XCC, 0XFF); //Light blue
            DrawBackgroundBmp(bmp);

            DrawBackgroundLine(Resources.GetString(Resources.StringResources.Hello), bmp, backColor, Colors.Black, fontSmall, 5, 5);

            led1 = new OutputPort(Led.Led1, false); //Blue
            led2 = new OutputPort(Led.Led2, false); //Green
            led3 = new OutputPort(Led.Led3, false); //Orange
            led4 = new OutputPort(Led.Led4, false); //Red

            try
            {
                long constructorTime = 0;

                GHI.Networking.EthernetBuiltIn ethernet = null;

                while (constructorTime == 0)
                {
                    DateTime now = DateTime.Now;

                    ethernet = new GHI.Networking.EthernetBuiltIn();

                    constructorTime = ((DateTime.Now - now).Ticks / TimeSpan.TicksPerMillisecond);

                    Debug.Print("Ethernet constructor time (ms) = " + constructorTime);

                    if (constructorTime == 0)
                    {
                        ethernet.Dispose();
                    }
                }
                //

                if (ethernet != null)
                {
                    ethernet.Open();
                    ethernet.EnableDhcp();
                    ethernet.EnableDynamicDns();

                    Debug.Print("Obtaining IP Address...");

                    while (ethernet.IPAddress == "0.0.0.0")
                    {
                        Thread.Sleep(1000);
                    }

                    Debug.Print("IP Address is : " + ethernet.IPAddress);
                    DrawBackgroundLine("IP Address is : " + ethernet.IPAddress, bmp, backColor, Colors.Black, fontLarge, 5, 5);
                }
                //

                // Get the time
                NTPTime(NTP_ADDRESS, NTP_TIME_OFFSET);

                Thread.Sleep(-1); // STOP HERE FOR TEST
            }
            catch (Exception e)
            {
                Debug.Print(e.Message);
            }
            //
            
            //FIN
            Thread.Sleep(-1);
        }
        //

        static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            if (e.IsAvailable)
            {
                isavail = true;
            }
            else
            {
                isavail = false;
            }
            //
            Debug.Print("Network IsAvailable: " + isavail.ToString()); 
        }
        //

        public static bool NTPTime(string TimeServer, int GmtOffset = 0)
        {
            Socket s = null;
            try
            {
                EndPoint rep = new IPEndPoint(Dns.GetHostEntry(TimeServer).AddressList[0], 123);
                s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                var ntpData = new byte[48];
                Array.Clear(ntpData, 0, 48);
                ntpData[0] = 0x1B; // Set protocol version

                s.SendTo(ntpData, rep); // Send Request

                // Wait for 30 seconds. if nothing: timeout
                if (s.Poll(30 * 1000 * 1000, SelectMode.SelectRead))
                {
                    s.ReceiveFrom(ntpData, ref rep); // Receive Time
                    byte offsetTransmitTime = 40;
                    ulong intpart = 0;
                    ulong fractpart = 0;
                    for (int i = 0; i <= 3; i++) intpart = (intpart << 8) | ntpData[offsetTransmitTime + i];
                    for (int i = 4; i <= 7; i++) fractpart = (fractpart << 8) | ntpData[offsetTransmitTime + i];
                    ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);
                    s.Close();

                    DateTime dateTime = new DateTime(1900, 1, 1) +
                                        TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);

                    // Needs a battery
                    if (saveTimeToHardwareClock)
                    {
                        RealTimeClock.SetDateTime(dateTime.AddMinutes(GmtOffset));
                        Utility.SetLocalTime(RealTimeClock.GetDateTime());
                        DrawBackgroundLine("Saving internet time to RealTimeClock: " + dateTime, bmp, backColor, Colors.Red, fontSmall, 5, 180);
                        Thread.Sleep(1000);
                        DateTime RTC = RealTimeClock.GetDateTime();
                        DrawBackgroundLine("Real-time Clock is now: " + RTC.ToString(), bmp, backColor, Colors.Black, fontSmall, 5, 195);
                    }
                    else
                    {
                        string theTime = "Time " + dateTime.AddMinutes(GmtOffset).ToString("hh:mm:ss tt"); //Use for 12 Hour without date
                        DrawBackgroundLine("Just looking...", bmp, backColor, Colors.Red, fontSmall, 5, 180);
                        DrawBackgroundLine("NOT saving internet time to RealTimeClock: " + dateTime.AddMinutes(GmtOffset), bmp, backColor, Colors.Red, fontSmall, 5, 196);
                        DrawBackgroundLine("12 Hour clock: " + theTime, bmp, backColor, Colors.Red, fontSmall, 5, 212);
                        DrawBackgroundLine("Ground Header pin PA26 to save internet time to RealTimeClock", bmp, backColor, Colors.Red, fontSmall, 5, 240);
                        DrawBackgroundLine("then reset this board", bmp, backColor, Colors.Red, fontSmall, 5, 255);
                    }
                    //

                    return true;
                }
                //

                s.Close();
                // Time out
                Debug.Print("Time out!!! Time was not set");
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
                try
                {
                    s.Close();
                }
                catch
                {
                }
            }
            return false;
        }
        //

        private static string GetMACAddress(byte[] PhysicalAddress)
        {
            return ByteToHex(PhysicalAddress[0]) + "-"
                                + ByteToHex(PhysicalAddress[1]) + "-"
                                + ByteToHex(PhysicalAddress[2]) + "-"
                                + ByteToHex(PhysicalAddress[3]) + "-"
                                + ByteToHex(PhysicalAddress[4]) + "-"
                                + ByteToHex(PhysicalAddress[5]);
        }
        //

        private static string ByteToHex(byte number)
        {
            string hex = "0123456789ABCDEF";
            return new string(new char[] { hex[(number & 0xF0) >> 4], hex[number & 0x0F] });
        }
        //

        private static void DrawBackgroundBmp(Bitmap b)
        {
            //Fill with background color
            b.DrawRectangle(backColor, // outline color
                 0, // outline
                 0, // x
                 0, // y
                 SystemMetrics.ScreenWidth, // width
                 SystemMetrics.ScreenHeight, // height
                 0, // x corner radius
                 0, // y corner radius
                 backColor,  // start gradient color
                 0, // start gradient x
                 0, // start gradient y
                 backColor,  // end gradient color
                 SystemMetrics.ScreenWidth, // end gradient x
                 SystemMetrics.ScreenHeight, // end gradient y
                 0xFF); // opacity
            b.Flush();
        }
        //

        /// <summary>
        /// Overwrites old text and flushes to bitmap
        /// Background color fill is the bitmap width 
        /// </summary>
        /// <param name="String to write"></param>
        /// <param name="Bitmap used"></param>
        /// <param name="Background color bitmap width"></param>
        /// <param name="Text color"></param>
        /// <param name="font"></param>
        /// <param name="Text X"></param>
        /// <param name="Text Y"></param>
        private static void DrawBackgroundLine(string s, Bitmap b, MSPM.Color Bcolor, MSPM.Color Tcolor, Font font, int X, int Y)
        {
            //Fill text line with background color
            //Erases old text if there
            b.DrawRectangle(Bcolor, // outline color
                 0, 1, Y,
                 SystemMetrics.ScreenWidth,
                 font.Height,
                 0, // x corner radius
                 0, // y corner radius
                 Bcolor,  // start gradient color
                 1, // start gradient x
                 Y, // start gradient y
                 Bcolor,  // end gradient color
                 SystemMetrics.ScreenWidth, // end gradient x
                 font.Height, // end gradient y
                 0xFF); // opacity
            b.Flush();
            //Draw the text
            bmp.DrawText(s, font, Tcolor, X, Y);
            b.Flush();
        }
        //
    }
    //End class

    /************************************************************************************/
    public static class Led
    {
        public const Cpu.Pin Led1 = G400D.Gpio.PC18;   //Blue
        public const Cpu.Pin Led2 = G400D.Gpio.PD14;   //Green
        public const Cpu.Pin Led3 = G400D.Gpio.PD17;   //Orange
        public const Cpu.Pin Led4 = G400D.Gpio.PD18;   //Red
    }
    //

    static class Button
    {
        public const Cpu.Pin Up = G400D.Gpio.PA24;  // LDR0
        public const Cpu.Pin Down = G400D.Gpio.PA4; // LDR1
        public const Cpu.Pin Left = G400D.Gpio.PD7;
        public const Cpu.Pin Right = G400D.Gpio.PD9;
        public const Cpu.Pin Select = G400D.Gpio.PD8;
    }
    //
} //End namespace

I have forgotten to mention one important? problem I have see when trying to debug a program using Ethernet on my G400-D Dev Board.

See attached Image.

I do not remember at what point in the program it happened but I am sure it was when using a breakpoint. I have had it happen three times
and I believe it was in different parts of the program but always at a breakpoint.

The Unknown USB Device IS the USB cable to USB Debug board connector.

When it happens I must reboot my PC.

I sure wish I had taken some notes at the time…

Anyway, I thought it may be helpful to the folks at GHI

next time it happens remove the board and plug in another USB device and see it work. if it doesn’t it could mean you have a short on your board or a bad cable, and windows is shutting down the USB Port as a protection. which requires a reboot to regain access.

Cheers,
Jay,

@ willgeorge -

We are going on post #11.
Did post #11 happen to you?

@ Dat -

Sorry… Bit out of my realm.

I assume I need a loop back or some sort of software to read the pings.

I use to have a plug in ethernet tester but I cannot find where it is. That was long ago.

Sorry if I sound stupid.