Support für BiDiB

FAQ

Hier sind Fragen und Antworten zur Implementierung von BiDiB gesammelt:

Ich möchte in meinem Steuerprogramm BiDiB implementieren, was muss ich alles einbauen?

Welchen Funktionsumfang ein Steuerprogramm implementiert, liegt im Ermessen des Steuerprogrammes. Es ist z. B. möglich, dass sich ein Konfigurationsprogramm auf Ports und Makros sowie Firmwareupdate konzentriert, ein Fahrprogramm hingegen Rückmeldungen, Fahrbefehle und Accessory implementiert und sich nicht um die Details und Konfiguration der einzelnen Ports kümmert.

Verpflichtend ist jedoch die Absicherung der Datenübertragung und die Grundfunktionen wie Knoten einlesen und darstellen.

Wie muss ich die verschiedenen Protokollversionen in meinem Programm behandeln?

BiDiB ist so angelegt, dass volle Rückwärtskompatibilität möglich ist. Dazu soll beim Einlesen jedes Knotens mit MSG_SYS_GET_P_VERSION und MSG_SYS_GET_MAGIC begonnen werden. Aus diesen Informationen ist erkennbar, welche Nachrichten der Knoten unterstützt bzw. auch welche er nicht (mehr) unterstützt, sowie welches Zustandsmodell verwendet wird und welche Features einzulesen sind.

Wie damit umgegangen wird kommt nun ganz auf die Software an, hier sind auch unterschiedliche Releasezyklen der Komponenten zu beachten. Alte Protokollversionen sollten soweit möglich mittels eines Kompatibilitäts-Layers unterstützt werden. Ist dies nicht möglich oder zu aufwendig, muss die eingeschränkte Kompatibilität in der Anleitung dokumentiert werden.

Wird eine veraltete oder unbekannte neue Protokollversion erkannt, die nicht oder nicht vollständig unterstützt wird, ist eine Warnung (eingeschränkte Funktionalität) bzw. Fehlermeldung ("bitte updaten") angebracht. Gerade für Vorwärtskompatibilität ist es aber wichtig, die Funktion und Benutzbarkeit der Software aufrechtzuerhalten. Unbekannte Nachrichtentypen, Nachrichtenparameter, Features, Konfiguratons-Enums etc. sollen einfach ignoriert werden.

Gibt es eine Übersicht für Steuerungsprogramme, wie man die Daten mit welchen Eigenschaften (seriell, Baudrate, USB, Netzwerk mit Portnummer) übertragen kann, welche Interfaces gibt es?

Das Protokoll unterscheidet zwischen Nachrichteninhalt (Payload) und Transportweg. Die Transportwege und deren Absicherung sind im Reiter 'Transport' beschrieben.

Aktuell (Stand 2016) sind 3 Interfaces am Markt: Tams S88-BiDiB, GBMBoost und BiDiB-IF2, alle basieren auf USB mit virtuellem seriellen Port.

Wo sind die genauen Message-Nummern definiert?
Es gibt eine verpflichtende Header-Datei, in dieser sind die Nachrichtennummern definiert. Innerhalb von Programmen soll immer nur diese header-Datei verwendet werden und die Nachrichtennummern über den #define eingesetzt werden. Diese Datei ist File-Bereich der BiDiB-Implement-Gruppe zu finden.
Ich habe ein BiDiB-System und habe Verbindung mit dem ersten Modul, wie komme ich an das zweite?

Wenn das erste Modul ein Hub/Interface ist, dann kann man dieses Modul nach der aktuellen Zuordnung Nodes zu lokalen Adressen fragen: MSG_NODETAB_GETALL. Damit bekommt man eine Liste, welche Baugruppen mit welcher UNIQUE_ID da angeschlossen sind und welche lokale Adresse diese aktuell haben. Über die lokale Adresse wird das dann wie folgt angesprochen:

  • Mit 00 adressiert man das Interface.
  • Mit 01 00 adressiert man den Knoten mit der lokalen Adresse 1
  • Mit 02 00 adressiert man den Knoten mit der lokalen Adresse 2

