Support für Hersteller
Userkonfiguration
Beispielcode
Analysewerkzeuge
Support für BiDiB
Einloggen von Knoten auf dem BiDiBus
Knoten müssen sich zu Beginn einer Sitzung am Bus neu anmelden. Hierzu müssen die Knoten zur Anmeldung aufgefordert werden, dies erfolgt vom Interface mit der Nachricht BIDIBUS_LOGON. Die Knoten versuchen sich anzumelden (MSG_LOCAL_LOGON). Wenn sich zwei oder mehr Knoten gleichzeitig anmelden wollen, kollidieren die Nachrichten und es schließt sich ein Verfahren zur Vereinzelung der Knoten an, bis ein Knoten eindeutig identifiziert ist und diesem eine Sitzungs-Adresse zugewiesen wird. Das gewählte Verfahren mittels zufälligem Backoff konvergiert sehr schnell.
Logon aus Sicht des Knotens
Ein Knoten hat vier interne Zustände:
DISCONNECTED | keine Verbindung. Der Knoten versucht, sich mittels Logon beim System anzumelden. |
---|---|
APPLIED | Der Knoten hat versucht, sich anzumelden und wartet auf die Bestätigung. |
CONNECTED | Der Knoten ist verbunden und empfängt/sendet Nachrichten. |
REJECTED | Der Knoten wurde abgewiesen. Er unternimmt keine weiteren Logon-Versuche mehr und zeigt den Fehlerzustand an. |
Zwischen diesen Zuständen gibt es nun folgende Übergänge:
- Der Knoten geht immer in DISCONNECTED:
- nach Power-Up
- wenn ein Busreset empfangen wurde
- wenn ein Logonversuch gescheitert ist
- wenn er zu lange keinen Poll vom Interface bekommen hat.
- Der Knoten geht in den Zustand APPLIED:
- nachdem er eine Logonnachricht abgesendet hat.
- Der Knoten geht in den Zustand CONNECTED:
- nachdem er eine positive Bestätigung auf seine Logonnachricht erhalten hat.
- Der Knoten geht in den Zustand REJECTED:
- nachdem er eine Abweisung mit seiner Unique-ID erhalten hat. Der Knoten verbleibt in diesen Zustand. (siehe Hinweis)
Um beim Logonvorgang die notwendige Vereinzelung zu erreichen, gibt es Regeln, welche bei einem Logonversuch zu beachten sind:
- Backoff:
-
Zu Beginn und nach einem erfolglosen Anmeldeversuch hat der Knoten eine zufällige Zahl an LOGON-Nachrichten des Busmasters zu ignorieren (='backoff'). Damit wird anderen Knoten die Chance gegeben, ihrerseits einen erfolgreichen Logon durchzuführen. Wenn es beim nächsten Anmeldeversuch wieder zu einer Kollision (und damit zum Scheitern des Anmeldens kommt) muss der Knoten erneut eine zufällige Zahl warten, diese ergibt sich aus der bisherigen Zahl zzgl. einer Zufallszahl, d.h. der 'backoff' wird verlängert.
Die Zufallszahl zu Beginn soll sich in einem Bereich von 1…63 befinden und anhand der Unique-ID des Knotens berechnet werden. Damit ist auch der erste Logonversuch bereits über die Knoten zeitlich entzerrt. Später wird der Backoff auf 0…63 beschränkt.
In der Empfangsroutine des Knoten erfolgt daher ein Test auf Logon und fallweise das Senden der Anmeldung:
if (received_message == BIDIBUS_LOGON) { if (my_bidib_connect == BIDIB_DISCONNECTED) { if (bidib_backoff) { bidib_backoff--; } else { send_logon_message(); my_bidib_connect = BIDIB_APPLIED; } } else if (my_bidib_connect == BIDIB_APPLIED) { // logon attempt failed, no ack received bidib_backoff = calculate_new_backoff(); } else { // other processing }
Der neue Backoff berechnet sich wie folgt:
unsigned char calculate_new_backoff(void) { unsigned char new_backoff; new_backoff = prbs8() & 0xF; new_backoff += previous_backoff; new_backoff &= 0x3F; // modulo 64 and limit previous_backoff = new_backoff; return(new_backoff); }
Als Zufallsprozess wird eine LSFR (PRBS) der Länge 8 verwendet.
Das sind in C nur ein paar Schiebebefehle und XOR's.
unsigned char seed = 0xAA; // this should be loaded by serial no. static unsigned char prbs8(void) { unsigned char new_rnd,temp; new_rnd = seed; // copy bit 1 new_rnd = new_rnd << 1; new_rnd = new_rnd ^ seed; // xor bit 2 new_rnd = new_rnd << 1; new_rnd = new_rnd ^ seed; // xor bit 3 new_rnd = new_rnd << 4; new_rnd = new_rnd ^ seed; // xor bit 7 new_rnd = new_rnd >> 7; // now put this bit to seed's lsb temp = seed << 1; seed = new_rnd + temp; return(seed); }
- Kollisionsvermeidung:
-
Wenn der Knoten eine LOGON-Aufforderung empfangen hat, so muss er mit mit seinem Sendeversuch eine bestimmte Zeit warten und dabei die Busleitung beobachten:
if (received == BIDIBUS_LOGON_par) { if (bidib_connect == BIDIB_DISCONNECTED) { if (bidib_backoff) bidib_backoff--; else { // backoff ist abgelaufen, also los // hier kommt jetzt zuerst collision avoidance: // Der Knoten wartet eine spezifische Wartezeit (von 0…31us), // debei wird die RX-Leitung beobachtet // und fallweise _nicht_ gesendet! unsigned char i; for (i=0; i<bidib_collision_avoidance_time; i++) { if (HARDWARE_GET_RX == 0) return; _delay_us(1); } ... // hier wird jetzt die LOGON Nachricht gesendet.
Das verringert die Wahrscheinlichkeit einer Kollision und beschleunigt damit das Anmelden aller Knoten.
Hinweis: Es kann der Fall eintreten (z. B. durch eine kurze Stromunterbrechung), dass der Knoten neu startet, aber immer noch am Interface angemeldet ist. In diesem Fall wird er beim Versuch, sich erneut anzumelden, ein 'REJECTED' erhalten, da ja das Interface einen doppelten Logon sieht. In diesem Fall soll sich der Knoten für 2 Sekunden nicht am Bus melden (damit ihn das Interface sicher ausbucht) und dann erneut versuchen, sich anzumelden. Wird diese Anmeldung erneut abgewiesen, dann dürfen keine weiteren Versuche unternommen werden.
- Beispieldaten eines BIDIBUS_LOGON:
-
Die LOGON-Nachricht wird wie eine normale Nachricht auch in ein Bus-Paket verpackt und mit CRC geschützt:
0x00B = Paket size 0x00A = Message size 0x000 = Adressstack (this message is from this node itself) 0x000 = Message Num (here 0) 0x0F0 = Code BIDIBUS_LOGON 0x000 = Unique, Class 0x000 = Unique, ClassX 0x00D = Unique, VendorID 0x075 = Unique, ProductID 0x000 = Unique, ProductID 0x073 = Unique, Serial 0x0F0 = Unique, Serial 0x0EB = CRC8
Logon aus Sicht des Interfaces
... hier fehlt noch Text ... bei Interesse bitte anfragen