SCM20260D Built In Ethernet - Socket Connect Failure

So I’m working on porting some legacy .NETMF code to TinyCLR. We are upgrading our board from a GHI G120 to a SCM20260D SoM.

I am using a Teltonika RUT240 LTE Modem/Router connected to our board via ethernet. I know it’s not an issue, since our old G120 NETMF board works with the same router configuration (I am able to hot-swap the same router to the old/new board and the old one is able to connect to the server)

Firstly, here’s my Ethernet init code (nearly copy paste from doc examples):

            var gpioController = GpioController.GetDefault();
            var resetPin = gpioController.OpenPin(SC20260.GpioPin.PG3);

            resetPin.SetDriveMode(GpioPinDriveMode.Output);

            resetPin.Write(GpioPinValue.Low);
            Thread.Sleep(100);

            resetPin.Write(GpioPinValue.High);
            Thread.Sleep(100);
            _nw = NetworkController.FromName(SC20260.NetworkController.EthernetEmac);

            var nif = new EthernetNetworkInterfaceSettings();
            var ncis = new BuiltInNetworkCommunicationInterfaceSettings();
            
   
            nif.Address = new IPAddress(new byte[] { 192, 168, 1, 200 });
            nif.SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 });
            // Teltonika Router LAN IP
            nif.GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 });
            nif.DnsAddresses = new IPAddress[]
                    {new IPAddress(new byte[] { 192,168,1,1 })};

            nif.MacAddress = new byte[] { 0xE8, 0x7F, 0xA2, 0xD1, 0x36, 0xD5 };
            nif.DhcpEnable = false;
            nif.DynamicDnsEnable = false;
            
            _nw.SetInterfaceSettings(nif);
            _nw.SetCommunicationInterfaceSettings(ncis);
            
            _nw.SetAsDefaultController();
            _nw.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
            _nw.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;
            _nw.Enable();

And here’s my basic Socket connect/send/receive code:

                    Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    soc.ReceiveTimeout = 30000;
                    soc.SendTimeout = 30000;

                    IPEndPoint ep = new IPEndPoint("SERVER_IP", 20000);

                    soc.Connect(ep);

                    soc.Send(buf);

                    soc.Receive(respBuf);

Now, the above socket code is identical between the NETMF and TinyCLR versions of firmware I’m working on.

I have an app running on our server that accepts socket connections and receives/responds to data on the above specified port (has been working for years with old NETMF boards).

(note: I can only embed 1 image here so the formatting is a little weird, so the images are denoted in order)
Here’s a wireshark capture of the old NETMF succesfully transacting with the server(1):
(PINK = Device IP, RED = Server IP)

Now this all works, but when trying to use TinyCLR, i get a SocketException on the Connect method call (with no additional information), and here’s that capture (2):

Furthermore, i noticed when i crank the socket send/receive timeouts to 30_000_000, the connect no longer throws an exception, but i get errors while sending/receiving data(3):

I have verified that the packets sent from the NETMF and TinyCLR devices are identical (at least from looking at the byte array passed to the Send() method)

Any ideas here? I can’t find any differences between the logic in either system, and I’m scratching my head. I have tried to set the clock speed lower on the SCM20260D as mentioned in other forum posts, but with no luck.

what firmware are you using?

If you can, please make small, simple project so we can reproduce, use socket class directly, don’t make wrapper class like MySocket.cs. We just want simple code that we can reproduce.

I am using FW version 2.2.0.6000

I created a basic app with only the ethernet config and attempted socket send:

using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using System.Threading;
// All version 2.2.0.6000
using GHIElectronics.TinyCLR.Networking;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Devices.Gpio;
using System.Net;
using System.Net.Sockets;

