#!/usr/bin/env python2 # This is script is aimed at being copied to some remote target host where it # will be run by osmo-gsm-tester through ssh from distutils.version import StrictVersion from gnuradio.fft import window from gnuradio import blocks from gnuradio import gr from gnuradio.filter import firdes import sys import json from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation from gnuradio import zeromq import socket import argparse from signal import * class GrBroker(gr.top_block): def __init__(self, args, cfg): gr.top_block.__init__(self, "InterENB Handover Flowgraph") ################################################## # Variables ################################################## self.args = args self.cfg = cfg self.samp_rate = samp_rate = 23040000 self.relative_gain = relative_gain = 1.0 self.blocks_add = {} ################################################## # Blocks ################################################## # Build ENB side + connect to per stream multilier: for enb in self.cfg['enb']: for it in enb: source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port']) sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port']) print('enb: earfcn=%u source=%r sink=%r' % (it['earfcn'], source_addr, sink_addr)) it['gr_block_zmq_source'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1) it['gr_block_zmq_sink'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1) it['gr_block_multiply'] = blocks.multiply_const_cc(relative_gain) it['gr_block_multiply'].set_block_alias('relative_gain %s' % source_addr) self.connect((it['gr_block_zmq_source'], 0), (it['gr_block_multiply'], 0)) if it['use_mimo']: source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'] + 1) sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'] + 1) print('enb: earfcn=%u source=%r sink=%r (MIMO)' % (it['earfcn'], source_addr, sink_addr)) it['gr_block_zmq_source2'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1) it['gr_block_zmq_sink2'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1) it['gr_block_multiply2'] = blocks.multiply_const_cc(relative_gain) it['gr_block_multiply2'].set_block_alias('relative_gain %s' % source_addr) self.connect((it['gr_block_zmq_source2'], 0), (it['gr_block_multiply2'], 0)) # Build UE side: for ue in self.cfg['ue']: for it in ue: source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port']) sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port']) print('ue: earfcn=%u source=%r sink=%r' % (it['earfcn'], source_addr, sink_addr)) it['gr_block_zmq_source'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1) it['gr_block_zmq_sink'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1) if it['use_mimo']: source_addr = 'tcp://%s:%u' % (it['peer_addr'].encode('utf-8'), it['peer_port'] + 1) sink_addr = 'tcp://%s:%u' % (args.bind_addr, it['bind_port'] + 1) print('ue: earfcn=%u source=%r sink=%r (MIMO)' % (it['earfcn'], source_addr, sink_addr)) it['gr_block_zmq_source2'] = zeromq.req_source(gr.sizeof_gr_complex, 1, source_addr, 100, False, -1) it['gr_block_zmq_sink2'] = zeromq.rep_sink(gr.sizeof_gr_complex, 1, sink_addr, 100, False, -1) # Create per EARFCN adder (only 2->1 supported so far) earfcn_li = self.calc_earfcn_list() blocks_add_next_avail_port = {} for earfcn in earfcn_li: self.blocks_add[earfcn] = blocks.add_vcc(1) blocks_add_next_avail_port[earfcn] = 0 # Connect the ENB-side multipliers to the Adder input ports: idx = 0 for enb in self.cfg['enb']: for it in enb: print('Connecting ENB port %u to Adder[%u] for earfcn %u' % (it['bind_port'], blocks_add_next_avail_port[it['earfcn']], it['earfcn'])) self.connect((it['gr_block_multiply'], 0), (self.blocks_add[it['earfcn']], blocks_add_next_avail_port[it['earfcn']])) # TODO: if it['use_mimo'], connect it['gr_block_multiply2'] to some adder... blocks_add_next_avail_port[it['earfcn']] += 1 # Connect the Adder to the UE-side (Dl): for earfcn, bl_add in self.blocks_add.items(): for ue in self.cfg['ue']: for it in ue: if it['earfcn'] != earfcn: continue print('Connecting Adder for earfcn %u to UE port %u' % (earfcn, it['bind_port'])) self.connect((bl_add, 0), (it['gr_block_zmq_sink'], 0)) # TODO: if it['use_mimo'], connect some adder to it['gr_block_zmq_sink2']... # UL: Connect 1 UE port splitting it into N ENB ports: for ue in self.cfg['ue']: for it_ue in ue: for enb in self.cfg['enb']: for it_enb in enb: if it_ue['earfcn'] != it_enb['earfcn']: continue print('connecting UE port %u to ENB port %u, earfcn=%u' % (it_ue['bind_port'], it_enb['bind_port'], it_enb['earfcn'])) self.connect((it_ue['gr_block_zmq_source'], 0), (it_enb['gr_block_zmq_sink'], 0)) if it_ue['use_mimo'] and it_enb['use_mimo']: self.connect((it_ue['gr_block_zmq_source2'], 0), (it_enb['gr_block_zmq_sink2'], 0)) def calc_earfcn_list(self): earfcn_li = [] for enb in self.cfg['enb']: for it in enb: if it['earfcn'] not in earfcn_li: earfcn_li.append(it['earfcn']) return earfcn_li def set_relative_gain(self, port, relative_gain): for enb in self.cfg['enb']: for it in enb: if it['bind_port'] == port: print('setting port %u rel_gain to %f' % (port, relative_gain)) it['gr_block_multiply'].set_k(relative_gain) return def mainloop(sock, broker): while True: chunk = sock.recv(4096) stringdata = chunk.decode('utf-8') msg = json.loads(stringdata) print('Received msg: %s' % msg) if msg['action'] == 'exit': print('Received exit command. Stopping radio...') return elif msg['action'] == 'set_relative_gain': broker.set_relative_gain(msg['port'], msg['rel_gain']) else: print('Unknwon action for message: %s' % msg) def sig_handler_cleanup(signum, frame): print("killed by signal %d" % signum) # This sys.exit() will raise a SystemExit base exception at the current # point of execution. Code must be prepared to clean system-wide resources # by using the "finally" section. This allows at the end 'atexit' hooks to # be called before exiting. sys.exit(1) def main(): for sig in (SIGINT, SIGTERM, SIGQUIT, SIGPIPE, SIGHUP): signal(sig, sig_handler_cleanup) parser = argparse.ArgumentParser() parser.add_argument('-b', '--bind-addr', dest='bind_addr', help="Address where local sockets are bound to") parser.add_argument('-c', '--ctrl-port', dest='ctrl_port', type=int, default=5005, help="Port where CTRL interface is bound to") args = parser.parse_args() print('bind_addr:', repr(args.bind_addr)) print('ctrl_port:', repr(args.ctrl_port)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((args.bind_addr, args.ctrl_port)) broker = None try: print('waiting for configuration on UDP socket...') chunk = sock.recv(4096) print('Received udp packet') stringdata = chunk.decode('utf-8') cfg = json.loads(stringdata) print('Got config:', stringdata) broker = GrBroker(args, cfg) print('Starting...') broker.start() print('in mainloop') mainloop(sock, broker) except KeyboardInterrupt: pass print('main loop ended, exiting...') # closing flowgraph and socket sock.close() if broker: broker.stop() broker.wait() if __name__ == '__main__': main() print("exit")