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