namespace SocketTest
{
    internal class Program
    {
        static byte[] testbuf = new byte[] { /* Filled w/ possibly sensitive data, len = 263 */};
        static void Main()
        {
            try
            {
                // Setup Ethernet
                var gpioController = GpioController.GetDefault();
                var resetPin = gpioController.OpenPin(SC20260.GpioPin.PG3);

                resetPin.SetDriveMode(GpioPinDriveMode.Output);

                resetPin.Write(GpioPinValue.Low);
                Thread.Sleep(100);

                resetPin.Write(GpioPinValue.High);
                Thread.Sleep(100);
                NetworkController _nw = NetworkController.FromName(SC20260.NetworkController.EthernetEmac);

                var nif = new EthernetNetworkInterfaceSettings();
                var ncis = new BuiltInNetworkCommunicationInterfaceSettings();


                nif.Address = new IPAddress(new byte[] { 192, 168, 1, 200 });
                nif.SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 });
                // Teltonika Router LAN IP
                nif.GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 });
                nif.DnsAddresses = new IPAddress[]
                        {new IPAddress(new byte[] { 192,168,1,1 })};

                nif.MacAddress = new byte[] { 0xE8, 0x7F, 0xA2, 0xD1, 0x36, 0xD5 };
                nif.DhcpEnable = false;
                nif.DynamicDnsEnable = false;

                _nw.SetInterfaceSettings(nif);
                _nw.SetCommunicationInterfaceSettings(ncis);

                _nw.SetAsDefaultController();

                _nw.Enable();

                // Send Data to Server
                byte[] recvBuf = new byte[1024];
                Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                soc.ReceiveTimeout = 30000000;
                soc.SendTimeout = 30000000;
                // With the following Timeouts:
                //soc.ReceiveTimeout = 30000;
                //soc.SendTimeout = 30000;
                // Received SocketException :
                //The thread '<No Name>' (0x2) has exited with code 0 (0x0).
                //#### Exception System.Net.Sockets.SocketException - 0x00000000 (1) ####
                //#### Message: 
                //#### System.Net.Sockets.Socket::Connect [IP: 002f] ####
                //                Exception thrown: 'System.Net.Sockets.SocketException' in GHIElectronics.TinyCLR.Networking.dll
                //System.Net.Sockets.SocketException: Exception was thrown: System.Net.Sockets.SocketException
                IPAddress serverIp = IPAddress.Parse("SERVER_IP");
                IPEndPoint ep = new IPEndPoint(serverIp, 20000);

                soc.Connect(ep);
                
                int sent = soc.Send(testbuf);

                Debug.WriteLine($"Sent {sent}/{testbuf.Length} bytes.");

                int recv = soc.Receive(recvBuf);

                Debug.WriteLine($"Received {recv} bytes");
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }


        }
    }
}

With the same results. Wireshark here:

I don’t have device here to test for now, but look at your code, you need to wait for network ready after enabled. That is why you wait for 30000 make different.

Look at our doc and try to implement it to see if any different.

Good catch. I had that implemented in my non-test firmware.

I added the wait to the test code:

using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using System.Threading;
using GHIElectronics.TinyCLR.Networking;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Devices.Gpio;
using System.Net;
using System.Net.Sockets;

namespace SocketTest
{
    internal class Program
    {
        static byte[] testbuf;//
        static bool linkReady = false;
        static void Main()
        {
            try
            {
                // Setup Ethernet
                var gpioController = GpioController.GetDefault();
                var resetPin = gpioController.OpenPin(SC20260.GpioPin.PG3);

                resetPin.SetDriveMode(GpioPinDriveMode.Output);

                resetPin.Write(GpioPinValue.Low);
                Thread.Sleep(100);

                resetPin.Write(GpioPinValue.High);
                Thread.Sleep(100);
                NetworkController _nw = NetworkController.FromName(SC20260.NetworkController.EthernetEmac);

                var nif = new EthernetNetworkInterfaceSettings();
                var ncis = new BuiltInNetworkCommunicationInterfaceSettings();


                nif.Address = new IPAddress(new byte[] { 192, 168, 1, 200 });
                nif.SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 });
                // Teltonika Router LAN IP
                nif.GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 });
                nif.DnsAddresses = new IPAddress[]
                        {new IPAddress(new byte[] { 192,168,1,1 })};

                nif.MacAddress = new byte[] { 0xE8, 0x7F, 0xA2, 0xD1, 0x36, 0xD5 };
                nif.DhcpEnable = false;
                nif.DynamicDnsEnable = false;

                _nw.SetInterfaceSettings(nif);
                _nw.SetCommunicationInterfaceSettings(ncis);

                _nw.SetAsDefaultController();
                _nw.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
                _nw.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;
                _nw.Enable();

                while (!linkReady) ;
                // Send Data to Server
                byte[] recvBuf = new byte[1024];
                Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                soc.ReceiveTimeout = 30000;
                soc.SendTimeout = 30000;
                // With the following Timeouts:
                //soc.ReceiveTimeout = 30000;
                //soc.SendTimeout = 30000;
                // Received SocketException :
                //The thread '<No Name>' (0x2) has exited with code 0 (0x0).
                //#### Exception System.Net.Sockets.SocketException - 0x00000000 (1) ####
                //#### Message: 
                //#### System.Net.Sockets.Socket::Connect [IP: 002f] ####
                //                Exception thrown: 'System.Net.Sockets.SocketException' in GHIElectronics.TinyCLR.Networking.dll
                //System.Net.Sockets.SocketException: Exception was thrown: System.Net.Sockets.SocketException
                IPAddress serverIp = IPAddress.Parse("SERVER_IP");
                IPEndPoint ep = new IPEndPoint(serverIp, 20000);

                soc.Connect(ep);
           
                
                int sent = soc.Send(testbuf);

                Debug.WriteLine($"Sent {sent}/{testbuf.Length} bytes.");

                int recv = soc.Receive(recvBuf);

                Debug.WriteLine($"Received {recv} bytes");
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }


        }

        private static void NetworkController_NetworkLinkConnectedChanged
        (NetworkController sender, NetworkLinkConnectedChangedEventArgs e)
        {
            //Raise connect/disconnect event.
        }

        private static void NetworkController_NetworkAddressChanged
            (NetworkController sender, NetworkAddressChangedEventArgs e)
        {

            var ipProperties = sender.GetIPProperties();
            var address = ipProperties.Address.GetAddressBytes();

            linkReady = address[0] != 0;
            Debug.WriteLine("IP: " + address[0] + "." + address[1] + "." + address[2] + "." + address[3]);
        }
    }
}

