Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tpbridge

Eine TP-Brücke ohne ETS: mehrere TP-Linien an einem Gerät, gekoppelt nach Regeln, die im Quelltext stehen. Kein Applikationsprogramm, kein Download, keine Inbetriebnahme - flashen, und es koppelt. Gedacht für Fälle, in denen eine Kopplung ohne ETS-Abhängigkeit gebraucht wird, typisch zum Debuggen.

Die Filterung ist damit übersetzt und nicht geladen: wer sie ändert, flasht. src/main.cpp ist die Konfiguration, alles andere ist Mechanik.

pio run -e pico -t upload -t monitor
pio run -e esp32

Die tpuart-Library kommt über lib_deps aus ihrem Repo, der Stand steht in platformio.ini. Wer an ihr selbst arbeitet, legt sie als Symlink nach lib/tpuart - siehe AGENTS.md.


Interfaces

Ein Interface ist der Weg zum Transceiver. Die Library bringt drei mit, dieses Projekt benutzt sie über den gemeinsamen Basistyp TPUart::Interface::Abstract:

Interface Konstruktor Anmerkung
Interface::RP2040 (rx, tx, uart) Hardware-UART, Empfang per DMA. Der belastbare Weg.
Interface::ArduinoSerial<SerialPIO> SerialPIO(tx, rx, fifo) PIO-UART auf beliebigen Pins. (tx, rx) — umgekehrt!
Interface::ESP32 (rx, tx, uart) ESP-IDF-Treiber.

Interfaces erst in setup() anlegen

TPUart::Interface::Abstract *interfaceTp1 = nullptr;      // global nur der Zeiger

