-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdsss_lib.py
More file actions
136 lines (124 loc) · 6.13 KB
/
Copy pathdsss_lib.py
File metadata and controls
136 lines (124 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python3
"""Bit-exact Python models of the bladeRF DSSS CRC engines + a frame-bit builder.
Transcribed verbatim from wlan_dsss_plcp_crc.vhd and wlan_crc.vhd so a generated
frame decodes (crc_correct) in the real VHDL framer (which is how these models are
ultimately validated)."""
# ---------------- PLCP CRC-16 (bit-serial), wlan_dsss_plcp_crc.vhd ----------------
def plcp_crc16(bits):
"""bits: iterable of 0/1, fed in time order. Returns the 16-bit 'crc' output
(crc_next XOR 0xFFFF) as an int with bit i = crc[i]."""
c = [1]*16 # crc_next reset = all ones
for d in bits:
n = c[:] # next from current
n[15] = c[14]
n[14] = c[13]
n[13] = c[12]
n[12] = c[11] ^ c[15] ^ d
n[11] = c[10]
n[10] = c[9]
n[9] = c[8]
n[8] = c[7]
n[7] = c[6]
n[6] = c[5]
n[5] = c[4] ^ c[15] ^ d
n[4] = c[3]
n[3] = c[2]
n[2] = c[1]
n[1] = c[0]
n[0] = c[15] ^ d
c = n
crc = [c[i] ^ 1 for i in range(16)] # crc <= crc_next xor x"FFFF"
return crc # list, crc[i]
def plcp_endian(crc):
"""endian(i)=crc(15-i); endian(8+i)=crc(7-i), i=0..7 -> list endian[0..15]."""
e = [0]*16
for i in range(8):
e[i] = crc[15 - i]
e[8+i] = crc[7 - i]
return e
# ---------------- payload CRC-32 (byte-parallel), wlan_crc.vhd ----------------
def crc32_step(c, di):
"""c: list of 32 current bits; di: list of 8 in_data bits (di[0]=LSB). Returns next."""
n = [0]*32
x = lambda *t: 0 ^ (lambda acc=0: acc)() # placeholder (unused)
n[0] = c[24]^c[30]^di[1]^di[7]
n[1] = c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[2] = c[26]^di[5]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[3] = c[27]^di[4]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]
n[4] = c[28]^di[3]^c[27]^di[4]^c[26]^di[5]^c[24]^c[30]^di[1]^di[7]
n[5] = c[29]^di[2]^c[28]^di[3]^c[27]^di[4]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[6] = c[30]^di[1]^c[29]^di[2]^c[28]^di[3]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]
n[7] = c[31]^di[0]^c[30]^di[1]^c[29]^di[2]^c[27]^di[4]^c[26]^di[5]^c[24]^c[30]^di[1]^di[7]
n[8] = c[0]^c[31]^di[0]^c[30]^di[1]^c[28]^di[3]^c[27]^di[4]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[9] = c[1]^c[31]^di[0]^c[29]^di[2]^c[28]^di[3]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]
n[10] = c[2]^c[30]^di[1]^c[29]^di[2]^c[27]^di[4]^c[26]^di[5]^c[24]^c[30]^di[1]^di[7]
n[11] = c[3]^c[31]^di[0]^c[30]^di[1]^c[28]^di[3]^c[27]^di[4]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[12] = c[4]^c[31]^di[0]^c[29]^di[2]^c[28]^di[3]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[13] = c[5]^c[30]^di[1]^c[29]^di[2]^c[27]^di[4]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]
n[14] = c[6]^c[31]^di[0]^c[30]^di[1]^c[28]^di[3]^c[27]^di[4]^c[26]^di[5]
n[15] = c[7]^c[31]^di[0]^c[29]^di[2]^c[28]^di[3]^c[27]^di[4]
n[16] = c[8]^c[30]^di[1]^c[29]^di[2]^c[28]^di[3]^c[24]^c[30]^di[1]^di[7]
n[17] = c[9]^c[31]^di[0]^c[30]^di[1]^c[29]^di[2]^c[25]^c[31]^di[0]^di[6]
n[18] = c[10]^c[31]^di[0]^c[30]^di[1]^c[26]^di[5]
n[19] = c[11]^c[31]^di[0]^c[27]^di[4]
n[20] = c[12]^c[28]^di[3]
n[21] = c[13]^c[29]^di[2]
n[22] = c[14]^c[30]^di[1]^c[24]^c[30]^di[1]^di[7]
n[23] = c[15]^c[31]^di[0]^c[25]^c[31]^di[0]^di[6]^c[24]^c[30]^di[1]^di[7]
n[24] = c[16]^c[26]^di[5]^c[25]^c[31]^di[0]^di[6]
n[25] = c[17]^c[27]^di[4]^c[26]^di[5]
n[26] = c[18]^c[28]^di[3]^c[27]^di[4]^c[24]^c[30]^di[1]^di[7]
n[27] = c[19]^c[29]^di[2]^c[28]^di[3]^c[25]^c[31]^di[0]^di[6]
n[28] = c[20]^c[30]^di[1]^c[29]^di[2]^c[26]^di[5]
n[29] = c[21]^c[31]^di[0]^c[30]^di[1]^c[27]^di[4]
n[30] = c[22]^c[31]^di[0]^c[28]^di[3]
n[31] = c[23]^c[29]^di[2]
return n
def crc32_hw(byte_list):
"""byte_list: ints 0..255 fed in order. Returns 32-bit 'crc' output list crc[0..31]
where crc(i)=crc_next(31-i) xor 1."""
c = [1]*32
for byte in byte_list:
di = [(byte >> j) & 1 for j in range(8)] # di[0]=LSB
c = crc32_step(c, di)
return [c[31 - i] ^ 1 for i in range(32)] # crc(i)
# ---------------- helpers ----------------
def byte_to_bits_lsb(b):
return [(b >> i) & 1 for i in range(8)] # LSB-first in time
def bits_to_int(bits):
return sum(b << i for i, b in enumerate(bits))
def build_descrambled_frame(payload_bytes, n_preamble_ones=64):
"""Return the descrambled bit stream the framer should see:
[preamble ones][SFD 0xF3A0][PLCP 48: SIGNAL,SERVICE,LENGTH,CRC16][payload][FCS32].
All multi-bit fields LSB-first in time (matches the framer's MSB-shift recv_reg)."""
P = len(payload_bytes)
pkt_len = P + 4 # data octets + 4-byte FCS
length_us = pkt_len * 8 # LENGTH(us); pkt_len = recv_reg[31:19] = LENGTH>>3
SIGNAL = 0x0A # 1 Mbps DSSS signal field (0x0A); value is don't-care to framer
SERVICE = 0x00
# First 32 PLCP bits (SIGNAL, SERVICE, LENGTH) in time order (LSB-first per field)
plcp32 = byte_to_bits_lsb(SIGNAL) + byte_to_bits_lsb(SERVICE) \
+ byte_to_bits_lsb(length_us & 0xFF) + byte_to_bits_lsb((length_us >> 8) & 0xFF)
crc16 = plcp_crc16(plcp32) # HW CRC over the 32 bits
crc_field = plcp_endian(crc16) # transmitted as PLCP bits 33..48
sfd = [(0xF3A0 >> i) & 1 for i in range(16)] # LSB-first so recv_reg[15:0]==0xF3A0
# FCS over the data bytes; assembled fcs == calculated_fcs requires LE byte order
fcs_bits = crc32_hw(payload_bytes)
fcs_int = bits_to_int(fcs_bits)
fcs_bytes = [(fcs_int >> (8*k)) & 0xFF for k in range(4)] # byte k -> fcs[8k+7:8k]
bits = [1]*n_preamble_ones
bits += sfd
bits += plcp32 + crc_field
for b in payload_bytes:
bits += byte_to_bits_lsb(b)
for b in fcs_bytes:
bits += byte_to_bits_lsb(b)
return bits
if __name__ == "__main__":
# quick self-consistency print
import random
random.seed(1)
pl = [random.randint(0,255) for _ in range(16)]
b = build_descrambled_frame(pl)
print("payload:", pl)
print("frame bits:", len(b))