Same results. SocketException w/ 30000 timeout.

Thanks for the help so far!!

-Additional [FYI]
@Gus_Issa
@Dat_Tran
-Has been awhile since we last needed to communicate, simply because the thousands of [G120 SoM / .NetMF] devices, [Polaris Energy Services] has fielded (deployed) have worked without flaw.
I give Kudo(s) to GHI for [G120 SoM / .NetMF] reliability, and have set our next-generation of (electrical) engineers [EE(s)] to follow such a proven path.

-Next Generation [EE(s)]:
	-Jordan Hardy (@jhardy) is my (son), [EE] from Montana Tech.
		-My [EE] degree was from Montana State.
		
	-Always makes for a good discussion of which path was better for [skinning-the-cat].

-As GHI knows, the realm of [Polaris] is critical Infrastructure, beyond edge, event horizon (perseverance of reciprocity), type of services.
	-Polaris has (ran-down-the-road) with multiple development tool-chains [c, c++, python, linux distro(s), eclipse, etc…]
		-By far, development within Visual Studio [Code], and/or the full Visual Studio [IDE] development suite, has (explicitly) become Polaris's (de-facto) productivity tool-chain.
	
-With zero (0) doubt, Polaris re-designed (previous: ----> to new) devices, to take advantage of the [SCM20260D-RevC SoM], running our C# application on [TinyCLR OS].
	-Porting code from the [G120 SoM / .NetMF], to: ----> [SCM20260D-RevC SoM / TinyCLR OS], has been (relatively) painless.
	
-The [SCM20260D-RevC (built-in-ethernet) controller], (Socket Connection Failure) is the final hurdle to jump, before field-qualifications can begin.
	I do think such (Socket Connection Failure) is easy to solve, yet the exact route to resolute still evades us.
	
-The use of [var], a variable (typeOf [?]), would never be used in Polaris production code.
	-[var], is only used here, for (example), and (in-line) with other [GHI / Forum] examples.
	
-To Note:
	-The Teltonika RUT240 router is but one of the [cellular] communications devices supported by our Polaris device, called a [PAC].
		-If there is any (other) errata, to which Polaris should be aware of, please forward (or direct) us to the source documentation.

Again, thanks Gus, Dat, and the entire [GHI Team] for producing products, which make the development (environment)….[FEZ]: Friking-EZ

1 Like

What Exception do you have?

When I ran your code, I got null exception because “recvBuf” is null and this exception is correct.

I changed your code, it works fine, no exception. You need to look on your server code.

Below is our code on PC (server) and SITCore

Server:

static void DoSocketServer()
{
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    socket.Bind(new IPEndPoint(IPAddress.Any, 20000));
    socket.Listen(1);


    var acceptSocket = socket.Accept();

  
    var cnt = 0;
    var total = 0;
    while (true)
    {

        var dataSend = UTF8Encoding.UTF8.GetBytes("This is from PC " + cnt);
        var sent = acceptSocket.Send(dataSend);

        total += sent;

        Console.WriteLine("Sent: " + total + ",cnt = " + cnt);
        cnt++;

        Thread.Sleep(1000);

    }


}

