kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Bereitstellung einer Klasse zur einfachen Verwendung des Internet-Protokolls UDP für den Datenaustausch von Mobile Devices untereinander

(EN google-translate)

(PL google-translate)

Ziel ist es, eine Klasse für verschiedene Plattformen bereitzustellen, die ein einfaches Konzept zum unkomplizierten Datenaustausch zwischen mobilen Geräten anbietet. Typischerweise sind dann Arduino-Boards mit IoT-Fähigkeit und Android-Geräte via WiFi bei einem W-LAN Router eingewählt. Hinzu können auch noch PCs oder Laptops, die entweder per LAN-Kabel mit dem Router verbunden sind, oder ebenfalls per WiFi eingewählt sind.

Vernetzung mehrerer Geräte und Datenaustausch untereinander.

Bild 0-1: Vernetzung mehrerer Geräte und Datenaustausch untereinander.

Das Konzept, das in diesem Zusammenhang verwirklicht wurde, kann mit Briefkästen mit Namensschildern verglichen werden.

Stellen Sie sich vor, dass es mehrere Häuser gibt, in denen es jeweils eine gewisse Anzahl an Briefkästen gibt. Anzahl und Beschriftung bei den Briefkästen ist für jedes Haus gleich.

Briefkasten-Konzept.

Bild 0-2: Briefkasten-Konzept.

Ende mit der Analogie. Tatsächlich gibt es im Objekt der Klasse Briefkasten immer ein zweidimensionales Array, bei dem die erste Dimension soviele Elemente umfasst, wie es ASCII-Zeichen gibt, nämlich 127. Die zweite Dimension besteht aus 6 Character-Elementen. Dabei stehen in den vorderen fünf Daten und im letzten das ASCII-Zeichen, das den gleichen Code besitzt, wie der Index in der ersten Dimension des Arrays.

Um Zahlen auf den Plätzen zu repräsentieren, gibt es die Konvention, dass das erste Element + oder - enthält und die nachfolgenden eine Zahl zwischen 0000 und 9999. Dabei werden führende Nullen immer mit eingetragen.

Durch Transformation, konkret Division durch 1000, wird aus der ganzen Zahl zwischen +-9999 eine Fließkommazahl zwischen +-9.999.

Ablauf der Kommunikation

Jedes Gerät kann in sein eigenes Array schreiben. Der Einfachheit halber gibt es set()-Methoden, die die direkte Übergabe von Fließkommazahlen, ganzen Zahlen (Integer) und Strings unterstützen, oder direkt ein Character-Array. Jedoch genauso gibt es set()-Methoden, denen auch die IP eines Zielgerätes und ein Port übergeben wird. In diesem Fall wird der Wert zunächst in das eigene Array gelegt, aber dann unmittelbar an das Ziel gesendet und ist dann dort als Kopie in dem gleichen Typ von zweidimensionalem Array verfügbar.

Parallel existieren get()-Methoden, die entweder das lokale Array auslesen, oder von einem entfernten Array Werte anfordern.

Schließlich gibt es eine start()-Methode, die den Datenaustausch via UDP aktiviert und eine refresh()-Methode, die Anfragen anderer entfernter Geräte erkennt und bearbeitet. #Erklärende Hinweise zu UML, insb. UML-Klassendiagramm, siehe auch:

30_Informatik3/02_UML
--------------------------------------------------------------
|                       Briefkasten                          |
--------------------------------------------------------------
| + start(ssid,pwd,port,logging) : bool                      |

...alternativ, wenn sich das Device nicht selber mit Start
des Anwenderprogramms anmeldet (Android / PC):
| + start(port,logging) : bool                               |

| + refresch() : int                                         |
|                                                            |
| + set(adresse : char, wert : char[]) : bool                |
| + set(adresse : char, wert : int) : bool                   |
| + set(adresse : char, wert : float) : bool                 |
|                                                            |
| + set(adresse : char, wert : char[], ip, port)             |
| + set(adresse : char, wert : int,    ip, port)             |
| + set(adresse : char, wert : float,  ip, port)             |
|                                                            |
| + getAsCharArray(adresse : char): char[]                   |
| + getAsInt(adresse : char) : int                           |
| + getAsFloat(adresse : char) : float                       |
|                                                            |
-------------------------------------------------------------|

Code 0-1: UML-Klassendiagramm von Briefkasten

Neben diesen public-Methoden, gibt es weitere, die private sind, um notwendige Umwandlungen vorzunehmen, beispielsweise hereinkommende float-Werte auf die 5 Character-Plätze "eines Briefkastens" zu verteilen.

