Wir entwickeln ein Gateway zwischen Wi-Fi und LoRa für UDP

Ich hatte einen Kindheitstraum — jedes „Wi-Fi-freie“ Gerät mit einem Ticket ins Netzwerk auszustatten, also mit einer IP-Adresse und einem Port. Nach einer Weile wurde mir klar, dass ich nicht länger warten sollte. Ich muss es einfach angehen und umsetzen.
Technisches Lastenheft
Erstellen Sie ein Gateway mit M5Stack und installiertem LoRa-Modul (Abbildung 1). Das Gateway wird mit dem Wi-Fi-Netzwerk verbunden, um eine lokale IP-Adresse über DHCP zu erhalten. In bestimmten Intervallen wird das Gateway seinen Namen (vergleichbar mit SSID für Wi-Fi) und den Bereich verfügbarer Ports in den „LoRa-Ether“ senden, damit andere Geräte wissen, dass es ein Netzwerk gibt, mit dem sie sich verbinden können und in welchem Bereich sie einen freien Port auswählen können. Da dies ein Prototyp sein wird, erfolgt keine Authentifizierung in diesem Schritt. Neue Client-Geräte finden das verfügbare LoRa-Netzwerk und übermitteln den gewählten Port. Nachdem das Gateway den Port vom neuen Client erhalten hat, prüft es, ob er frei ist. Wenn ja, registriert es den neuen Client und beginnt, diesen Port auf seinem eigenen asynchronen UDP-Server zu überwachen. Nach der Registrierung erhält der Client die Zustimmung oder Ablehnung zur Nutzung des beantragten Ports. Der Ablauf wird in Tabelle 1 dargestellt.

Abbildung 1
Tabelle 1
Seite
Richtung und Daten
Seite
Sitzung
[ Kunde ]
<— Signal-Leuchtturm —
[ Gateway ]
0xA1
[ Kunde ]
— ausgewählter Port —>
[ Gateway ]
0xB1
[ Kunde ]
<— Zustimmung oder Ablehnung —
[ Gateway ]
0xA2
[ Kunde ]
— UPD-Paket —>
[ Gateway ]
0xB2
[ Kunde ]
<— UPD-Paket —
[ Gateway ]
0xA3
[ Netzwerk ]
<— UPD-Paket —
[ Gateway ]
0xC1
Vor mir auf dem Tisch liegen verschiedene Module für M5Stack und warten darauf, benutzt zu werden. Lassen Sie uns das LoRa-Modul nehmen und ein wenig damit experimentieren. Die Idee der Module ist großartig! Was kann man dazu sagen? Aber ich habe die erste Version der Module, die eine schreckliche integrierte Antenne hat, die auf einer flexiblen Leiterplatte ausgeführt und an der Seitenwand des Gehäuses befestigt ist. Ich habe einmal Feldtests mit solchen Modulen durchgeführt (man kann sich das auf einem russischsprachigen YouTube-Kanal ansehen):

Natürlich musste ich diese Überbleibsel entfernen und die Standard-Drahtantennen einlöten, die mit dem Ra-01 mitgeliefert werden. Nach dieser Anpassung hat sich die Reichweite der Verbindung deutlich verbessert, aber es gibt einen Nebeneffekt – die Antenne hat einen größeren Durchmesser als der zulässige Abstand zwischen den Modulen. Ich musste auf den Abschlussmodul vorübergehend verzichten.
Die ersten Schwierigkeiten aufgrund synchroner Steifheit
Es scheint, ergreife einfach die Bibliothek WiFiUdp.h, wo alles für das komfortable Betreiben eines UDP-Servers bereitsteht, das ist jedoch nicht der Fall. Die Bibliothek ist darauf ausgelegt, einen synchronen Server zu betreiben, der bedauerlicherweise nicht mehrere Verbindungen in einem einzigen Thread gleichzeitig bedienen kann. Eine solche Bibliothek eignet sich nicht für die aktuelle Aufgabe. Daher mussten viele Tassen Tee getrunken werden und nach einer Bibliothek gesucht werden, die es erlaubt, einen asynchronen UDP-Server hochzufahren, der in der Lage ist, viele Verbindungen gleichzeitig zu unterstützen. Eine solche Bibliothek wurde gefunden — AsyncUDP.h. Was ist also der Unterschied zwischen einem synchronen und einem asynchronen Server? Lassen Sie uns sechs Szenarien in Abbildung 2 betrachten, die die Arbeitsweisen der Sockets anschaulich darstellen.

