Fez Spider Socket Programs

Hello There,

I am using a Fez Spider and wifi rs21 module. I connect to my wifi module and am able to pull the time with this code.


DateTime NTPTime(string TimeServer)
        {
            // Find endpoint for timeserver
            IPEndPoint ep = new IPEndPoint(Dns.GetHostEntry(TimeServer).AddressList[0], 50);
            
            // Connect to timeserver
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            s.ReceiveTimeout = 1000;
            s.SendTimeout = 1000;

            if (s.Poll(1000, SelectMode.SelectWrite))
            {
                s.Connect(ep);
            }
            else
            {
                if (LogRequested != null)
                {
                    LogRequested(null, new LogRequestArgs("Cannot connect to socket"));
                }
                return new DateTime();
            }
            
            // Make send/receive buffer
            byte[] ntpData = new byte[48];
            Array.Clear(ntpData, 0, 48);

            // Set protocol version
            ntpData[0] = 0x1B;

            // Send Request
            s.Send(ntpData);

            // Receive Time
            s.Receive(ntpData);

            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();

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

            TimeSpan offsetAmount = new TimeSpan(0, TimezoneOffset, 0, 0, 0);
            DateTime networkDateTime = (dateTime + offsetAmount);

            if (IsDST(networkDateTime))
            {
                networkDateTime.AddHours(1);
            }

            return networkDateTime;
        }

The problem I am running into is when I disconnect from the wifi and reconnect this line


s.Send(ntpData);

hangs my application. I tried putting this to test it:


            if (s.Poll(1000, SelectMode.SelectWrite))
            {
                s.Connect(ep);
            }
            else
            {
                if (LogRequested != null)
                {
                    LogRequested(null, new LogRequestArgs("Cannot connect to socket"));
                }
                return new DateTime();
            }

but it always failed. This behavior also happens with my webserver I start up on networkUp event and network down event although the debug output states that a websever was started on x ipaddress but I am never able to access it.

Network Up:


                WebServer.StartLocalServer(_wifi.NetworkSettings.IPAddress, 80);
                index = WebServer.SetupWebEvent("index", WebServer_RefreshRate);
                applog = WebServer.SetupWebEvent("applog");
                records = WebServer.SetupWebEvent("records");

                applog.WebEventReceived += new WebEvent.ReceivedWebEventHandler(applog_WebEventReceived);
                index.WebEventReceived += new WebEvent.ReceivedWebEventHandler(index_WebEventReceived);
                records.WebEventReceived += new WebEvent.ReceivedWebEventHandler(records_WebEventReceived);

Network Down:


            applog.WebEventReceived -= new WebEvent.ReceivedWebEventHandler(applog_WebEventReceived);
            index.WebEventReceived -= new WebEvent.ReceivedWebEventHandler(index_WebEventReceived);
            records.WebEventReceived -= new WebEvent.ReceivedWebEventHandler(records_WebEventReceived);

            applog = null;
            index = null;
            records = null;

            WebServer.StopLocalServer();

I have been kind of frustrated because I have tried every combination I can think off…

Thanks!

A couple of questions. In the first instance, when you disconnect the wifi and reconnect, do you get networkdown and up events firing? Have you shown that they’re firing correctly (debug.print or display messages as a minimum) in both scenarios?

To explain what is going on, I think you need to tell us how the NTP call is made; do you do that once the networkup event has fired off, or is that fired by a timer? Perhaps the socket is not actually open because you don’t have an IP address or something; have you checked that?

I have verified that the network up and down events are firing. I also have verified that I am getting an ipaddress when I connect.

I don’t get why the first time it works but the second time I disconnect and connect it fails and hangs on the Connect method.

The output of the


Dns.GetHostEntry(TimeServer).AddressList[0]

is {64.250.177.145}. I am going to admit that I don’t know much about this socket stuff but I am trying to learn how it all works.

When I do call the NTPTime() method, I am starting this method in a separate thread. I don’t know if that helps.

After some more testing I have created a simple application that demonstrates my problem. I also found that when the Wifi module connects its generates a Network_Down event then the Network_Up event. When the user disconnects the Wifi, a network down event is triggered only.

This program also demonstrates the problem of the socket error. The error given is after the network connects, dissconnects, then connects.

Output:
RS21 WiFi module version Number is 4.4.5
WiFi Module’s MAC Address is 0351672913455
Connecting to Home_Slow
Connected
Network is down generated but may not be down
Network is Up
IP Address: 192.168.1.11
Subnet Mask: 255.255.255.0
Gateway: 192.168.1.1
DNS Server: 192.168.1.1
10/21/2012 21:35:48
Disconnected
Network is Down
IsNetworkConnected: False
IsNetworkUp: False

