Resetting ENC28 network module after IP stack failure

This a thread is a continuation of the named subject, which started @
A personal challenge? - ‘This should never happen!’

We’ve heard that NETMF V4.3 for GHI products will resolve many issues relevant to networking stability among other things and that it’s expected to be released hopefully soon. However, until V4.3 is released, a number of developers are currently working towards the completion of their projects and are facing (infrequent in my case) networking problems, permanent IP stack failure to be specific.

Some have suggested: dispose/reset of the network allocated resources and restart them, obviously without having to restart the whole system.

Has anyone had the chance to effectively resolve this issue?

I think we are close to a good solution and I believe I can do it along what I suggested in the above thread. However, I have bigger bugs to exterminate and it’s not on the top of my priority list. Implementing a solution is the easy part, testing its effectiveness is the real challenge, especially if the crashing of networking is not happening frequently enough, as it’s my case.

If I am lucky, I’ll post the reset code some time next week, and hopefully some of you can assist in the testing phase.

I basically have to bring my programing setup close to my scope bench and verify if the RESET pin of the ENC28 module is already toggled with ‘Interface.Close()’, ‘Interface.Dispose()’, constructor, or ‘Interface.Open()’. if that’s the case then I don’t know what else we can do to solve the problem other than restarting the system or recycling power in the worst case!

Thanks to Sambo for this thread.

The network stack is clearly unstable, and we have (at least) to restart the ENC28 to bring it back.

So, Is it possible to unassign a module from a socket ?

Why you have problem to reset TCP/IP Stack ?
You can abtain that doing a simple algorithm:


        public static void StopEthernet()
        {
            if (listener != null)
            {
                try
                {
                    listener.Stop();
                    listener.Close();
                    listener = null;
                }
                catch (SocketException ex)
                {
                    string sex = ex.Message;
                }
            }
            if (Eth1 == null)
                return;
            if (NetworkInterfaceExtension.AssignedNetworkInterface != null)
            {
                NetworkInterfaceExtension.AssignNetworkingStackTo(null);                
            }
            Thread.Sleep(1000);
            Eth1.CableConnectivityChanged -= new EthernetENC28J60.CableConnectivityChangedEventHandler(Eth1_CableConnectivityChanged);
            Eth1.NetworkAddressChanged -= new NetworkInterfaceExtension.NetworkAddressChangedEventHandler(Eth1_NetworkAddressChanged);
            Eth1.Close();
            Thread.Sleep(1000);
            Eth1.Dispose();
            Eth1 = null;
            GC.WaitForPendingFinalizers();

            // now is better thread.Sleep(2000) ... minumum
        }

// Now you can restart from scratch ETH Intf.

        static EthernetENC28J60 CreateEthernetInterface()
        {

            // ********** G400 Raptor socket 1
            //public static EthernetENC28J60 Eth1 = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G400.Pin.PB5, GHI.Hardware.G400.Pin.PB0, GHI.Hardware.G400.Pin.PA7, 4000);
            // ********** G400 HDR
            Eth1 = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G400.Pin.PC22, GHI.Hardware.G400.Pin.PC31, GHI.Hardware.G400.Pin.PA5);
            // ********** G120 Cobra II
            //public static EthernetENC28J60 Eth1 = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G120.Pin.P1_17, GHI.Hardware.G120.Pin.P2_21 , GHI.Hardware.G120.Pin.P1_14);
            // ********** EMX Spider
            //public static EthernetBuiltIn Eth1 = new EthernetBuiltIn();
            return Eth1;
        }

        static void StartEthernet()
        {
            Eth1 = CreateEthernetInterface();
            Eth1.Open();

            Eth1.CableConnectivityChanged += new EthernetENC28J60.CableConnectivityChangedEventHandler(Eth1_CableConnectivityChanged);
            //Eth1.CableConnectivityChanged += new EthernetBuiltIn.CableConnectivityChangedEventHandler(Eth1_CableConnectivityChanged);
            Eth1.NetworkAddressChanged += new NetworkInterfaceExtension.NetworkAddressChangedEventHandler(Eth1_NetworkAddressChanged);
            Eth1.NetworkInterface.EnableStaticIP(_boardIp, _boardNetmask, _boardGw); // class C net
            string [] DnsAddresses = new string[] { "8.8.8.8" , "192.168.20.1"};
            Eth1.NetworkInterface.EnableStaticDns(DnsAddresses);
            Eth1.NetworkInterface.PhysicalAddress = new byte[] { 0x00, 0xC0, 0x03, 0x00, 0xC1, 0x03 }; // MACADDR: 00-C0-03-00-C1-03
            // Now assign interface
            NetworkInterfaceExtension.AssignNetworkingStackTo(Eth1);
            if (!Eth1.IsCableConnected)
            {
                NetworkAvailablityBlocking = new ManualResetEvent(false);
                do
                {
                    if (!Eth1.IsCableConnected)
                    {
                        Debug.Print("Ethernet cable is not connected yet.");
                    }
                    else
                        break;
                }
                while (!NetworkAvailablityBlocking.WaitOne(5000, false));
            }

            while (IPAddress.GetDefaultLocalAddress() == IPAddress.Any)
            {
                Debug.Print("IP address is not set yet.");
            }
            Debug.Print("IP address is set");
        }