Angenommen, auf lokaler Adresse 2 sei ein weiterer Hub:

  • Mit 02 05 00 adressiert man den Knoten mit der lokalen Adresse 5 hinter diesem Hub.

Achtung: bei nächsten Einschalten kann die Liste anders sein (hängt vom Logon ab), man muss also immer über die UNIQUE_ID gehen. Ein Liste der möglichen UNIQUEs als xml-Datei ist auf Anfrage verfügbar.

Was ist Broadcast und welche Nachrichten sind davon betroffen?

Bei bestimmten Zustandsübergängen und Nachrichten ist es erforderlich, dass alle Knoten im System möglichst zeitnah diese Nachrichten erhalten, wie z. B. die Uhrzeit. Ein solche Nachricht wird daher nur an das erste Interface übergeben, dieses sorgt selbst für eine Weiterverteilung an alle nachgeordneten Knoten.

Folgende Nachrichten werden als Broadcast gesendet:

  • MSG_SYS_ENABLE, MSG_SYS_DISABLE: Freigabe oder Sperren von Spontannachrichten.
  • MSG_SYS_CLOCK: Übermittlung der Uhrzeit
  • MSG_BOOST_ON, MSG_BOOST_OFF (jedoch nur, wenn das erste Datenbyte den Wert 0 hat): Übermittlung des Boosterzustandes
  • MSG_LOCAL_ACCESSORY: Legacy-Verteilung von DCC-Accessorynachrichten

Es ist zu beachten, dass ein neu angemeldeter Knoten nichts von vergangenen Broadcasts weiß, dieser neue Knoten muss dann individuell mit dem System- bzw. Boosterstatus versorgt werden.

Auf der RS485-Seite wird, im Gegensatz zur Host-Seite, dem Paket noch ein Package Length-Byte vorangestellt?
<MAGIC><P_LENGTH><M_LENGTH><MESSAGE>...<M_LENGTH><MESSAGE><CRC><MAGIC>

Das ist nur teilweise richtig. Beim BiDiBus ist ja das Framing bereits mittels der Sendeerlaubnis durch die TOKEN sichergestellt, eine MAGIC wird also hier nicht mehr benötigt. Das komplette Paket sieht wie folgt aus:

<TOKEN><P_LENGTH><M_LENGTH><MESSAGE>...<M_LENGTH><MESSAGE><CRC>

wobei der Token von Interface gesendet wird. Auch das 'Escaping' entfällt auf der RS485-Seite.

Nachdem sich ein Knoten am Interface angemeldet hat und vom Interface mit MSG_NODE_NEW an den Host gemeldet wurde, welche Nachrichten schickt der Host an den Knoten?
Hier kommen beispielsweise folgende Anfragen: MSG_SYS_PING, MSG_SYS_GET_SW_VERSION, MSG_SYS_GET_P_VERSION MSG_NODETAB_GETALL, dann eine Folge MSG_NODETAB_GETNEXT, welche nach den ersten Antworten zur NODETAB gesendet werden. MSG_NODETAB_GETNEXT wird solange wiederholt, bis die NODETAB komplett gelesen ist.
Der Host adressiert den Knoten direkt mit Adresse 0x01 0x00 (zum Beispiel). Das Interface kann diese Anfragen an den Knoten weiterleiten und den Knoten mit POLL 0x01 zum Antworten freigeben. Wie adressiert der Knoten das Antwortpaket an den Host?
Das Interface gibt eine Sendefreigabe (POLL durch senden eines TOKEN mit gesetztem 9.Bit) für einen bestimmten Knoten, wenn eine Antwort kommt, dann weiß das Interface ja, von wem. Das Interface fügt dann selbst die aktuelle Knotenadresse zur Adresse der Nachricht vorne dazu.
Hat das Interface auch eine Adresse und wird die Unique_ID des Interface als Knoten an den Host gemeldet?

