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