Main Site Documentation

Problem with UDP Sockets and the Panda II


#1

Hello all,

I am new to the NETMF and the Panda II, and I am trying to write a driver for some flight control hardware. Basically, this is a prototyping effort to explore the feasibility of using the FEZ devices for a new product line of flight controller hardware (yokes, radio panels, etc). I purchased a Panda II kit, and have been leaning the NETMF for the past 1-2 months. After much discussion with the engineers, I started writing the driver and server applications earlier this week. I’ve read completely through the beginner’s guide to NETMF, as well as the “Internet of Things;” and I’ve re-read the sections most pertinent to the problem I’m having, several times.

While not new to programming, I am new to using sockets and UDP. However the examples in the texts were fairly straightforward, and I have gotten several of them to run. In the application I’ve been working on this week, I’ve been able to write from the Panda to the server app…but not vice-versa. I believe I am initializing and using the UDP socket correctly, but when I try to send a packet from the server, I will get a “connection forcibly closed” exception from the Panda. As this post will have a lengthy code section, I’ll post the exact exception output in a post to follow. But I was hoping that someone might see something I’ve missed. Although I am not entirely certain, I think the issue seems to be in the “mySocket.SendTo()” method. I’ve run it through the debugger many times, but cannot seem to get a grasp on the problem, no doubt due to my limited (by rapidly-expanding) knowledge of UDP sockets.

Note that the project has grown somewhat lengthy, so I’ve only pasted the code that I feel to be most germane to this problem. The remaining code seems to work fine, although I can certainly post more if anyone needs to see it.

Finally, a million thanks to anyone who can help me figure this out, as I’m really stuck here…

Panda Code:


using System;
using System.Text;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Net;
using GHIElectronics.NETMF.Net.Sockets;
using GHIElectronics.NETMF.Net.NetworkInformation;

using Socket = GHIElectronics.NETMF.Net.Sockets.Socket;

namespace PandaHardware
}
   public class InitializeUDP
   {
      // Set IP, subnet, gateway and MAC addresses for the FEZ Connect
      private byte[] ip;
      private byte[] subnet;
      private byte[] gateway;
      private byte[] mac;
      private byte[] data;
      public Socket mySocket;
      public EndPoint serverEndPoint;
      public IPEndPoint pandaEndPoint;

      public void ConfigureUDP()
      {
         ip = new byte[] { 192, 168, 1, 100 };
         subnet = new byte[] { 255, 255, 255, 0 };
         gateway = new byte[] { 192, 168, 1, 254 };
         mac = new byte[] { 0x00, 0x26, 0x1C, 0x7B, 0x29, 0xE8 };
         data = new byte[UdpDataInStruct.INPUT_STRUCT_SIZE];

         // Enable the WIZnet interface on FEZ Connect
         WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10, (Cpu.Pin)FEZ_Pin.Digital.Di7, true);

         // Enable the program to set and use a static IP address
         NetworkInterface.EnableStaticIP(ip, subnet, gateway, mac);

         // I don't think we need this, if we aren't on the Internet with the device...
         NetworkInterface.EnableStaticDns(new byte[] { 192, 168, 1, 254 });

         // Create a UDP socket
         mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

         // Configure the receiving endpoint
         pandaEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.100"), 2000);

         // Set up the destination as the P3D client/server device
         serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.254"), 2000);
      }
   } // end clas InitializeUDP
}

Server Code:


using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace UDPServer
{
   class UDPServer
   {
      private static int count;
      private static Socket mySocket;
      private static IPEndPoint serverEndPoint;
      private static EndPoint pandaEndPoint;
      private static UdpDataInStruct dataStructFromPanda;
      private static UdpDataOutStruct dataStructToPanda;
      private static byte[] byteArrayFromPanda;
      private static byte[] byteArrayToPanda;

      static void Main(string[] args)
      {
         // DEBUG CODE
         count = 1;
         try
         {
            // Create the actual socket
            mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
         }
         catch (SocketException se)
         {
            Console.WriteLine("Could not establish socket connection");
            Console.WriteLine(se.ToString());
            mySocket.Close();
         }

         // Define and bind a desired IP and port number to this application, for this machine
         serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.254"), 2000);
         mySocket.Bind(serverEndPoint);

         // Create a byte array of sufficient size to hold the available data
         byteArrayFromPanda = new byte[UdpDataInStruct.INPUT_STRUCT_SIZE];
         byteArrayToPanda = new byte[UdpDataOutStruct.OUTPUT_STRUCT_SIZE];

         // Define the endpoint from which to receive data
         pandaEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.100"), 2000);

         // Wait for 0.2s to see if an error results from no data being available on the socket
         if (mySocket.Poll(200000, SelectMode.SelectError))
         {
            Console.WriteLine("Socket Error");
            return;
         }

         // Forever loop to continuously process outgoing and incoming UDP data
         while (true)
         {
            // Read data from Panda
            ReadFromPanda();
            Thread.Sleep(200);  // Debug code

            // Write data to Panda
            WriteToPanda();
            Thread.Sleep(200); //  Debug code

            // Output the value of the count variable, then increment it
            Console.WriteLine("Count = {0}", count);
            count++;

            // Debug
            // Console.Read();
         }
      } // end Main


      // **********************************************************************************************
      //                                        METHOD DEFINITIONS                                    *
      // **********************************************************************************************
      public static void ReadFromPanda()
      {
         if (mySocket.Available > 0)
         {
            // Fetch the data from PandaII
            try
            {
               mySocket.ReceiveFrom(byteArrayFromPanda, byteArrayFromPanda.Length, SocketFlags.None, ref pandaEndPoint);
            }
            catch (SocketException se)
            {
               Console.WriteLine(se.ToString());
            }

            // Populate the data structure from the serialized array just read from the Panda device
            dataStructFromPanda.DeserializeArray(byteArrayFromPanda);

            // Output the struct's data to the console
            Console.WriteLine("Message From " + ((IPEndPoint)pandaEndPoint).Address.ToString());
            Console.WriteLine("aileronVoltage: {0}", dataStructFromPanda.aileronValue);
            Console.WriteLine();
         } 
      } // end ReadFromPanda()


      public static void WriteToPanda()
      {
         // Load the output buffer array
         byteArrayToPanda = dataStructToPanda.SerializeStruct();

         try
         {
            mySocket.SendTo(byteArrayToPanda, byteArrayToPanda.Length, SocketFlags.None, pandaEndPoint);
         }
         catch (SocketException se)
         {
            Console.WriteLine(se.ToString());
         }

         // DEBUG CODE: Send output struct data
         Console.WriteLine("Sending to " + ((IPEndPoint)pandaEndPoint).Address.ToString());
         Console.WriteLine("Nose Gear light: {0}", dataStructToPanda.gearLightNose);
         Console.WriteLine();
      } // end WriteToPanda()
   } // end class UDPServer
}

Thanks again!

TB

EDIT: Well, I did forget the exception, and then I screwed up the first attempt to edit, lol…


#2

Forget something?


#3

You are too speedy for me!

:wink:

TB


#4

I should add that I had to comment-out the try-catch block in order to get at that exception. As written above, the code spits out the exception to the console and keeps running. So to be able to copy it to the clip board, I simply commented out the try-catch statements, and then executed the ReceiveFrom() method directly…and then copied the exception to the clip board for insertion here. But I believe that the exception is the exactly same one I am seeing on the console.

TB

EDIT: Another very interesting turn of events, is that when I went back and swappred the order of the write/read calls to Panda from the server, it changes the value in the mySocket.Available property. So in other words, when I write to Panda first, the Available property gets set to ‘1’ and the code in the ‘if’ statement will then run on the next iteration of the main while loop. If I try to read from Panda first, Available is ‘0’ so that block never executes. Very interesting, but I not sure what it means.

Since Panda is sending data as soon as the connection is established, I reasoned that I could call the read method first…because Available would be greater than zero. But that doesn’t seem to be the case as far as I can tell.


#5

@ tcbetka
I see where you configure the network, but I don’t see where you setup the UDP listener socket?


#6

Sorry, I didn’t scroll over to the right.
…but where do you start listening for incoming udp connections?


#7

Don’t you need something like this:

serversocket.Bind(remoteEndPoint);
int i = 1;
while (true)
{
if (serversocket.Poll(-1, SelectMode.SelectRead))
{
byte[] inBuf = new byte[serversocket.Available];
int count = serversocket.ReceiveFrom(inBuf,
ref remoteEndPoint);
Debug.Print(new String(Encoding.UTF8.GetChars(inBuf)));
}
}

#8

You magnificent fellow you!!!

I totally missed that in the Panda code. So I added the mySocket.Bind() for the Panda end, and voila…instantly seems to work! I’ll test it more though, but I sure get a different output now!!

Wow. Am I a dufus.

(Thanks!)

TB


#9

Don’t worry. I’ve made much worse mistakes than that :-[


#10

Well, what is so particularly frustrating is that I must have looked at that section of code about 20 times…and missed it every time. I guess it really is true that two sets of eyes are better than one sometimes.

Thanks again.

TB