Ja. Es hat die lokale Adresse 0 und das Interface wird gemeldet, wie jeder andere Knoten auch. Das Interface darf auch selbst Funktionen haben, wie z. B. selbst Melderbits oder DCC-Ausgabe haben.

Auch jeder Knoten ohne Interfacefunktion antwortet bei der Frage nach seiner Nodetabelle mit einer (statischen) Tabelle, in welcher nur eine Eintrag mit der Adresse 0 steht.

Mir fehlt da die trennende 0, wenn ich eine Nodetabelle lese.

Die Nodetabelle enthält nur die Zuordnung in einer Ebene, nicht den gesamten Adressstack. Darum ist das Adressbyte in der Nodetabelle nur ein Byte groß.

Ein Hub hat eine recht beschränkte Sicht auf den Bus, ihm ist nicht bekannt, in welcher Ebene er ist. Nach oben sieht er ein Interface, an dass er die erhaltenen Nachrichten abliefert, dabei ergänzt er den Adressstack mit seiner aktuellen lokalen Adressen.

Wie funktioniert das mit Hubs und der Subadresse?

Eine Nachricht hat einen Adressstack, dieser bestimmt, wie die Nachricht in BiDiB-System verteilt wird. Beispiel:

4.3.0+Nachricht

Das wird wie folgt interpretiert: der angesprochene Node schaut sich das erste Byte der Adresse an, sieht eine 4 und entscheidet: ist nicht für mich, sondern für SubNode 4. Schickt das Paket also weiter zu SubNode 4, entfernt aber die 4 vom Adressstapel.

3.0+Nachricht

SubNode 4 schaut die Adresse an, sieht eine 3 und entscheidet: ist nicht für mich, sondern für SubNode 3. Er schickt also das Paket weiter zu SubNode 3, entfernt aber die 3 vom Adressstapel.

0+Nachricht

SubNode 3 schaut die Adresse an, sieht eine 0 – und bearbeitet die Nachricht.

Wie setzt sich die Unique-ID zusammen, wie muss ich das auswerten?

Die Unique_ID besteht aus Herstellerkennung (VID, 8 Bit) und einer 32-Bit-Zahl (4 Bytes), welche PID und Seriennummer enthält. Die Aufteilung dieser 32-Bit liegt im Ermessen des Herstellers und wird mit dem Feature FEATURE_RELEVANT_PID_BITS dem Hostsystem bekannt gegeben.

Die 32 Bit werden immer little endian interpretiert, die LSBs sind die PID, der Rest ist die Seriennummer.

Beispiel:

Byte 3…7 (also 32 Bit) seien 0xAA 0xBB 0xCC 0xDD, FEATURE_RELEVANT_PID_BITS habe den Wert 10.

PID: 0x3AA (das erste Byte und die untersten beiden Bits des zweiten Bytes)

Serial: 0x37732E (die restlichen Bits, um 10 Bit nach unten geschoben)

Codebeispiel zur Auswertung:


unsigned long pid_and_serial;
unsigned long pid, serial;
pid_and_serial =  le32_to_cpu((unsigned long *)&unique[3]);
pid = pid_and_serial & ( (1 << FEATURE_RELEVANT_PID_BITS) -1 );
serial = pid_and_serial >> FEATURE_RELEVANT_PID_BITS;

le32_to_cpu() steht für das auf vielen Plattformen verfügbare Makro zum Konvertieren einer Little-Endianess-Zahl auf die interne CPU Darstellung.

Wie wird die Vergabe dieser Zahl bei der Herstellerkennung 13 (DIY gemäß NMRA) geregelt?
Für Selbstbauprojekte wird diese 32 Bitzahl in zwei 16 Bitzahlen aufgeteilt: die ersten beiden Bytes sind eine Produkttypkennung, die letzten beiden Bytes sind eine Seriennummer. Jede Zahl wird mit Little-Endian (LSB first) übertragen. Die Produktkennung wird in Absprache mit www.opendcc.de vergeben.
Sind denn Fehlermeldungen immer zusätzliche Nachrichten oder ersetzen sie eine normale Antwort?