SITCore

static byte[] testbuf;//
static bool linkReady = false;
static void DoTestSocketClient()
{
    try
    {
        // Setup Ethernet
        var gpioController = GpioController.GetDefault();
        var resetPin = gpioController.OpenPin(SC20260.GpioPin.PG3);

        resetPin.SetDriveMode(GpioPinDriveMode.Output);

        resetPin.Write(GpioPinValue.Low);
        Thread.Sleep(100);

        resetPin.Write(GpioPinValue.High);
        Thread.Sleep(100);
        NetworkController _nw = NetworkController.FromName(SC20260.NetworkController.EthernetEmac);

        var nif = new EthernetNetworkInterfaceSettings();
        var ncis = new BuiltInNetworkCommunicationInterfaceSettings();


        

        nif.Address = new IPAddress(new byte[] { 192, 168, 86, 61 });
        nif.SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 });
        nif.GatewayAddress = new IPAddress(new byte[] { 192, 168, 86, 1 });
        nif.DnsAddresses = new IPAddress[] { new IPAddress(new byte[] { 75, 75, 75, 75 }), new IPAddress(new byte[] { 75, 75, 75, 76 }) };
        nif.MacAddress = new byte[] { 0xE8, 0x7F, 0xA2, 0xD1, 0x36, 0xD5 };

        nif.DhcpEnable = false;
        nif.DynamicDnsEnable = false;

        _nw.SetInterfaceSettings(nif);
        _nw.SetCommunicationInterfaceSettings(ncis);

        _nw.SetAsDefaultController();
        _nw.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
        _nw.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;
        _nw.Enable();

        while (!linkReady) ;
        // Send Data to Server
        byte[] recvBuf = new byte[1024];
        Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       
        // With the following Timeouts:
        soc.ReceiveTimeout = 30000;
        soc.SendTimeout = 30000;
        
        IPAddress serverIp = IPAddress.Parse("192.168.86.56");
        IPEndPoint ep = new IPEndPoint(serverIp, 20000);

        soc.Connect(ep);

        testbuf = UTF8Encoding.UTF8.GetBytes("This is from SITCore");

        int sent = soc.Send(testbuf);

        Debug.WriteLine($"Sent {sent}/{testbuf.Length} bytes.");

        int recv = soc.Receive(recvBuf);

        var recvString = Encoding.UTF8.GetString(recvBuf);

        Debug.WriteLine($"Received {recv} bytes");
        Debug.WriteLine($"Received Text: {recvString}");
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
    }


}

private static void NetworkController_NetworkLinkConnectedChanged
(NetworkController sender, NetworkLinkConnectedChangedEventArgs e)
{
    //Raise connect/disconnect event.
}

private static void NetworkController_NetworkAddressChanged
    (NetworkController sender, NetworkAddressChangedEventArgs e)
{

    var ipProperties = sender.GetIPProperties();
    var address = ipProperties.Address.GetAddressBytes();

    linkReady = address[0] != 0;
    Debug.WriteLine("IP: " + address[0] + "." + address[1] + "." + address[2] + "." + address[3]);
}

Was your exception related to recvBuf or testbuf? All your changes are seemingly related to testbuf (send) byte array.

Aplogies, in the second version of the test code i sent I failed to mention in comments testbuf was filled with data (and initialized) when I tested:

static byte testbuf = new byte { /* Filled w/ possibly sensitive data, len = 263 */};

I just didn’t want to share the data I’m using on a public forum.

I’m still getting an exception on soc.Connect:

    #### Exception System.Net.Sockets.SocketException - 0x00000000 (1) ####
    #### Message: 
    #### System.Net.Sockets.Socket::Connect [IP: 002f] ####
Exception thrown: 'System.Net.Sockets.SocketException' in GHIElectronics.TinyCLR.Networking.dll
System.Net.Sockets.SocketException: Exception was thrown: System.Net.Sockets.SocketException

You need to run exactly our code, one for SITCore, one for PC, not modify anything, unless the IP address, gateway… need to match with your network config. It should run just fine as we tested here.
Then compare our code to your simple project to find out what problem is.

Can you share your server code? is it same as our server code?

And can you make sure you can ping to SITCore with the provide IP address?