void setup()
{
    interfaceTp1 = new TPUart::Interface::RP2040(17, 16, uart0);

Als globales Objekt funktioniert Interface::RP2040 nicht: sein Konstruktor beansprucht einen DMA-Kanal und beschreibt dessen Register, und das läuft vor main() — was der Arduino-Core danach an der Hardware zurechtsetzt, sieht diese Konfiguration nicht mehr. Der Empfang bleibt dann tot, ohne jede Fehlermeldung: der Zustand kommt nie über Uninitialized hinaus und rx bleibt bei 0 Byte.

SerialPIO und Interface::ESP32 dürfen statisch stehen, ihre Konstruktoren fassen keine Hardware an — aber einheitlich spät anzulegen ist billiger als die Ausnahme zu merken.

Pins

Auf dem RP2040 sind die UART-Pins nicht frei wählbar: uart0 kann TX 0/12/16/28 und RX 1/13/17/29, uart1 TX 4/8/20/24 und RX 5/9/21/25. SerialPIO kann jeden Pin; was dort am Bus aufgefallen ist, steht in AGENTS.md.

Auf dem ESP32 prüft uart_set_pin() nicht, ob ein Pin frei ist. Liegt dort der eingebaute Flash oder PSRAM, bootet das Board still im Kreis — ohne ein einziges Zeichen Ausgabe.


Linien und Regeln

Eine Linie entsteht aus einem Interface, die Reihenfolge der Aufrufe bestimmt den Namen in der Ausgabe:

Line &tp1 = bridge.addInterface(*interfaceTp1);   // heisst TP1
Line &tp2 = bridge.addInterface(*interfaceTp2);   // heisst TP2

Die Regeln einer Linie sagen, was HINTER ihr liegt — nicht, was sie durchlässt. Das ist der Denkschritt, an dem alles hängt: tp1.permitUnicast("1.1") heißt „die Linie 1.1 ist über TP1 erreichbar", und daraus folgen Quittung und Weiterleitung.

Unicast: physikalische Adressen

Nur Koppler, also zwei Stellen — ein einzelnes Gerät ist keine gültige Angabe:

Muster Greift für Eigene Adresse
"1.1" 1.1.01.1.255 1.1.0 (Linienkoppler)
"1.0" oder "1.*" 1.0.01.15.255 1.0.0 (Bereichskoppler)
"*" jede physikalische Adresse keine

Eine Linie 0 gibt es deshalb nicht: 1.0 ist der Bereichskoppler. Die Koppleradresse der ersten permit-Regel geht per setOwnAddress() an den Chip — dessen Auto-Quittung kennt genau eine Adresse, alles Weitere entscheidet die Brücke selbst.

Broadcast: Gruppenadressen

Je Stelle eine Zahl oder *:

tp1.permitBroadcast("12/*/12");
tp1.permitBroadcast("12/*/*");
tp1.permitBroadcast("*/*/10");
tp1.permitBroadcast("*");        // alle

Dreistufig, wie oben — die zweistufige Schreibweise (12/2000) nimmt der Parser nicht. Ein Muster mit Tippfehler wird abgelehnt und gemeldet, nicht stillschweigend anders ausgelegt.

Platz ist für 8 Unicast- und 16 Broadcast-Regeln je Linie (MAX_UNICAST_RULES, MAX_BROADCAST_RULES); eine Regel darüber wird abgelehnt und gemeldet.

Reihenfolge: erste passende Regel gewinnt

tp1.denyBroadcast("12/*/*");   // erst die Ausnahme
tp1.permitBroadcast("*");      // dann alles Uebrige

Andersherum geschrieben ist dasselbe deny toter Code — und das fällt nicht auf, weil beides übersetzt und läuft. Passt keine Regel, ist die Linie für dieses Ziel nicht zuständig.


Quittung

Der Kniff, und er folgt direkt aus „die Regeln sagen, was hinter der Linie liegt":

Kommt auf TP2 ein Telegramm herein, quittiert TP2 genau dann, wenn eine andere Linie das Ziel erlaubt — denn nur dann kann es weitergegeben werden.

Zwei Einschränkungen dazu:

  • Unicast auf der Empfangslinie selbst wird nicht quittiert. Dort antwortet das Gerät.
  • Gruppenadressen schon — die hören mehrere, und die Quittung ist auf TP1 ein verdrahtetes Oder.

Mit einer einzigen Linie wird nichts quittiert, es gibt kein Gegenüber. Der Hochlauf sagt das.

Gerechnet wird das beim Hochlauf für jede der 65536 Adressen; im Tick kostet die Entscheidung zwei Speicherzugriffe (Tabellen, ~768 Byte je Linie). Das ist nötig, weil die Quittung binnen 2,8 ms auf dem Bus sein muss und die Entscheidung auf dem RP2040 im Interrupt fällt.

Alles quittieren

tp1.setAcknowledgeAll(true);

Umgeht die Regeln vollständig — auch Ziele auf der Linie selbst und solche, die keine andere Linie erlaubt. Das ist eine Lüge auf den Bus: der Absender hält sein Telegramm für angekommen, obwohl niemand es weitergibt. Zum Messen (Buslast, Timing, Wiederholungsverhalten) genau richtig, im Betrieb als Koppler falsch. Weitergeleitet wird davon nichts zusätzlich.


Weiterleitung

Dieselbe Regelauswertung wie bei der Quittung — sonst verspräche die Quittung eine Zustellung, die nicht stattfindet. Ein Telegramm geht in die Sendewarteschlange jeder anderen Linie, die es erlaubt und verbunden ist.

Nicht weitergegeben werden: kaputte Telegramme, eigene Echos, erkannte Wiederholungen, und alles zu einer Linie, die gerade nicht verbunden ist.

Der Hop Count wird heruntergezählt. Ohne das kreist ein Telegramm zwischen zwei Linien, bis ein anderer Koppler es abwürgt — am Bus beobachtet als dasselbe Telegramm mit Hop 6, 4, 2, 0. Er steht im Steuerfeld hinter den Adressen (Standard Byte 5, Extended Byte 1, Bits 6-4); 7 heißt „nicht zählen", 0 heißt verbraucht und wird verworfen. Weil das die Prüfsumme mitzieht und die Library sie beim Einreihen prüft statt neu zu rechnen, geht eine Kopie mit eigener CRC auf die Reise.


Konsole

Ein Zeichen je Befehl, kein Zeilenpuffer:

Taste Wirkung
Enter Leerzeile als Marke im Mitlesen
i Zustand und Regeln je Linie
s die Zähler je Linie
m Telegrammausgabe an/aus (Vorgabe: aus)
h ? Kurzhilfe

Zyklisch gibt die Brücke nichts aus. Kaputte Telegramme kommen unabhängig davon immer, in Rot.

m schaltet nur die Ausgabe — der Busmonitor-Modus des Chips wird nicht angefasst, der macht ihn transparent und als Koppler unbrauchbar.

Zahlen aus s, die etwas sagen

Feld Bedeutung
forwarded in von anderen Linien übernommen
rejected nicht angenommen: nicht verbunden oder Warteschlange voll
hop exhausted hier hereingekommen mit Hop Count 0
no con gesendet, aber vom Chip nicht bestätigt
peak tx Spitze der Sendewarteschlange — Rückstau
max run / ack längster Tick, längste Quittungsentscheidung (µs)
overflow … muss 0 bleiben

Wiederholungen und Quittung

setRepetitions(0, 0) heißt: jedes Telegramm geht genau einmal auf den Bus, statt nach der Chip-Vorgabe bis zu dreimal. Das macht eine Mitschrift eindeutig — und reicht auch beim Koppeln, denn Wiederholungen heilen keinen fehlenden Abnehmer. Wer auf eine Linie schiebt, auf der niemand zuhört, bekommt keine Quittung, und dann eben dreimal keine. Die Frage ist die Filterung, nicht die Wiederholungszahl.

setAcknowledgeAll(true) ist eine Präferenz, keine Betriebsart:

  • aus — quittiert wird nur, was weitergegeben werden kann. Die Quittung sagt die Wahrheit, und ein Telegramm ohne Abnehmer bleibt sichtbar unquittiert (no con in der Statistik).
  • an — quittiert wird alles. Der Bus bleibt ruhig, weil fremde Sender nicht wiederholen; die Quittung behauptet dafür eine Zustellung, die von der Filterung nicht gedeckt ist.

About

KNX TP bridge without ETS - TP lines coupled by rules that live in the source, built on the tpuart library

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages