from serial import *
from time import *
from random import *

def crc(bitfolge, polynom = '10011'):
    """
    zu der 'nachricht' und zu dem 'polynom' (Strings aus 0 und 1) wird
    die CRC-'Prüfsumme' berechnet (String aus 0 und 1)
    """
    lp = len(polynom)
    ln = len(bitfolge)
    for j in range(lp-1):
        bitfolge = bitfolge+'0'
    bitliste = list(bitfolge)
    schieberegister = bitliste[:lp]
    for i in range(ln):
        if schieberegister[0] == '1':
            for j in range(lp):
                if schieberegister[j] == polynom[j]:
                    schieberegister[j] = '0'
                else:
                    schieberegister[j] = '1'
        if i < ln-1:
            schieberegister = schieberegister[1:lp]+list(bitliste[lp+i])
    return ''.join(schieberegister[1:])


def sendeJamSignal(s, bitzeit):
    print('Sende Jamsignal', end='')
    s.setRTS(1)
    for i in range(20):
        print('.', end='')
        sleep(bitzeit)
    print('Jamsignal beendet')
    s.setRTS(0)

def sendeEinzelnesByte(s, bitzeit, bitfolge, sender, empfaenger):
    sender_binaer = bin(sender)[2:].zfill(4)
    empfaenger_binaer = bin(empfaenger)[2:].zfill(4)
    gesamteBitfolge = sender_binaer + empfaenger_binaer + bitfolge
    gesamteBitfolge = gesamteBitfolge + crc(gesamteBitfolge)

    print('Warte auf freie Leitung', end='')
    freieZeit = 0
    while freieZeit < 20:
        print('.', end = '')
        if s.getCTS():
            freieZeit = 0
        else:
            freieZeit = freieZeit + 1
        sleep(bitzeit)
    print()

    print('Sende...')
    s.setRTS(1)
    sleep(bitzeit)

    for i in gesamteBitfolge:
         if i == '1':
            s.setRTS(1)
            sleep(bitzeit)
         else:
            s.setRTS(0)
            sleep(bitzeit*0.5)
            empfangenesBit = s.getCTS()
            if empfangenesBit == 1 or empfangenesBit == True:
                print('Fehlversuch')
                sendeJamSignal(s, bitzeit)
                return False
            sleep(bitzeit*0.5)

    s.setRTS(0)
    sleep(bitzeit)
    print('Senden erfolgreich')
    return True

def sendeByte(s, bitzeit, bitfolge, sender, empfaenger):
        versuche = 0
        byteGesendet = False
        while versuche < 5 and not byteGesendet:
            versuche = versuche + 1
            print('Sendeversuch', versuche, bitfolge, sender, empfaenger)
            byteGesendet = sendeEinzelnesByte(s, bitzeit, bitfolge, sender, empfaenger)
            if not byteGesendet:
                pause = bitzeit * randint(1, 2**versuche)
                print('Neuer Versuch in:', pause)
                sleep(pause)
        return byteGesendet

def sendeText(s, bitzeit, text, sender, empfaenger):
    for zeichen in text:
        bitfolgeBuchstabe = bin(ord(zeichen))[2:].zfill(8)
        zeichenGesendet = sendeByte(s, bitzeit, bitfolgeBuchstabe, sender, empfaenger)
        if zeichenGesendet:
            print('OK:', zeichen)
        else:
            print('Nicht gesendet:', zeichen)

s = Serial('com1')
s.setRTS(0)    
bitzeit = 1
nachricht = 'Hi'
eigeneAdresse = 1
ziel = 2
sendeText(s, bitzeit, nachricht, eigeneAdresse, ziel)