Abbildung 2
In den Hauptrollen:
Mensch in der Rolle von Socket;
Taube in der Rolle von Verbindung;
Brief in der Rolle von Daten.
Episode A. Synchroner Socket ohne Timeout
Der Mensch wird stehen bleiben, bis die Taube ihm den Brief bringt.
Episode B. Synchroner Socket mit Timeout
Der Mensch wartet die vereinbarte Zeit mit der Taube ab, und wenn diese nicht rechtzeitig kommt, wird der Mensch gehen.
Episode C. Synchroner Socket mit Multithreading
Der Mensch faulenzt und beobachtet, wie die Tauben selbstständig die Briefe zustellen.
Episode D. Asynchroner Socket (wenn es nichts zu empfangen gibt)
Eine Person beschäftigt sich mit ihren Lieblingsbeschäftigungen, vergisst jedoch nicht die Tauben.
Episode E. Asynchroner Socket (wenn es etwas zu empfangen gibt)
Eine Person lenkt sich kurz von ihren Angelegenheiten ab, um einen Brief von der Taube zu erhalten.
Episode F. Asynchroner Socket mit Multithreading
Eine Person beschäftigt sich mit ihren Angelegenheiten und beobachtet, wie die Tauben selbstständig Briefe zustellen.
Wenn Sie aufmerksam waren, haben Sie sicherlich bemerkt, dass die Halsbänder der Tauben in jeder Episode eine bestimmte Farbe haben. Und das ist kein Zufall. In den Episoden A und B arbeitet nur ein Socket auf dem Server, und das war's. In Episode C arbeiten bereits zwei Sockets. In den Episoden D, E und F sind es dann drei Sockets. 'Warum sind da zwei und hier drei?', fragen Sie sich vielleicht. Dies ist bedingt 2 und 3; tatsächlich kann es statt 2 auch 20 und statt drei 200 sein. Es geht darum zu zeigen, dass asynchrone Sockets die Hardware nicht so stark belasten wie synchrone.
Wie viel Platz für was?
Betrachten wir Tabelle 1, die die Struktur eines UDP-Pakets zeigt, und überlegen wir, was damit gemacht werden kann.
Tabelle 1. Struktur eines UDP-Pakets
Bits
0 — 15
16 — 31
0-31
Quellport (Source port)
Zielport (Destination port)
32-63
Länge der Datagramme (Length)
Prüfziffer (Checksum)
64-…
Daten (Data)
Fügen wir ein weiteres Feld an den Anfang dieser Tabelle hinzu. Session (1 Byte). Das reicht für dieses Projekt aus. Basierend auf der Session wird das Gerät wissen, was mit dem Paket als Nächstes zu tun ist. Lassen Sie uns jetzt Codes für die Sessions erstellen und diese in Tabelle 2 eintragen.
Tabelle 2. Erläuterung zu Sessions
Code
Titel
Erklärung
0xA1
Beacon
Das Gateway sendet den Namen des LoRa-Netzwerks und den gültigen Portbereich in regelmäßigen Abständen. Dies ist notwendig, damit neue Clients das verfügbare Netzwerk sehen und aktuelle Clients, wenn keine Übertragungen stattfinden, das Signalniveau bestimmen können.
0xB1
Anfrage
Wenn der Client das Netzwerk entdeckt, sendet er den bevorzugten Port.
0xA2
Zustimmung oder Ablehnung
Wenn der angeforderte Port frei ist, antwortet der Server mit Zustimmung, andernfalls mit Ablehnung.
0xB2
Up-Link
Wenn der Client ein UDP-Paket an das Gateway sendet.
0xA3
Down-Link
Wenn das Gateway ein UDP-Paket an den Client sendet.
0xC1
Fortsetzung des Up-Links
Wenn das Gateway ein UDP-Paket ins lokale Netzwerk sendet.
Gut. Lassen Sie uns nun die Zusammensetzung der Sessions in Tabelle 3 besprechen.
Tabelle 3. Sessions
Sessionname
Zusammensetzung
Beacon
Session-Code (1 Byte) + Name des LoRa-Netzwerks (4 Byte) + Startport (2 Byte) + Endport (2 Byte)
Anfrage
Übertragungs-Code (1 Byte) + Name des LoRa-Netzwerks (4 Bytes) + Bevorzugter Port (2 Bytes)
Zustimmung oder Ablehnung
Übertragungs-Code (1 Byte) + Name des LoRa-Netzwerks (4 Bytes) + Bevorzugter Port (2 Bytes) + Ergebnis (1 Byte)
Up-Link
Übertragungs-Code (1 Byte) + Name des LoRa-Netzwerks (4 Bytes) + Remote-IP-Adresse (4 Bytes) + Remote-Port (2 Bytes) + Lokale-IP-Adresse (4 Bytes) + Lokaler Port (2 Bytes) + Datengröße (2 Bytes) + Daten
Downlink
Übertragungs-Code (1 Byte) + Name des LoRa-Netzwerks (4 Bytes) + Remote-IP-Adresse (4 Bytes) + Remote-Port (2 Bytes) + Lokale-IP-Adresse (4 Bytes) + Lokaler Port (2 Bytes) + Datengröße (2 Bytes) + Daten
Fortsetzung des Up-Links
Remote-IP-Adresse (4 Bytes) + Remote-Port (2 Bytes) + Datengröße (2 Bytes) + Daten
Ich habe zwei Clients für Arduino und M5Stack geschrieben. Auf können Sie sehen, wie das funktioniert. Innerhalb der Wohnung gibt es keine Probleme, praktische Tests habe ich bisher noch nicht durchgeführt.
Der Quellcode ist auf GitHub verfügbar unter
Mehr über das Basisgerät M5Stack erfahren und kaufen können Sie
Wählen Sie drahtlose LoRa-Module für das Basisgerät aus
Es würde mich freuen, wenn dieses Projekt Ihnen nützlich ist. Vielen Dank für Ihre Zeit!
Literaturliste und (oder) Quellen:
Quelle: habr.com