....


Note: I don’t use gadgeteer Ethernet ENC28 module in the designer, but I instantiate it in the code.
This is working on G400HDR, but I think it can work also on other boards. As soon I can I will try G120 and Cerberus. In this specific code showed above I don’t use DHCP.

@ dobova : I did nearly the same code, but the problem is that when I try ti recreate the ENC28 interface, I get an SPI exception meaning that the previous object is still in use.

I disposed and unassigned ENC28 as you do, (except for the GC.WaitForPendingFinalizer) but I didn’t worked.

I’ll add this line (and send you champaign if it works !)

Why to reset ENC28 ?
Because when you send a packet to ENC28 and your socket is not under Receive blocking method, you get a crash.

I’m looking for 2 weeks now to find that problem… My tests are currently running, but it sounds I finally found the exact cause of my network stack crash.

I explain :

I have a Raptor+Enc28 (no matter what the purpose is), which connect at startup to a TCP server (on Windows).
Raptor send a status message every 0.5 second and the server send messages every 0.25 second.
As soon as you are not in the receive method (because you are processing the received message), if some messages are arriving to the Raptor, your network stack is crashed.

And the only way to bring it back is to restart the ENC28.

Hope my explanations are clear, I’m a french speaker :wink:

EDIT: I’ve changed some code to real code in my project. I missed some point in the example.

I can’t avoid socket crash, when I kill abrouptly the listener without knowledge of internal state. I just recover (really ignore it) with “try/catch” block. When I call StartEthernet it restarts all the show with no issue.

In any case I didn’t face socket problem as you describe. Are you using Accept() on new thread?

In fact, I’m not doing any accept on the Raptor I’m only doing a connection. And from that socket, I do Send/Receive operations.

I will try your code tonight, (adding some missing lines in mine) to test if it works (I hope so!)

Just for humor: I learned something new from dobova’s code:
sex == SocketException ex

The C# interpreter was happy to declare ‘string sex’!

:slight_smile: :smiley:

And while we are off topic, is this a string or “no string sex”

I’m learning more:

For humans there is ‘ex-wife’ for computers there is ‘ex.Message’!

Ok that’s enough! That’s my last joke (I’m just kidding!).

Back to business. I remember I’ve started from a similar code I found here somewhere on GHI’s web, but there are a few drawbacks that need to be taken care of:

What if you unplug the network cable and you plug it back in again, the code as is will not recover again. Same thing can be said if the router restarts for some reason. The code included above is missing the event handlers so I can’t be sure what’s being done there other than reporting.

Say you are using DHCP and the ip address assigned by the router changes when the cable is replugged in or the router restarted? I guess most people will say, well we are going to restart the system! what if it’s a black box sitting somewhere and it’ll be very hard to reach to restart immediately after network connection comes back?

What if the assignment of an ip did not succeed, we get stuck in an infinite loop printing “IP address is not set yet.” at max UC speed?!

Now it’s fair to say that I do like StopEthernet() and I’ll be adding that to my code.

Thank you dobova!

I did it too and tested it all this night, it seems to work great !

So now my network stack is still crashing sometimes, but I can restart it safely !

Thanks a lot Dobova !

Just a note about cable disconnect: I don’t manage this case becouse in the specific application the G400 is in a very reliable network infrastructure, so I do an easy reset like this:

        
static void Eth1_CableConnectivityChanged(object sender, EthernetENC28J60.CableConnectivityEventArgs e)
        {
            Debug.Print("Built-in Ethernet Cable is " + (e.IsConnected ? "Connected!" : "Disconnected!"));

            if (e.IsConnected)
            {
                if ( NetworkAvailablityBlocking != null)
                    NetworkAvailablityBlocking.Set();
                // restart tcp listner thread
                //StopEthernet(); 
                //Thread.Sleep(2000);
                //StartEthernet();
                SdCardUtility.LogPrint("Resetting system due to network cable disconnect!");
                SdCardUtility.UnmountSdCard();
                Thread.Sleep(4000);
                PowerState.RebootDevice(false);
            }    
        }

Obviously this solution is not good in all situations, for example when mouse instead to stay on the desktop near the keyboard, it goes eating net cables… It may happen…

About DHCP : I have made a very fast test and I’ve no problem, but I’m using a Windows Server 2012R2 DHCP server that is very good and reliable. Appliance like routers from D-Link, Netgear or other may not work in the same way.

For my own, I don’t manage the CableDisconnectedEvent, when I detect a connection failure, I ping the local interface, and then the gateway (my network topology is always the same and can not change) if I get no response from the gateway I restart the ENC28. (It’s now running for 20 hours with 5 messages/second)

And since my mainboard is embedded on a drone, if a mouse is eating my cables… I hope she’s also able to sing “I believe I can fly !” :wink:

@ GMISoft - ;D ;D