Beachten Sie, dass für die Realisierung der Klasse Briefkasten in der Regel wieder Bibliotheken eingebunden werden müssen, die die Basismethoden für UDP bereitstellen.

Umsetzung der Klasse für einen Laptop oder ein Android-Device mittels Processing

In der Processing-Entwicklungsumgebung darf die Klasse für den Laptop und das Android-Gerät möglichst gleich aussehen.

Briefkasten_PC_TEST.zip -- Processing-Sketch

Hauptprogramm

String ZIEL_IP = "192.168.0.101";
int ZIEL_PORT = 2390;
int eigenerLauschport = 6000;
boolean KONSOLENAUSGABE = true;

int LED = 0;
float aX = 0.0;  //Beschleunigungswert von Arduino

Briefkasten briefkasten;

void setup() 
{
  briefkasten = new Briefkasten();
  briefkasten.start(eigenerLauschport,KONSOLENAUSGABE);
  
  textSize(24.0);
  
  size(500,500);
}

void draw() 
{
     if(LED==1)
        background(255,100,100);
     else
        background(127);
        
     aX = briefkasten.getAsFloat('x'); 
     
     fill(0);
     text("aX="+aX+"m/s^2",30,30);
}

public void mousePressed()
{
     if(LED==0)
         LED = 1;
     else
         LED = 0;
     briefkasten.set('L',LED,ZIEL_IP,ZIEL_PORT);
}

void keyPressed() 
{
    briefkasten.set(key, "Hallo".toCharArray(), ZIEL_IP, ZIEL_PORT);   

Code 0-2: }

// import UDP library
import hypermedia.net.*;


public class Briefkasten
{
    private UDP udp;  // define the UDP object

    private int PUFFERGROESSE = 6; //Idee: letzte Stelle enthält Index
    private int ARRAYGROESSE = 128;
  
    private char[][] data = new char[ARRAYGROESSE][PUFFERGROESSE];
  
