HSG

Aktuelle Seite: HSG/Fächer/Informatik/Netze

miniEthernet - ein an Ethernet angelehntes Protokoll mit Manchestercodierung

Ethernet-Skizze Quelle: The origin of the Ethernet symbol

Manchester-Code

nach wikipedia-Artikel 'Manchester-Code':

Manchester-Bits

Der Manchester-Code ist ein Leitungscode, der bei der Kodierung das Taktsignal erhält. Die Flanken des Signals, bezogen auf das Taktsignal, tragen die Information. Eine fallende Flanke bedeutet zum Beispiel eine logische Null, eine steigende Flanke eine logische Eins. Daher gibt es mindestens eine Flanke pro Bit, aus der das Taktsignal abgeleitet werden kann. Der Manchester-Code ist selbst­synchronisierend und unabhängig vom Gleichspannungspegel. Manchester-Code wird zum Beispiel bei 10-Mbit-Ethernet verwendet

Für unsere Zwecke hat der Machestercode zwei wichtige Vorteile. Erstens unterscheidet sich ein 0-Bit von einer 'toten Leitung'. Damit funktioniert die Kollisionserkennung viel sicherer. Zweitens ermöglicht die 'bittragende Flanke' die Rückgewinnung des Taktes. Auf diese Weise sollten auch längere Pakete ohne Synchronisierungsfehler übertragbar werden.

Bitfolge --> Pegelfolge

Ein Null-Bit wird durch die Pegelfolge '10', ein Eins-Bit durch die Pegelfolge '01' reräsentiert.

def Manchestercodiert(bitfolge):
    """
    gibt zu bitfolge (str) die Manchester-codierte Pegelfolge zurueck
    '101011' --> '011001100101'
    """
    t = ['10','01']
    return ''.join([t[int(x)] for x in bitfolge])

Tests

>>> Manchestercodiert('101011')
'011001100101'
>>> Manchestercodiert('01000001')
'1001101010101001'

Senden einer Pegelfolge

Das Senden soll in einem abbrechbaren Thread erfolgen. Die Zeitsteuerung soll aus der Systemzeit abgeleitet werden. Auf diese Weise wird eine große 'Langzeitkonstanz' erreicht. Zur Kollisionserkennung soll nach jedem Setzen der Leitung auf Null (bei einer Eins gibt es nach Konstruktion des Busses keine Kollision) die Leitung beobachtet werden. Im Kollisionsfall soll ein Callback ausgelöst und die Überwachung der Leitung bis zur nächsten Flanke unterbrochen werden.

import time
import platform

def zeit():
    if platform.system() == 'Windows':
        return time.clock()
    else:
        return time.time()

import serial
import threading

class Model(object):
    def __init__(self):
        self.s = serial.Serial('/dev/ttyS0')
        self.s.setRTS(False)
        self.stopflag = threading.Event()
        self.pegelfolge = ''
        self.pegelzeit = 0.01
        self.sendThread = None

    def send(self,pegelfolge,pegelzeit,setLeitung,getLeitung,stopflag,OnCollision):
        """
        sendet die Pegel aus der pegelfolge (str) mit der pegelzeit (float), benutzt dazu die Funktion setLeitung,
        die ein boolsches Argument hat, das Senden kann ueber stopflag (threading-event) abgebrochen werden,
        die Funktion getLeitung gibt einen boolschen Wert zurueck,
        bei einer Kollision wird der Callback OnCollision aufgerufen
        """
        t0 = zeit()
        n = len(pegelfolge)
        i = 0
        while (not stopflag.isSet()) and (len(pegelfolge) > 0) :
            pegel = (pegelfolge[0] == '1')
            # print(pegel) # DEBUG
            setLeitung(pegel)
            pegelfolge = pegelfolge[1:]
            i = i + 1
            # Warten und Kollisionserkennung
            collisionsflag = False
            while zeit() - t0 < i*pegelzeit:
                if (pegel == False) and (not collisionsflag) and (getLeitung() == True):
                    collisionsflag = True
                    if OnCollision != None:
                        OnCollision()
                if (pegel == True) or collisionsflag:
                    time.sleep(0.0001)
        if stopflag.isSet():
            print('Senden abgebrochen ...')
        setLeitung(False)
        
    def stop(self):
        self.stopflag.set()

    def OnColl(self):
        print('Kollision') # DEBUG
                       
    def start(self):
        self.stopflag.clear()
        self.sendThread = threading.Thread(target=self.send,
                                           args=(self.pegelfolge,self.pegelzeit,self.s.setRTS,
                                                 self.s.getCTS,self.stopflag,self.OnColl))
        self.sendThread.start()
      
    def __del__(self):                                # schliesst sicher die Schnittstelle
        self.s.close()

sendthread1.py

Test

Zum Test wurde eine Pegelfolge gesendet und das Gesendete auf einem anderen Rechner mit Hilfe des Pegeltransceivers empfangen. Mit dem Pegeltransceiver wurden in die ersten beiden 'Pausen' kurze '1'-Impulse erzeugt, um Kollisionen auszulösen.

>>> m=Model()
>>> m.pegelfolge='011001100101'
>>> m.pegelzeit=0.5
>>> m.start()
>>> Kollision
Kollision

Das Bild zeigt die beiden kurzen Impulse in den ersten Pausen. Hinter der eigentlichen Nachricht wurden vier kurze Impulse im Transceiver generiert, die ignoriert werden können.

Test 0

Auch das Abbrechen einer laufenden Sendung wurde erfolgreich getestet.

>>> m.start()
>>> m.stop()
>>> Senden abgebrochen ...

Der Transceiver zeigte, dass die Sendung tatsächlich abgebrochen wurde.

Präambel und Start Frame Delimiter

aus wikipedia-Artikel 'Ethernet':

Die Präambel besteht aus einer 7 Byte langen, alternierenden Bitfolge (101010...1010), an sie schließt der Start Frame Delimiter (SFD) mit der Bitfolge (10101011) an. Diese Sequenz diente einst der Bit-Synchronisation der Netzwerkgeräte. Sie war für all jene Geräteverbindungen notwendig, die die Bit-Synchronisation nicht durch die Übertragung einer kontinuierlichen Trägerwelle auch in Ruhezeiten aufrecht erhalten konnten, sondern diese mit jedem gesendeten Frame wieder neu aufbauen mussten. Das alternierende Bitmuster erlaubte jedem Empfänger eine korrekte Synchronisation auf die Bit-Abstände. Da bei einer Weiterleitung über Hubs jeweils ein gewisser Teil der Präambel verloren geht, wurde sie in der Spezifikation groß genug gewählt, damit bei maximaler Ausdehnung des Netzwerkes für den Empfänger noch eine minimale Einschwingphase übrig bleibt.

Im MiniEthernet soll die Präambel auf das Byte '10101010' und den SFD '10101011' verkürzt werden.

>>> praeambel
'01100110011001100110011001100101'
>>> m=Model()
>>> m.pegelfolge='01100110011001100110011001100101'
>>> m.pegelzeit=0.05
>>> m.start()

Präambel

Links

Delphi-Programme

ManchesterSender0.zip, Manchesterempfaenger4.zip, NetzHWneu.zip