Das hängt von der Fehlermeldung ab. Beispielsweise beschwert sich ein Knoten über eine falsche Sequenz, behandelt aber die Nachricht ansonsten ganz normal. Und der Knoten nimmt fortan diese 'falsche' Sequenznummer als Ausgangspunkt für das weitere Sequencing.

Bei einer falschen CRC kommt nur die Fehlermeldung zurück und das Paket wird verworfen. Hier kommt dann die normale Antwort nicht mehr.

Ich erhalte immer BIDIB_ERR_SEQUENCE, warum?
a) Jeder Knoten hat eine eigene Sequenzüberprüfung, d.h. der Host muss für jeden Knoten die Sequenznummer separat verwalten. D.h., jeder Knoten prüft, ob die Sequenz in seinem Empfangsbuffer korrekt ist.
b) Die Sequenz ist ein Byte (8-Bit) und ist umlaufend, wobei die 0 ausgelassen wird: ... 253, 254, 255, 1, 2, 3, ...
Was wird mit der IDENTIFY-Taste programmiert?
Die Identify-Taste programmiert überhaupt nichts, sie dient zur Auffindung von Knoten. Da ja der Anwender keine Adressen mehr vergibt, muss es eine Möglichkeit geben, damit man die Zuordnung vom Objekt im Hostprogramm zur Baugruppe überprüfen kann: Das erfolgt mittels IDENTIFY: drückt man an der Baugruppe auf IDENTIFY, so soll das entsprechende Objekt in Hostprogramm blinken. Und umgekehrt: löst man im Hostprogramm IDENTIFY aus, so muss die Baugruppe blinken.
Kommt jede Nachricht einzeln?

Nein. Bei BiDiB ist gewollt, dass Nachrichten gebündelt werden. Das hat folgenden Gründe:

  • Der Overhead eines Protokolls steigt prozentual an, je kleiner die Nachrichten sind. Adressierung, Datensicherung usw. ist konstant, die Nutzbytes (payload) sind bei kleinen Nachrichtengrößen aber wenig.
  • Die Reaktionszeit ist um so besser, je kleiner die Nachrichten sind.

BiDiB löst diesen Zielkonflikt dadurch, dass Nachrichten gebündelt werden dürfen – d.h. das Protokoll wird automatisch effizienter, wenn mehr Daten transportiert werden müssen. Diese Bündelung kann auf jedem Transportlayer erfolgen und sie kann unterschiedliche Nachrichten (auch von verschiedenen Endknoten) umfassen. Die Bündelung erfolgt nur bis max. zulässigen Paketgröße des jeweiligen Transportlayers (bei BiDiBus z. B. 64 Bytes).

Muss ich immer auf die Antwort einer Nachricht warten?

Nein, man darf (und soll) durchaus mehrere Nachrichten an einen Knoten zusammenfassen und miteinander senden. Aus Rücksicht auf die problemlose Abarbeitung multipler Nachrichten im Knoten dürfen diese zusammengefassten Nachrichten aber keinesfalls mehr Antworten verursachen, als der Sendepuffer aufnehmen kann. Dieser umfasst zwar mindestens 64 Byte (entsprechend der zulässigen Paketgröße), der Platz kann aber nicht voll ausgenutzt werden ohne Spontannachrichten zu stören. Daher gilt eine Grenze von 48 Byte an Antworten je Knoten.

Beispiel: Zur Abfrage sämtlicher Features eines Knotens kann man bei der ersten Anfrage ein MSG_FEATURE_GETALL und gleich noch 4 MSG_FEATURE_GETNEXT schicken. Der Knoten beginnt mit der Antwort MSG_FEATURE_COUNT und sendet diese 4 Features, wobei man sofort beim Erhalt des COUNT gleich ein weiteres MSG_FEATURE_GETNEXT abschicken kann und so quasi die Verbindung 'unter Dampf' halten kann.

Wie wird die Datenübertragung im Volumen gesichert?