    private boolean LOGGING = false;
    
//| + start(ssid,pwd,port,logging) : bool                      |
    //public void start(String ssid, String pwd, int port, boolean logging)
    public boolean start(int port, boolean logging)
    {
        udp = new UDP( this, port );
        udp.listen( true );
      
        for(int i=0;i<data.length;i++)
        {
             data[i][0] = ' ';
             data[i][1] = ' ';
             data[i][2] = ' ';
             data[i][3] = ' ';
             data[i][4] = ' ';
             data[i][5] = (char)i;
        }
      
        this.LOGGING = logging;
        this.udp = udp; //port ist der Port, auf dem dieses Device lauscht!
        udp.listen( true );
        return true;
    }
//| + refresch() : int                                         |
    // wird hier von receive aufgerufen und bekommt auch dessen Übergabeparameter!
    public void refresh(byte[] remotedata, String remoteip, int remoteport)
    {
         String message = new String( remotedata );
  
         // print the result
         if(LOGGING) println( "receive: \""+message+"\" from "+remoteip+" on port "+remoteport );
  
  
         if(remotedata!=null && remotedata.length>=6)
         {
             data[(int)message.charAt(5)][0] = message.charAt(0);
             data[(int)message.charAt(5)][1] = message.charAt(1);
             data[(int)message.charAt(5)][2] = message.charAt(2);
             data[(int)message.charAt(5)][3] = message.charAt(3);
             data[(int)message.charAt(5)][4] = message.charAt(4);
         }
         
    }

//|                                                            |
//| + set(adresse : char, wert : char[]) : bool                |
    public boolean set(char c, char[] wert)
    {
          if((int)c>=0 && (int)c<=127 && wert!=null && wert.length>=5)
          {
                data[(int)c][0] = wert[0];
                data[(int)c][1] = wert[1];
                data[(int)c][2] = wert[2];
                data[(int)c][3] = wert[3];
                data[(int)c][4] = wert[4];
                return true;
          }
          else
          {
                return false;
          }
    }
    
//| + set(adresse : char, wert : int) : bool                   |
    public boolean set(char c, int wert)
    {
          if((int)c>=0 && (int)c<=127 && wert>=-9999 && wert<=9999)
          {
                if(wert>0)
                {
                    data[(int)c][0] = '+';
                }    
                else   
                {
                    data[(int)c][0] = '-';
                    wert = -wert;
                }    
                data[(int)c][4] = (char)(wert%10+48);
                wert/=10;
                data[(int)c][3] = (char)(wert%10+48);
                wert/=10;
                data[(int)c][2] = (char)(wert%10+48);
                wert/=10;
                data[(int)c][1] = (char)(wert%10+48);
                return true;
          }
          else
          {
                return false;
          }
    }
    
//| + set(adresse : char, wert : float) : bool                 |
    public boolean set(char c, float wert)
    {
         int w = (int)(wert*1000.0f + 0.5f);
         return set(c, w);
    }

//|                                                            |
//| + set(adresse : char, wert : char[], ip, port)             |
    public void set(char c, char[] text, String ip, int  port)
    {
        if(set(c,text)==true)
        {
             String nachricht = (new String(data[(int)c]));
             udp.send( nachricht, ip, port );
             if(LOGGING) println("Nachricht \""+nachricht+"\" an "+ip+" port:"+port+" gesendet");
        }        
        else
        {
             println("!!! ERROR !!!");
        }
    }
//| + set(adresse : char, wert : int,    ip, port)             |
    public void set(char c, int wert, String ip, int  port)
    {
        if(set(c,wert)==true)
        {
             udp.send( new String(data[(int)c]), ip, port );
             if(LOGGING) println("Nachricht \""+(new String(data[(int)c]))+"\" an "+ip+" port:"+port+" gesendet");
        }                  
    }
//| + set(adresse : char, wert : float,  ip, port)             |
    public void set(char c, float wert, String ip, int  port)
    {
        if(set(c,wert)==true)
        {
             udp.send( new String(data[(int)c]), ip, port );
             if(LOGGING) println("Nachricht \""+(new String(data[(int)c]))+"\" an "+ip+" port:"+port+" gesendet");
        }                  
    }
//|                                                            |
//| + getAsCharArray(adresse : char): char[]                   |
    public char[] getAsCharArray(char c)
    {
         if((int)c>=0 && (int)c<127)
         {
             char[] ergebnis = new char[data[(int)c].length-1];
             for(int i=0;i<data[(int)c].length-1;i++)
                 ergebnis[i] = data[(int)c][i];
             return ergebnis;    
         }
         else
         {
             return null;
         }
    }
//| + getAsInt(adresse : char) : int                           |
    public int getAsInt(char c)
    {
         if((int)c>=0 && (int)c<127)
         {
             int x = 0;
             x+=(int)data[(int)c][1]-48;
             x*=10;
             x+=(int)data[(int)c][2]-48;
             x*=10;
             x+=(int)data[(int)c][3]-48;
             x*=10;
             x+=(int)data[(int)c][4]-48;
             if(data[(int)c][0]=='-')
                x = -x;
             return x;   
         }
         else
         {
             return 0;
         }
    }
//| + getAsFloat(adresse : char) : float                       |
    public float getAsFloat(char c)
    {
         if((int)c>=0 && (int)c<127)
         {
             int x = 0;
             x+=(int)data[(int)c][1]-48;
             x*=10;
             x+=(int)data[(int)c][2]-48;
             x*=10;
             x+=(int)data[(int)c][3]-48;
             x*=10;
             x+=(int)data[(int)c][4]-48;
             if(data[(int)c][0]=='-')
                x = -x;
             return (float)x*0.001f;   
         }
         else
         {
             return 0.0f;
         }
    }
   
    //call-back-Methode, die udp per this-Übergabe
    //bekannt gemacht wird
    void receive( byte[] data, String ip, int port ) 
    {  
          refresh(data,ip,port);  
    }
}

Code 0-3: Klasse Briefkasten

Umsetzung der Klasse für einen Arduino 33 nano IoT mittels der Arduino-IDE

https://store-usa.arduino.cc/products/arduino-nano-33-iot -- Pin-Layout des Arduino nano 33 IoT
WiFiUdpSendReceiveString103_Briefkastenkonzept.zip -- Arduino-Sketch
#include "Sensordaten.h"
#include "Briefkasten.h"

Sensordaten sensordaten;
Briefkasten briefkasten;

void setup() 
{
    pinMode(13,OUTPUT);
    Serial.begin(9600);
    sensordaten.start();
    briefkasten.start("kramann3","23571113",2390,true);
    briefkasten.set('L',0);
    delay(3000);
    
}
void loop() 
{
   zeigeLokaleSensordaten();
   briefkasten.set('x',sensordaten.getAX(),"192.168.0.100",6000);
   briefkasten.refresh();

   //LED von PC aus steuern
   int LED = briefkasten.getAsInt('L');
   digitalWrite(13,LED);
   
   delay(300);
}

void zeigeLokaleSensordaten()
{
    Serial.print("SENSORDATEN LOKAL: AX=");
    Serial.print(sensordaten.getAX());
    Serial.print(" AY=");
    Serial.print(sensordaten.getAY());
    Serial.print(" AZ=");
    Serial.println(sensordaten.getAZ());
}

Code 0-4: Hauptprogramm

#include <WiFiNINA.h>
#include <WiFiUdp.h>

#define PUFFERGROESSE 6 //Idee: letzte Stelle enthält Index
#define ARRAYGROESSE 128

class Briefkasten
{
    private:
        char ergebnis[6];
        char packetBuffer[256];
        bool LOGGING;
        WiFiUDP Udp;
        char data[ARRAYGROESSE][PUFFERGROESSE];

        void udpprint(char* s) { if(Serial) Serial.print(s); }
        void udpprint(int x) { if(Serial) Serial.print(x); }
        void udpprint(uint32_t x) { if(Serial) Serial.print(x); }
        void udpprint(float x) { if(Serial) Serial.print(x); }
        void udpprint(IPAddress ip) { if(Serial) Serial.print(ip); }
        void udpprintln(char* s){ if(Serial) Serial.print(s); }
        void udpprintln(int x){ if(Serial) Serial.print(x); }
        void udpprintln(float x){ if(Serial) Serial.print(x); }
        void udpprintln(IPAddress ip) { if(Serial) Serial.print(ip); }
        void udpprintln(uint32_t x) { if(Serial) Serial.print(x); }

        uint32_t string2ip(char* s)
        {
            uint32_t IP = 0;
            int inx=0;
            // 012345678901234
            // 123.123.123.123
            uint32_t x = s[inx]-48;
            inx++;
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            inx++;            
            IP = x;

            x = s[inx]-48;
            inx++;
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            inx++;            
            IP += x<<8;

            x = s[inx]-48;
            inx++;
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            inx++;            
            IP += x<<16;

            x = s[inx]-48;
            inx++;
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            if(s[inx]!='.') {x*=10; x+=s[inx]-48;inx++;}
            inx++;            
            IP += x<<24;

            return IP;
        }
        
    public:
        bool start(char* ssid, char* pass, int localPort, bool logging)
        {
           LOGGING = logging;
           //letztes Zeichen == Index == ASCII-Variablenname
           for(int i=0;i<ARRAYGROESSE;i++)
               data[i][PUFFERGROESSE-1]=i;
          
           int err =  WiFi.begin(ssid, pass);
           if(WL_CONNECTED)
           {
              Udp.begin(localPort);
              udpprintln("UDP erfolgreich gestartet!");
              return true;
           }   
           else
           {
              udpprintln("UDP schlug fehl!");
              return false;
           }
        }
    
        /* Eine Zeichenkette in den lokalen Puffer legen */
        bool set(char c, char* s)
        {
            int index = (int)c;
            if(index>=0 && index<ARRAYGROESSE)
            {
                for(int i=0;i<PUFFERGROESSE;i++)
                    data[index][i] = s[i];
                return true;    
            }
            else
            {
                return false;
            }
        }
        bool set(char c, int x)  // Bereich +/-9999
        {
            int index = (int)c;
            if(index>=0 && index<ARRAYGROESSE)
            {
                if(x>=0)
                {
                   data[index][0]='+';
                }   
                else   
                {
                   data[index][0]='-';
                   x = -x;
                }   

                for(int i=PUFFERGROESSE-2;i>=1;i--)
                {
                    data[index][i] = x%10 + 48;
                    x/=10;
                }
                return true;       
            }
            else
            {
                return false;
            }
        }

        bool set(char c, float x)
        {
            int index = (int)c;
            if(index>=0 && index<ARRAYGROESSE)
            {
                if(x>=0)
                {
                   data[index][0]='+';
                }   
                else   
                {
                   data[index][0]='-';
                   x = -x;
                }   
                int xx = (int)(x*1000.0+0.5);

                for(int i=PUFFERGROESSE-2;i>=1;i--)
                {
                    data[index][i] = xx%10 + 48;
                    xx/=10;
                } 

                return true;
            }
            else
            {
                return false;
            }
        }

        void set(char c, char* text, char* ip, int port)
        {
             if( set(c,text) )
             {
                int index = (int)c;
                uint32_t IP = string2ip(ip);
                Udp.beginPacket(IP,port);
                Udp.write(data[index]);
                Udp.endPacket();
             }                
        }

        void set(char c, int x, char* ip, int port)
        {
             if( set(c,x) )
             {
                int index = (int)c;
                uint32_t IP = string2ip(ip);
                Udp.beginPacket(IP,port);
                Udp.write(data[index]);
                Udp.endPacket();
             }                
        }

