-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
203 lines (145 loc) · 5.31 KB
/
main.py
File metadata and controls
203 lines (145 loc) · 5.31 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
@file main.py
@author Riccardo Cavallari
@date 2019.10.01
"""
import scheduler
import packet
import random
import wave
import gpio
from array import array
from collections import deque
from vcd import VCDWriter
PROB_THRESHOLD = 0.3
FRAMES_PER_PACKET = 160 # mono, 10 ms @ 16 kHz sampl. rate
FRAME_INTERVAL = 10e-3
CODEC_INTERVAL = FRAME_INTERVAL
IN_FIFO_LEN = 10
OUT_FIFO_LEN = IN_FIFO_LEN
RADIO_FIFO_LEN = 10
# packet + ack + 2*Tifs
PACKET_DURATION = 0.564e-3 # subevent duration
CONNECTION_EVENT = 0.75*FRAME_INTERVAL
MAX_TX_CONN_EVENT = int(CONNECTION_EVENT/PACKET_DURATION)
underflowCnt = 0
overflowCnt = 0
radioOverflow = 0
vcdFile = open("out.vcd", "w")
vcd = VCDWriter(vcdFile, timescale='1 us')
gpio0 = gpio.Gpio(0, vcd, 'producer', '!')
gpio1 = gpio.Gpio(0, vcd, 'consumer', '$')
gpio2 = gpio.Gpio(0, vcd, 'ble', '#')
# FIFO to hold packet ready to bt tx-ed or retx-ed
fifoRadio = deque([], RADIO_FIFO_LEN)
def printTime():
""" print current time """
print(scheduler.Scheduler.clockTime,'-'*50)
def createPacket(payload):
""" Create a packet with a given payload """
pkt = packet.Packet(payload)
return pkt
def producerCallback(fifo, wf):
""" read frames from the wav input file and add it to the input FIFO.
This represents the output of the codec """
# add packets to the input FIFO
payload = wf.readframes(FRAMES_PER_PACKET)
if (payload != b''):
packet = createPacket(payload)
else:
packet = createPacket(bytes(2*FRAMES_PER_PACKET))
fifo.append(packet)
gpio0.toggle(scheduler.Scheduler.clockTime*1e6)
def isochronousTransportCallback(fifoIn, fifoOut):
""" Simulate a unicast isochronous channel between a master and a slave """
#TODO
def aclTransportCallback (fifoIn, fifoOut):
""" Simulate an ACL tranport between a master and a slave. Packets are
retransmitted untile they are successfully acknowledged. """
global fifoRadio, radioOverflow
# get the packet scheduled for this event
schedPacket = fifoIn.popleft()
schedPacket.txAttemps = packet.FLUSH_TIMEOUT_INF
if fifoRadio.maxlen == len(fifoRadio):
radioOverflow += 1
fifoRadio.append(schedPacket)
# schedule tx slots within a connection event
for i in range(min(len(fifoRadio), MAX_TX_CONN_EVENT)):
event = scheduler.Event(scheduler.Scheduler.clockTime + i*PACKET_DURATION,
0, txCallaback, [fifoRadio, fifoOut])
scheduler.addEvent(event)
def txCallaback(fifoIn, fifoOut):
""" Get a packet from the input FIFO and send it over the air """
global overflowCnt
try:
packet = fifoIn.popleft()
if (random.random() < PROB_THRESHOLD):
if fifoOut.maxlen == len(fifoOut):
overflowCnt += 1
fifoOut.append(packet)
print("Packet", packet.seqNum, "OK, re-tx", packet.txAttemps)
gpio2.toggle(scheduler.Scheduler.clockTime*1e6)
else:
print("Packet", packet.seqNum, "Error")
# decrease txAttempts and put the packet back in the FIFO
packet.txAttemps -= 1
if (packet.txAttemps):
fifoIn.appendleft(packet)
else:
del packet
except IndexError:
print("Input FIFO is empty!")
def consumerCallback(fifo, file):
""" Get a packet from output FIFO and reproduce it """
global underflowCnt
try:
sample = fifo.popleft()
# print(sample.seqNum)
file.writeframes(sample.payload)
except IndexError:
file.writeframes(bytes(2*FRAMES_PER_PACKET))
underflowCnt += 1
print("Output FIFO is empty!")
gpio1.toggle(scheduler.Scheduler.clockTime*1e6)
def main():
""" Main function of the simulator """
# input and output FIFOs
fifoIn = deque([], IN_FIFO_LEN)
fifoOut = deque([], OUT_FIFO_LEN)
# input wave file
wf = wave.open('440Hz.wav', 'rb')
# output wave file
wof = wave.open('output.wav', 'wb')
wof.setnchannels(1)
wof.setsampwidth(2)
wof.setframerate(16000)
# for i in range(5):
# packet = createPacket(array('L', [x*i for x in range(4)]))
# fifoIn.append(packet)
# set the simulation duration in seconds
scheduler.setSimDuration(10.1)
# producer adds packet to the input FIFO
event = scheduler.Event(0, CODEC_INTERVAL, producerCallback,
[fifoIn, wf])
scheduler.addEvent(event)
# the transport sends packets on the medium and store them in a (finte)
# output FIFO
event = scheduler.Event(0, FRAME_INTERVAL,
aclTransportCallback, [fifoIn, fifoOut])
scheduler.addEvent(event)
# consumer takes packets from the output FIFO and writes them to a wave file
# RSL10: 16129/16000 or 15957/16000
event = scheduler.Event(FRAME_INTERVAL, FRAME_INTERVAL,
consumerCallback, [fifoOut, wof])
scheduler.addEvent(event)
# START the simulation
scheduler.runEvents()
# end of the simulation
scheduler.simDone()
print("Consumer underflow:", underflowCnt)
print("Consumer overflow:", overflowCnt)
print("Radio overflow:", radioOverflow)
wof.close()
vcd.close()
vcdFile.close()
if __name__ == '__main__': main()