blob: 3681e7e04cc9ab21bb4795c257820ce5878fa026 [file] [log] [blame]
Pau Espin Pedrol41091232020-10-05 19:23:38 +02001#!/usr/bin/env python2
2
3from distutils.version import StrictVersion
4
5from gnuradio.fft import window
6from gnuradio import blocks
7from gnuradio import gr
8from gnuradio.filter import firdes
9import sys
10import json
11from argparse import ArgumentParser
12from gnuradio.eng_arg import eng_float, intx
13from gnuradio import eng_notation
14from gnuradio import zeromq
15import socket
16import argparse
17from signal import *
18
19class GrBroker(gr.top_block):
20
21 def __init__(self, args, cfg):
22 gr.top_block.__init__(self, "Intra Handover Flowgraph")
23
24 ##################################################
25 # Variables
26 ##################################################
27 self.args = args
28 self.cfg = cfg
29 self.samp_rate = samp_rate = 23040000
30 self.relative_gain = relative_gain = 1.0
31 self.blocks_add = {}
32
33 ##################################################
34 # Blocks
35 ##################################################
36
37 # Build ENB side + connect to per stream multilier:
38 for enb in self.cfg['enb']:
39 for it in enb:
40 source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'])
41 sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'])
42 print('enb: earfcn=%u source=%r sink=%r' % (it['earfcn'], source_addr, sink_addr))
43 it['gr_block_zmq_source'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1)
44 it['gr_block_zmq_sink'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1)
45 it['gr_block_multiply'] = blocks.multiply_const_cc(relative_gain)
46 it['gr_block_multiply'].set_block_alias('relative_gain %s' % source_addr)
47 self.connect((it['gr_block_zmq_source'], 0), (it['gr_block_multiply'], 0))
48 if it['use_mimo']:
49 source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'] + 1)
50 sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'] + 1)
51 print('enb: earfcn=%u source=%r sink=%r (MIMO)' % (it['earfcn'], source_addr, sink_addr))
52 it['gr_block_zmq_source2'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1)
53 it['gr_block_zmq_sink2'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1)
54 it['gr_block_multiply2'] = blocks.multiply_const_cc(relative_gain)
55 it['gr_block_multiply2'].set_block_alias('relative_gain %s' % source_addr)
56 self.connect((it['gr_block_zmq_source2'], 0), (it['gr_block_multiply2'], 0))
57
58 # Build UE side:
59 for ue in self.cfg['ue']:
60 for it in ue:
61 source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'])
62 sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'])
63 print('ue: earfcn=%u source=%r sink=%r' % (it['earfcn'], source_addr, sink_addr))
64 it['gr_block_zmq_source'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1)
65 it['gr_block_zmq_sink'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1)
66 if it['use_mimo']:
67 source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'] + 1)
68 sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'] + 1)
69 print('ue: earfcn=%u source=%r sink=%r (MIMO)' % (it['earfcn'], source_addr, sink_addr))
70 it['gr_block_zmq_source2'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1)
71 it['gr_block_zmq_sink2'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1)
72
73 # Create per EARFCN adder (only 2->1 supported so far)
74 earfcn_li = self.calc_earfcn_list()
75 blocks_add_next_avail_port = {}
76 for earfcn in earfcn_li:
77 self.blocks_add[earfcn] = blocks.add_vcc(1)
78 blocks_add_next_avail_port[earfcn] = 0
79 # Connect the ENB-side multipliers to the Adder input ports:
80 idx = 0
81 for enb in self.cfg['enb']:
82 for it in enb:
83 print('Connecting ENB port %u to Adder[%u] for earfcn %u' % (it['bind_port'], blocks_add_next_avail_port[earfcn], it['earfcn']))
84 self.connect((it['gr_block_multiply'], 0), (self.blocks_add[it['earfcn']], blocks_add_next_avail_port[earfcn]))
85 # TODO: if it['use_mimo'], connect it['gr_block_multiply2'] to some adder...
86 blocks_add_next_avail_port[earfcn] += 1
87
88 # Connect the Adder to the UE-side (Dl):
89 for earfcn, bl_add in self.blocks_add.items():
90 for ue in self.cfg['ue']:
91 for it in ue:
92 if it['earfcn'] != earfcn:
93 continue
94 print('Connecting Adder for earfcn %u to UE port %u' % (earfcn, it['bind_port']))
95 self.connect((bl_add, 0), (it['gr_block_zmq_sink'], 0))
96 # TODO: if it['use_mimo'], connect some adder to it['gr_block_zmq_sink2']...
97
98 # UL: Connect 1 UE port splitting it into N ENB ports:
99 for ue in self.cfg['ue']:
100 for it_ue in ue:
101 for enb in self.cfg['enb']:
102 for it_enb in enb:
103 if it_ue['earfcn'] != it_enb['earfcn']:
104 continue
105 print('connecting UE port %u to ENB port %u, earfcn=%u' % (it_ue['bind_port'], it_enb['bind_port'], it_enb['earfcn']))
106 self.connect((it_ue['gr_block_zmq_source'], 0), (it_enb['gr_block_zmq_sink'], 0))
107 if it_ue['use_mimo'] and it_enb['use_mimo']:
108 self.connect((it_ue['gr_block_zmq_source2'], 0), (it_enb['gr_block_zmq_sink2'], 0))
109
110 def calc_earfcn_list(self):
111 earfcn_li = []
112 for enb in self.cfg['enb']:
113 for it in enb:
114 if it['earfcn'] not in earfcn_li:
115 earfcn_li.append(it['earfcn'])
116 return earfcn_li
117
118 def set_relative_gain(self, port, relative_gain):
119 for enb in self.cfg['enb']:
120 for it in enb:
121 if it['bind_port'] == port:
122 print('setting port %u rel_gain to %f' % (port, relative_gain))
123 it['gr_block_multiply'].set_k(relative_gain)
124 return
125
126def mainloop(sock, broker):
127 while True:
128 chunk = sock.recv(4096)
129 stringdata = chunk.decode('utf-8')
130 msg = json.loads(stringdata)
131 print('Received msg: %s' % msg)
132
133 if msg['action'] == 'exit':
134 print('Received exit command. Stopping radio...')
135 return
136 elif msg['action'] == 'set_relative_gain':
137 broker.set_relative_gain(msg['port'], msg['rel_gain'])
138 else:
139 print('Unknwon action for message: %s' % msg)
140
141
142def sig_handler_cleanup(signum, frame):
143 print("killed by signal %d" % signum)
144 # This sys.exit() will raise a SystemExit base exception at the current
145 # point of execution. Code must be prepared to clean system-wide resources
146 # by using the "finally" section. This allows at the end 'atexit' hooks to
147 # be called before exiting.
148 sys.exit(1)
149
150def main():
151
152 for sig in (SIGINT, SIGTERM, SIGQUIT, SIGPIPE, SIGHUP):
153 signal(sig, sig_handler_cleanup)
154
155 parser = argparse.ArgumentParser()
156 parser.add_argument('-b', '--bind-addr', dest='bind_addr', help="Address where local sockets are bound to")
157 parser.add_argument('-c', '--ctrl-port', dest='ctrl_port', type=int, default=5005, help="Port where CTRL interface is bound to")
158 args = parser.parse_args()
159
160 print('bind_addr:', repr(args.bind_addr))
161 print('ctrl_port:', repr(args.ctrl_port))
162 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
163 sock.bind((args.bind_addr, args.ctrl_port))
164
165 broker = None
166 try:
167 print('waiting for configuration on UDP socket...')
168 chunk = sock.recv(4096)
169 print('Received udp packet')
170 stringdata = chunk.decode('utf-8')
171 cfg = json.loads(stringdata)
172 print('Got config:', stringdata)
173 broker = GrBroker(args, cfg)
174 print('Starting...')
175 broker.start()
176 print('in mainloop')
177 mainloop(sock, broker)
178 except KeyboardInterrupt:
179 pass
180 print('main loop ended, exiting...')
181 # closing flowgraph and socket
182 sock.close()
183 if broker:
184 broker.stop()
185 broker.wait()
186
187
188if __name__ == '__main__':
189 main()
190 print("exit")