Connecting to Home_Slow
Connected
Network is down generated but may not be down
Network is Up
IP Address: 192.168.1.11
Subnet Mask: 255.255.255.0
Gateway: 192.168.1.1
DNS Server: 192.168.1.1

Exception System.Net.Sockets.SocketException - CLR_E_FAIL (1)

#### Message: 
#### Microsoft.SPOT.Net.SocketNative::sendto [IP: 0000] ####
#### System.Net.Sockets.Socket::SendTo [IP: 0022] ####
#### System.Net.Sockets.Socket::SendTo [IP: 0011] ####
#### Test.Program::GetNTPTime [IP: 0048] ####
#### Test.Program::wifi_NetworkUp [IP: 0072] ####
#### Gadgeteer.Modules.Module+NetworkModule::OnNetworkEvent [IP: 004d] ####
#### System.Reflection.MethodBase::Invoke [IP: 0000] ####
#### Gadgeteer.Program::DoOperation [IP: 001a] ####
#### Microsoft.SPOT.Dispatcher::PushFrameImpl [IP: 004a] ####
#### Microsoft.SPOT.Dispatcher::PushFrame [IP: 001d] ####
#### Microsoft.SPOT.Dispatcher::Run [IP: 0006] ####
#### Gadgeteer.Program::Run [IP: 001c] ####
#### Test.Program::Main [IP: 001a] ####
#### SocketException ErrorCode = 10060
#### SocketException ErrorCode = 10060

A first chance exception of type ‘System.Net.Sockets.SocketException’ occurred in Microsoft.SPOT.Net.dll
#### SocketException ErrorCode = 10060
#### SocketException ErrorCode = 10060

the code so hopefully someone can duplicate it.


public partial class Program
    {
        string myAP = "";          //Wireless Network SSID
        string password = "";  //Wireless Password

        void ProgramStarted()
        {
            wifi.UseDHCP();
            
            wifi.NetworkDown += new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkDown);
            wifi.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkUp);

            Connect();
        }

        void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            Debug.Print("Network is Up");
            Debug.Print("IP Address: " + wifi.NetworkSettings.IPAddress.ToString());
            Debug.Print("Subnet Mask: " + wifi.NetworkSettings.SubnetMask.ToString());
            Debug.Print("Gateway: " + wifi.NetworkSettings.GatewayAddress.ToString());
            Debug.Print("DNS Server: " + wifi.NetworkSettings.DnsAddresses[0].ToString());

            Debug.Print(GetNTPTime("time.nist.gov", 60 * -4).ToString());

            Thread.Sleep(5000);

            Disconnect();
        }

        void Connect()
        {
            WiFi_RS21.WiFiNetworkInfo myBSS = wifi.Search(myAP);

            if (myBSS != null)
            {
                Debug.Print("Connecting to " + myAP);
                wifi.Join(myBSS, password); // Network with WPA or WPA2 security.
                Debug.Print("Connected");
            }
            else
            {
                Debug.Print(myAP + " Wireless network was not found");
            }
        }

        void Disconnect()
        {
            wifi.Disconnect();
            Debug.Print("Disconnected");
        }

        void wifi_NetworkDown(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            if (!wifi.IsNetworkConnected)
            {
                Debug.Print("Network is Down");
                Debug.Print("IsNetworkConnected: " + wifi.IsNetworkConnected);
                Debug.Print("IsNetworkUp: " + wifi.IsNetworkUp);
                Debug.Print("\n");

                Connect();
            }

            Debug.Print("Network down event generated but may not be down");
        }

        /// <summary>
        /// Get time from NTP server
        /// </summary>
        /// <param name="timeServer">Time server to use</param>
        /// <param name="gmtOffset">GMT offset in minutes</param>
        /// <returns>NTP date-time or DateTime.MinValue when an error has occured.</returns>
        public DateTime GetNTPTime(string timeServer, int gmtOffset = 0)
        {
            Socket s = null;
            try
            {
                // init socket
                EndPoint remoteEP = new IPEndPoint(Dns.GetHostEntry(timeServer).AddressList[0], 123);
                s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                s.SendTimeout = 2000;
                s.ReceiveTimeout = 2000;

                // init request
                byte[] ntpData = new byte[48];
                Array.Clear(ntpData, 0, 48);
                ntpData[0] = 0x1B; // set protocol version

                // send request
                s.SendTo(ntpData, remoteEP);

                // wait 30s if no response, timeout
                if (s.Poll(30 * 1000 * 1000, SelectMode.SelectRead))
                {
                    // get response
                    s.ReceiveFrom(ntpData, ref remoteEP);

                    s.Close();

                    // parse time value
                    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);

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

                    return ntpTime.AddMinutes(gmtOffset);
                }
                else
                {
                    // timeout
                    s.Close();
                }
            }
            catch (Exception e)
            {
                try
                {
                    s.Close();
                }
                catch { }
            }

            return DateTime.MinValue;
        }
    }

