@@ -1,6 +1,39 @@
import random
# https://en.wikipedia.org/wiki/8b/10b_encoding
import re
class ControlSymbol(int):
pass
class EncDec_8B10B(object):
class EncDec_8B10B(object):
# Table 36-3 of 802.3-2018 has symbols for 1000Base-X coding
COMMA = ControlSymbol(0xbc)
COMMA_ALTA = ControlSymbol(0x3c)
COMMA_ALTB = ControlSymbol(0xfc)
K_28_0 = ControlSymbol(0x1c)
K_28_2 = ControlSymbol(0x5c)
K_28_3 = ControlSymbol(0x7c)
K_28_4 = ControlSymbol(0x9c)
K_28_6 = ControlSymbol(0xdc)
K_23_7 = ControlSymbol(0xf7)
K_27_7 = ControlSymbol(0xfb)
K_29_7 = ControlSymbol(0xfd)
K_30_7 = ControlSymbol(0xfe)
# Where disparity of 0 means more 0's, 1 means more 1's
#
# index of lookup strings:
# <ctrl><disparity><data>
#
# data is lowest/rightmost bit maps to A, and high bit is H
#
# format of data:
# <newdisparity><data>
# data is lowest/rightmost bit transmitted first
#
# comment of each line is:
# # "<data bitstring>" <start disp><encoding><ending> [<dec val>]
enc_lookup = [
enc_lookup = [
"00010111001", # "00000000" -D00.0- [0]
"00010111001", # "00000000" -D00.0- [0]
"00010101110", # "00000001" -D01.0- [1]
"00010101110", # "00000001" -D01.0- [1]
@@ -2055,8 +2088,109 @@ class EncDec_8B10B(object):
"DEC8b10bERR" # "1111111111"
"DEC8b10bERR" # "1111111111"
]
]
def __init__(self):
self.__rd = 0
self.__syncd = False
self.__pendingdata = ''
@staticmethod
def _to10b(v):
'''convert integer to bits, in the correct order, which is
first (high) bit to be sent first.'''
binstr = bin(v)[2:]
return ('0' * (10 - len(binstr)) + binstr)[10:-11:-1]
def issyncd(self):
return self.__syncd
__syncre = re.compile('11000001..|00111110..')
def decode(self, bstr):
'''Decode bstr, a string of 0's, and 1's to bytes. This
consumes all the bits, and stores any excess bits if some are
missing.
Returns either None, or a byte string w/ the data.
If a control byte is received, it is returned by itself as an
instance of ControlSymbol.
Note that it needs to receive an EncDec_8B10B.COMMA control byte
first to establish sync, and then will data after that.
'''
if set(bstr) - set('01'):
raise ValueError('invalid characters in: %s' % repr(bstr))
data = self.__pendingdata + bstr
if not self.__syncd:
m = self.__syncre.search(data)
if not m:
self.__pendingdata = data[-9:]
return
self.__syncd = True
data = data[m.start():]
r = bytearray()
for idx in range(0, len(data), 10):
i = data[idx:idx + 10]
if len(i) != 10:
self.__pendingdata = i
break
try:
ctrl, d = self.dec_8b10b(int(i[::-1], 2))
except Exception:
self.__syncd = False
self.__pendingdata = data[idx + 1:]
return
#print(repr(ctrl), repr(d), repr(r))
if ctrl and r:
self.__pendingdata = data[idx:]
return r
if ctrl:
self.__pendingdata = data[idx + 10:]
return ControlSymbol(d)
r += d.to_bytes(1, byteorder='big')
else:
self.__pendingdata = ''
if r:
return r
def encode(self, bstr):
'''Encode bstr into a string representing the binary (unicode
string represented by 0 and 1). The first bit to transmit is
at index 0, and so on.'''
r = []
rd = self.__rd
if isinstance(bstr, ControlSymbol):
rd, c = self.enc_8b10b(bstr, rd, ctrl=1)
r.append(c)
else:
for i in bstr:
rd, c = self.enc_8b10b(i, rd)
r.append(c)
self.__rd = rd
return ''.join(self._to10b(x) for x in r)
@staticmethod
@staticmethod
def enc_8b10b(data_in, running_disparity, ctrl=0, verbose=False):
def enc_8b10b(data_in, running_disparity, ctrl=0, verbose=False):
'''Encode a single byte to 10 bits.'''
assert data_in <= 0xFF, "Data in must be maximum one byte"
assert data_in <= 0xFF, "Data in must be maximum one byte"
encoded = int(EncDec_8B10B.enc_lookup[(
encoded = int(EncDec_8B10B.enc_lookup[(
ctrl << 9) + (running_disparity << 8) + data_in], 2)
ctrl << 9) + (running_disparity << 8) + data_in], 2)
@@ -2068,6 +2202,8 @@ class EncDec_8B10B(object):
@staticmethod
@staticmethod
def dec_8b10b(data_in, verbose=False):
def dec_8b10b(data_in, verbose=False):
'''Decode 10 bits into a byte.'''
assert data_in <= 0x3FF, "Data in must be maximum 10 bits"
assert data_in <= 0x3FF, "Data in must be maximum 10 bits"
decoded = EncDec_8B10B.dec_lookup[(data_in)]
decoded = EncDec_8B10B.dec_lookup[(data_in)]
if decoded == "DEC8b10bERR":
if decoded == "DEC8b10bERR":
@@ -2080,4 +2216,3 @@ class EncDec_8B10B(object):
print("Decoded: {:02X} - Control: {:01b}".format(decoded, ctrl))
print("Decoded: {:02X} - Control: {:01b}".format(decoded, ctrl))
return ctrl, decoded
return ctrl, decoded