(Teil 2) Netzwerkverbindung zwischen Windows Phone 7 und Netduino Plus

WP7_und_Netduino_01_thumb1
Netduino und WP7 Anwendung

Im ersten Teil zeigte ich eine Client Anwendung für Windows Phone 7. Damit sich die App auch verbinden kann, brauchen wir noch ein wenig Code für den Netduino.
Wer sich mit der Socket Klasse für Windows Phone 7 auseinandergesetzt hat, wird sicherlich darauf gestoßen sein, dass nur eine Client Anwendung geschrieben werden kann (ab Mango Update). Jedoch ist das nicht weiter schlimm, da wir den Netzwerk Server auf dem Netduino schreiben können, was auch im nachhinein sinnvoller ist.

WP7_und_Netduino_02
WP7 Handy, Netduino Plus und Servo

Auch hier habe ich wieder den Code auf (fast) das Wesentlich reduziert. Die Rückantwort an den Client, um den Empfang zu bestätigen, fällt hier weg. Wer später daraus eine Fernsteuerung programmiert, muss ohnehin darauf verzichten, und eher eine Fehlerbehandlung schreiben.
Der gesamte Code für den Netduino fällt wesentlich kürzer aus. Das liegt mitunter daran, dass im .NET Micro Framework nicht alles übernommen wurde, wie im herkömmlichen .NET Framework.
Die Netzwerkserver Klasse, mit der später die Daten empfangen werden.
   1: public class NetworkServerSocket
   2: {
   3:     /// <summary>
   4:     /// Legt die Anzahl der Verbindungen in der Warteschlange fest.
   5:     /// </summary>
   6:     private const int _Backlog = 5;
   7:     /// <summary>
   8:     /// Legt den zu empfangenen Puffer fest
   9:     /// </summary>
  10:     private const int _BufferSize = 1024;
  11:     /// <summary>
  12:     /// Wartet auf eine Anfrage des Client und stellt schließlich die Verbindung her.
  13:     /// </summary>
  14:     public void StartHost()
  15:     {
  16:         // Port festlegen
  17:         int serverPort = 1200;
  18:  
  19:         // Initialisiert die Socket Klasse mit 
  20:         // den Einstellungen für ein TCP Verbindung
  21:         Socket serverSocket =  serverSocket = new Socket(
  22:             AddressFamily.InterNetwork, 
  23:             SocketType.Stream, 
  24:             ProtocolType.Tcp);
  25:  
  26:         // Assoziiert den Socket mit einem lokalen Endpunkt
  27:         serverSocket.Bind(new IPEndPoint(IPAddress.Any, serverPort));
  28:  
  29:         // Versetz den Socket in den aktiven Abhörmodus
  30:         serverSocket.Listen(_Backlog);
  31:  
  32:         // Puffergröße festlegen
  33:         byte[] receiveBuffer = new byte[_BufferSize];
  34:  
  35:         // Zählt später, wie viele Bytes empfangen wurden
  36:         int countByteReceived;
  37:  
  38:         while (true)
  39:         {
  40:             // Zweiten Socket als Client anlegen.
  41:             // Dient dazu, die Anfrage vom Client zu verarbeiten.
  42:             Socket client = null;
  43:  
  44:             // Bleibt solange bis eine eigene Nachricht eingeht.
  45:             client = serverSocket.Accept();
  46:  
  47:             // Legt später fest, wieviele Bytes gesendet wurden
  48:             int totalBytesEcho = 0;
  49:  
  50:             // Schleife für den Empfang der Datenübermittlung
  51:             while ((countByteReceived = client.Receive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None)) > 0)
  52:             {
  53:                 // Event senden
  54:                 NetworkMessage(receiveBuffer);
  55:                     
  56:                 // Anzahl Bytes summieren
  57:                 totalBytesEcho += countByteReceived;
  58:  
  59:                 // Buffer zurücksetzen
  60:                 receiveBuffer = new byte[_BufferSize];
  61:             }
  62:  
  63:  
  64:             // Es gibt hier kein Shutdown
  65:             // Schließe die Verbindung
  66:             client.Close();
  67:         }
  68:     }
  69:  
  70:     
  71:     public delegate void NetworkMessageEvent_Handler(object sender, NetworkMessageEventArgs e);
  72:     public event NetworkMessageEvent_Handler NetworkMessageEvent;
  73:     /// <summary>
  74:     /// Event senden
  75:     /// </summary>
  76:     /// <param name="byteMessage"></param>
  77:     public virtual void NetworkMessage(byte[] byteMessage)
  78:     {
  79:         if (NetworkMessageEvent != null)
  80:         {
  81:             NetworkMessageEvent(this, new NetworkMessageEventArgs(byteMessage));
  82:         }
  83:     }
  84: }