Damit es nicht zu einem 'Overrun' eines Knotens kommt, muss das PC-Programm fallweise seine Nachrichten an diesen Knoten beschränken. Es kann sonst der Fall eintreten, dass ein Knoten z. B. die Antworten nicht mehr abgeholt bekommt und deswegen gezwungen ist, Nachrichten oder Antworten zu verwerfen. Ein Sequenzfehler ist die natürliche Folge.

  • Das PC-Programm bündelt so viele Nachrichten an einen Knoten, bis die prognostizierte Antwortgröße 43 Bytes ist. Daran wird eine Nachricht MSG_PING angefügt. Damit liegt das unter der Schwelle von 48 Bytes.
  • Erst wenn die Antwort zu diesem Ping eingetroffen ist, wird der Knoten erneut mit Nachrichten beaufschlagt.

Ein Knoten soll mind. das Doppelte der Paketgröße als Ausgangspuffer bereit halten.

In der Datei BiDiB-Messages.xml ist zu jedem Downlinkbefehl die zu erwartende Antwortgröße angegeben.

Wie wird die Verstellung eines Accessory gemeldet?

Ein Accessoryobjekt teilt dem Host die Verstelling in einer MSG_ACCESSORY_NOTIFY-Nachricht als Fehlermeldung mit, dabei wird auch die aktuelle Stellung als Begriff mitgeliefert.

Je nach interner Konstruktion des Knotens ist es nicht immer möglich, den aktuellen Begriff zu bestimmen. In diesem Fall meldet der Knoten den Begriff 255. Dies ist als Warnung/Fehler zu sehen "Achtung Weiche X wurde per Hand verstellt. Die aktuelle Lage ist unbekannt!".

Nach einer solchen Übertragung befindet sich das Accessoryobjekt immer im Fehlerzustand und kann nicht benutzt werden. Die Nachricht soll vom Host mit MSG_ACCESSORY_SET quittiert werden, in der die neue Lage bestätigt oder die alte erneut angefordert wird. Erst nach einer positiven Antwort (in MSG_ACCESSORY_STATE) ist das Objekt dann wieder benutzbar.

Neben einer ungewollten Lageabweichung, die mittels einer Rückmeldeeinrichtung erkannt wird, kann auch eine aktive "Handverstellung" durch Bedienung vor Ort oder durch einen direkten Eingriff am Objekt erfolgen.

Warum der Wechsel von MSG_LC_KEY auf MSG_LC_PORT_STAT und was muss ich beachten?

Mit der Revision 1.26 wurde ein allgemeines Portmodell eingeführt, welches bis zu 4096 Ports ansprechen kann. Die bisherigen Inputs wurden in dieses Modell integriert und somit können jetzt auch mehr als 128 Inputs abgefragt werden, ebenso werden flexible, umschaltbare Portarten unterstützt.

Abfrage: Ein direkter Eingang wurde bis V0.6 mit MSG_LC_KEY_QUERY, PORTNUM abgefragt. Das wird ab V0.7 ersetzt durch MSG_LC_PORT_QUERY PORTADDRESS(16bit). Für eine Übergangszeit unterstützen die Knoten auch noch die alte Abfrage, sofern vom Adressbereich her möglich.

Meldung: Ein direkter Eingang wurde bis V0.6 mit der Nachricht MSG_LC_KEY, PORTNUM, STAT gemeldet. Das wird ab V0.7 ersetzt durch MSG_LC_STAT PORTADDRESS(16bit) STAT. Aus Sicht eines PC-Programmes kann man beide Nachrichtenarten parallel akzeptieren.

Schnellabfrage: Durch den neu eingeführten Befehl MSG_LC_PORT_QUERY_ALL SELECT START END können beim Systemstart alle Eingänge mit einem Befehl abgefragt werden. Beispiel: MSG_LC_PORT_QUERY_ALL 00 80 00 00 FF FF frägt alle Inputs ab (SELECT = 0x8000 = Inputs, START = 0, END = 0xFFFF).