osmo-gsm-tester/src/osmo_gsm_tester/external/gnuradio_zmq_broker_remote.py

194 lines
8.7 KiB
Python
Executable File

#!/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")