Dazu wieder ein Event, damit immer nach einem Datenempfang ein neuer Stellwert gesetzt wird.


   1: public struct NetworkMessageEventArgs
   2: {
   3:     public byte[] ByteMessage;
   4:  
   5:     public NetworkMessageEventArgs(byte[] byteMessage)
   6:     {
   7:         ByteMessage = byteMessage;
   8:     }
   9: }


Das Protokoll, das ich bereits für die WP7 App angelegt habe, kann vollständig übernommen werden. Jedoch muss eine weitere Methode (die ich hier ToString benannt habe) hinzugefügt und der Konstruktor für die Übergabe des Byte Array angepasst werden.


   1: /// <summary>
   2: /// Ein Objekt, das als Protokol für die Übertragung verwendet wird.
   3: /// Der Inhalt kann beliebig erweitert werden. 
   4: /// Im Beispiel wird zunächst ein Wert übermittelt.
   5: /// </summary>
   6: public struct NetworkProtocolRemote
   7: {
   8:     /// <summary>
   9:     /// Die Variable zum festlegen des Stellwertes.
  10:     /// </summary>
  11:     private int _ServoValue;
  12:     /// <summary>
  13:     /// Initialisiert das Protokol mit Variablen.
  14:     /// </summary>
  15:     /// <param name="onVocabulary"></param>
  16:     public NetworkProtocolRemote(int servoValue)
  17:     {
  18:         _ServoValue = servoValue;
  19:     }
  20:     /// <summary>
  21:     /// Empfangenes Byte Array wird eingelesen und befüllt die Variablen.
  22:     /// </summary>
  23:     /// <param name="receive"></param>
  24:     public NetworkProtocolRemote(byte[] receive)
  25:     {
  26:         _ServoValue = 0;
  27:  
  28:         SetProperties(ToString(receive));
  29:     }
  30:     /// <summary>
  31:     /// Überstezt das Byte Array in einen String.
  32:     /// Ist leider nicht im .NET Micro Framework vorhanden.
  33:     /// </summary>
  34:     /// <param name="receive"></param>
  35:     /// <returns></returns>
  36:     public static string ToString(byte[] receive)
  37:     {
  38:         // Kann nur in ein Char Array umgewandelt werden.
  39:         // Im .NET Micro gibt es keine GetString Methode
  40:         char[] caValues = Encoding.UTF8.GetChars(receive);
  41:         string protocol = string.Empty;
  42:         for (int i = 0; i < caValues.Length; i++)
  43:         {
  44:             protocol += caValues[i].ToString();
  45:         }
  46:         return protocol;
  47:     }
  48:     /// <summary>
  49:     /// Der Inhalt des empfangenen Protokols wird in den Variablen festlegt.
  50:     /// </summary>
  51:     /// <param name="protocol"></param>
  52:     public void SetProperties(string protocol)
  53:     {
  54:         // Das Protokol kann um weitere Variablen erweitert werden,
  55:         // daher habe ich hier eine Schleife eingesetzt, 
  56:         // um hier die Variablen festzulegen.
  57:         foreach (string item in protocol.Split(';'))
  58:         {
  59:             string[] sa = item.Split(':');
  60:  
  61:             switch (sa[0])
  62:             {
  63:                 case ("ServoValue"):
  64:                     {
  65:                         _ServoValue = Convert.ToInt16(sa[1]);
  66:                         break;
  67:                     }
  68:                 default:
  69:                     {
  70:                         break;
  71:                     }
  72:             }
  73:         }
  74:     }
  75:     /// <summary>
  76:     /// Gibt den Inhalt des Objektes als Byte Array zurück
  77:     /// </summary>
  78:     /// <returns></returns>
  79:     public byte[] GetRemoteToByte()
  80:     {
  81:         string content = string.Empty;
  82:  
  83:         content += "Vocabulary:" + _ServoValue + ";";
  84:  
  85:         // Wenn weitere Werte übermittelt werden sollen,
  86:         // dann sollte die Sendung immer aus dem 
  87:         // Namen des Wertes, das mit dem Trennzeichen
  88:         // Doppelpunkt zum Wert und schließlich mit 
  89:         // Semikolon abgeschlossen wird.
  90:         // Beispiel:
  91:         //  IrgendEinWert:123;IrgendWasWert:456;
  92:  
  93:         return Encoding.UTF8.GetBytes(content);
  94:     }
  95:     /// <summary>
  96:     /// Ruft den Wert des Servos ab oder legt diesen fest.
  97:     /// </summary>
  98:     public int ServoValue
  99:     {
 100:         set { _ServoValue = value; }
 101:         get { return _ServoValue; }
 102:     }
 103: }