        void set(char c, float x, char* ip, int port)
        {
             if( set(c,x) )
             {
                int index = (int)c;
                uint32_t IP = string2ip(ip);
                Udp.beginPacket(IP,port);
                Udp.write(data[index]);
                Udp.endPacket();
             }                
        }

        char* getAsCharArray(char c)
        {
             ergebnis[0] = data[(int)c][0];
             ergebnis[1] = data[(int)c][1];
             ergebnis[2] = data[(int)c][2];
             ergebnis[3] = data[(int)c][3];
             ergebnis[4] = data[(int)c][4];
             ergebnis[5] = 0;
             return ergebnis;
        }

        int getAsInt(char c)
        {
            int x=0;
            x+=data[(int)c][1]-48;
            x*=10;
            x+=data[(int)c][2]-48;
            x*=10;
            x+=data[(int)c][3]-48;
            x*=10;
            x+=data[(int)c][4]-48;
            
            if(data[(int)c][0]=='-')
                x = -x;
                
            return x;
        }

        int getAsFloat(char c)
        {
            int x=0;
            x+=data[(int)c][1]-48;
            x*=10;
            x+=data[(int)c][2]-48;
            x*=10;
            x+=data[(int)c][3]-48;
            x*=10;
            x+=data[(int)c][4]-48;
            
            if(data[(int)c][0]=='-')
                x = -x;
                
            return (float)x*0.001;
        }



        int refresh()
        {
            int len = 0;
            
            int packetSize = Udp.parsePacket();
            if(packetSize) 
            {
                udpprint("Received packet of size ");
                udpprintln(packetSize);
                udpprint(" From ");
                IPAddress remoteIp = Udp.remoteIP();
                udpprint(remoteIp);
                udpprint((uint32_t)Udp.remoteIP());
                
                

                // read the packet into packetBufffer
                len = Udp.read(packetBuffer, 255);
                if (len > 0) 
                {
                    packetBuffer[len] = 0;
                }

                if(len>1)
                {
                    //... also wurde etwas für einen der Briefkästen empfangen:
                    data[packetBuffer[5]][0] = packetBuffer[0];
                    data[packetBuffer[5]][1] = packetBuffer[1];
                    data[packetBuffer[5]][2] = packetBuffer[2];
                    data[packetBuffer[5]][3] = packetBuffer[3];
                    data[packetBuffer[5]][4] = packetBuffer[4];                  
                }
                
                udpprint(" Contents: ");
                udpprintln(packetBuffer);
             }

             return len; //Länge des ggf. empfangenen Pakets wird zurückgegeben
        }
        
};

Code 0-5: Klasse Briefkasten

#include <SPI.h>
#include <Arduino_LSM6DS3.h>

#include "Arduino.h"

class Sensordaten
{
  private:
  
    // Accelerometer Daten "globalisieren"
    float ax=0.0, ay=0.0, az=0.0;
    // Gyroscope Daten "globalisieren"
    float gx=0.0, gy=0.0, gz=0.0;

  public:
    void start()
    {
        IMU.begin();
    }

    float getAX() 
    {
         if (IMU.accelerationAvailable()) 
             IMU.readAcceleration(ax, ay, az);
         return ax;   
    }
    float getAY() 
    {
         if (IMU.accelerationAvailable()) 
             IMU.readAcceleration(ax, ay, az);
         return ay;   
    }
    float getAZ() 
    {
         if (IMU.accelerationAvailable()) 
             IMU.readAcceleration(ax, ay, az);
         return az;   
    }

    float getGX() 
    {
        if (IMU.gyroscopeAvailable()) 
            IMU.readGyroscope(gx, gy, gz);
         return gx;   
    }

    float getGY() 
    {
        if (IMU.gyroscopeAvailable()) 
            IMU.readGyroscope(gx, gy, gz);
         return gx;   
    }

    float getGZ() 
    {
        if (IMU.gyroscopeAvailable()) 
            IMU.readGyroscope(gx, gy, gz);
         return gx;   
    }

    
};

Code 0-6: Klasse Sensordaten

Screenshot: Links ist der Serial Monitor, rechts ist das Processing-Fenster.

Bild 0-3: Screenshot: Links ist der Serial Monitor, rechts ist das Processing-Fenster.

Arduino nano 33 IoT mit bei Digital-IO-Pin 13 angeschlossener LED mit Vorwiderstand (220Ohm).

Bild 0-4: Arduino nano 33 IoT mit bei Digital-IO-Pin 13 angeschlossener LED mit Vorwiderstand (220Ohm).