You are executing a long lasting operation in the event thread (GetNTPTime). You should not be holding up the event thread. Put the GetNTPTime routing into a separate thread and see what happensl.

@ Mike

I removed all Thread.Sleep() functions and replaced the GetNTPTime() time with this code.


Thread t;

void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
        {
            Debug.Print("Network is Up");
            Debug.Print("IP Address: " + wifi.NetworkSettings.IPAddress.ToString());
            Debug.Print("Subnet Mask: " + wifi.NetworkSettings.SubnetMask.ToString());
            Debug.Print("Gateway: " + wifi.NetworkSettings.GatewayAddress.ToString());
            Debug.Print("DNS Server: " + wifi.NetworkSettings.DnsAddresses[0].ToString());

            t = new Thread(new ThreadStart(GetTime));
            t.Start();
        }

I am still getting the same result though but thanks for the suggestion. Do you have any other ideas? I don’t understand why a NetworkDown event is generated when trying to join a network then shortly after a NetworkUp event. The behavior of the socket error still happens during the second run.

I was doing research and found this webpage: http://netmf.codeplex.com/workitem/313. it’s similar, could it be the 4.1 firmware? I am going to try the 4.2 and see if it happens still.

Well no library exists for the wifi module for 4.2…oh well…lol

the next sdk should be out soon.

Yes trying for this week

That would be great. Can anybody else reproduce this problem so I can verify its not me only?

I have been doing more testing and found that its not just the NTP protocol problem. This code started in another thread had the same behavior problems:


try
            {
                using (HttpWebRequest request = HttpWebRequest.Create(@ "http://www.google.com") as HttpWebRequest)
                {
                    request.Method = "GET";

                    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                    {
                        using (Stream receiveStream = response.GetResponseStream())
                        {

                            // simulate reading the stream.
                            using (StreamReader readStream = new StreamReader(receiveStream))
                            {
                                string s = readStream.ReadToEnd();

                                Debug.Print(s);

                                readStream.Close();
                                receiveStream.Close();

                                response.Close();
                            }
                        }
                    }

                }

                Debug.Print(DateTime.UtcNow.ToString());
            }
            catch (WebException webEx)
            {
                Debug.Print("Web Exception Occured");
                if (webEx.InnerException is SocketException)
                {
                    SocketException sock = webEx.InnerException as SocketException;
                    Debug.Print("Socket error code: " + sock.ErrorCode.ToString());
                }
            }
            catch (Exception ex)
            {
                Debug.Print("Exception of type: " + ex.GetType().FullName);
            }
            finally
            {
                Thread.Sleep(1000);
            }

Output:

Exception System.Net.Sockets.SocketException - CLR_E_FAIL (9)

#### Message: 
#### Microsoft.SPOT.Net.SocketNative::connect [IP: 0000] ####
#### System.Net.Sockets.Socket::Connect [IP: 001d] ####
#### System.Net.HttpWebRequest::EstablishConnection [IP: 015a] ####
#### System.Net.HttpWebRequest::SubmitRequest [IP: 0013] ####
#### System.Net.HttpWebRequest::GetResponse [IP: 000c] ####
#### Test.Program::GetGoogle [IP: 0019] ####
#### Test.Program::GetTime [IP: 001f] ####
#### SocketException ErrorCode = 10038
#### SocketException ErrorCode = 10038

A first chance exception of type ‘System.Net.Sockets.SocketException’ occurred in Microsoft.SPOT.Net.dll
#### SocketException ErrorCode = 10038
#### SocketException ErrorCode = 10038
#### Exception System.Net.WebException - 0x00000000 (9) ####
#### Message: connection failed
#### System.Net.HttpWebRequest::EstablishConnection [IP: 0168] ####
#### System.Net.HttpWebRequest::SubmitRequest [IP: 0013] ####
#### System.Net.HttpWebRequest::GetResponse [IP: 000c] ####
#### Test.Program::GetGoogle [IP: 0019] ####
#### Test.Program::GetTime [IP: 001f] ####
A first chance exception of type ‘System.Net.WebException’ occurred in System.Http.dll
#### Exception System.Net.WebException - 0x00000000 (9) ####
#### Message:
#### System.Net.HttpWebRequest::GetResponse [IP: 00d3] ####
#### Test.Program::GetGoogle [IP: 0019] ####
#### Test.Program::GetTime [IP: 001f] ####
A first chance exception of type ‘System.Net.WebException’ occurred in System.Http.dll
Web Exception Occured

Wanted to let everyone know that upgrading to 4.2 seems to have solved the problem disconnecting and connecting issue.