Zuletzt kommt die Program.cs Klasse, um den Server auch starten zu können. Dazu gehört natürlich auch das Initialisieren für einen PWM Port, um den Servo später anzusteuern und auch die Übergabe des Einstellwertes über die Event Methode.


   1: public class Program
   2: {
   3:     /// <summary>
   4:     /// Ein PWM Signal erzeugen, um den Servo anzusteuern.
   5:     /// </summary>
   6:     private static PWM _ServoForControl;
   7:     /// <summary>
   8:     /// Server Klasse initialisieren
   9:     /// </summary>
  10:     private static NetworkServerSocket _Server = new NetworkServerSocket();
  11:     private static NetworkProtocolRemote _Protocol;
  12:  
  13:     public static void Main()
  14:     {
  15:         // Initialisiere PWM Klasse und lege den Pin Ausgang fest.
  16:         _ServoForControl = new PWM(Pins.GPIO_PIN_D5);
  17:  
  18:         // Puls Signal festlegen als Ausgangspunkt
  19:         _ServoForControl.SetPulse(20000, 1500);
  20:  
  21:         // Event hinzufügen für den Empfang
  22:         _Server.NetworkMessageEvent += new NetworkServerSocket.NetworkMessageEvent_Handler(server_NetworkMessageEvent);
  23:  
  24:         // Server in eigenem Thread starten.
  25:         new Thread(_Server.StartHost).Start();
  26:     }
  27:     /// <summary>
  28:     /// Wird ausgeführt, wenn neue Daten empfangen wurden.
  29:     /// </summary>
  30:     /// <param name="sender"></param>
  31:     /// <param name="e"></param>
  32:     private static void server_NetworkMessageEvent(object sender, NetworkMessageEventArgs e)
  33:     {
  34:         // Variablen festlegen über das Protokol
  35:         _Protocol = new NetworkProtocolRemote(e.ByteMessage);
  36:  
  37:         // Neuen Wert festlegen am PWM Port
  38:         _ServoForControl.SetPulse(20000, ServoValueToPwmValue(_Protocol.ServoValue));
  39:     }
  40:     /// <summary>
  41:     /// Übersetz den empfangenen Wert zu einer Pulslänge um.
  42:     /// </summary>
  43:     /// <param name="servoValue"></param>
  44:     /// <returns></returns>
  45:     public static uint ServoValueToPwmValue(int servoValue)
  46:     {
  47:         return (uint)System.Math.Round(((double)servoValue / 180) * 2000);
  48:     }
  49: }


So, im Großen und Ganzen war das schon alles, um ein einfaches Bespiel zu erhalten, mit dem sich eine Netzwerkverbindung zwischen Windows Phone 7 und Netduino Plus herstellen lässt.












Netzwerkverbindung zwischen WP7 und Netduino Plus
Zur Veranschaulichung ein Video.

 


Das Ganze habe ich natürlich auch wieder als Visual Studio 2010 Solution vorbereitet:
Netduino Plus Programm Solution - Download

Kommentare

Beliebte Posts aus diesem Blog

Arduino Control (Teil 5) - PWM Signal einlesen

Angular auf dem Raspberry Pi

RC Fahrtenregler für Lego Kettenfahrzeug