Merge branch 'fixeria/trx' of https://github.com/axilirator/gr-gsm into fixeria_trx

# Resolved conflicts:
#	apps/grgsm_trx
#	python/trx/radio_if.py
#	swig/grgsm_swig.i
This commit is contained in:
Piotr Krysik 2018-04-17 09:10:33 +02:00
commit 2471052cfe
14 changed files with 466 additions and 88 deletions

View File

@ -42,11 +42,11 @@ class Application:
base_port = 5700
# PHY specific
phy_sample_rate = 4*1625000/6
phy_sample_rate = 4 * 1625000 / 6
phy_tx_antenna = "TX/RX"
phy_rx_antenna = "RX2"
phy_rx_gain = 30
phy_tx_gain = 40
phy_tx_gain = 10
phy_args = ""
phy_ppm = 0
@ -101,7 +101,7 @@ class Application:
# PHY specific
s += " Radio interface specific\n" \
" -a --device-args Set device arguments\n" \
" -s --sample-rate Set sample rate (default 2000000)\n" \
" -s --sample-rate Set sample rate\n" \
" -g --rx-gain Set RX gain (default 30)\n" \
" -G --tx-gain Set TX gain (default 10)\n" \
" --rx-antenna Set RX antenna (default RX2)\n" \

View File

@ -1,9 +1,9 @@
<?xml version="1.0"?>
<block>
<name>Burst to fn_time</name>
<name>Burst to FN time</name>
<key>gsm_burst_to_fn_time</key>
<import>import grgsm</import>
<make>grgsm.burst_to_fn_time()</make>
<make>grgsm.gsm_burst_to_fn_time()</make>
<sink>
<name>bursts_in</name>

View File

@ -36,6 +36,7 @@ install(FILES
tmsi_dumper.h
msg_to_tag.h
trx_burst_if.h
burst_to_fn_time.h
controlled_fractional_resampler_cc.h
time_spec.h
fn_time.h DESTINATION include/grgsm/misc_utils

View File

@ -0,0 +1,57 @@
/* -*- c++ -*- */
/* @file
* @author Piotr Krysik <ptrkrysik@gmail.com>
* @author Vadim Yanitskiy <axilirator@gmail.com>
* @section LICENSE
*
* Gr-gsm is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* Gr-gsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gr-gsm; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef INCLUDED_GRGSM_BURST_TO_FN_TIME_H
#define INCLUDED_GRGSM_BURST_TO_FN_TIME_H
#include <grgsm/api.h>
#include <gnuradio/block.h>
namespace gr {
namespace gsm {
/*!
* \brief <+description of block+>
* \ingroup gsm
*
*/
class GRGSM_API burst_to_fn_time : virtual public gr::block
{
public:
typedef boost::shared_ptr<burst_to_fn_time> sptr;
/*!
* \brief Return a shared_ptr to a new instance of grgsm::burst_to_fn_time.
*
* To avoid accidental use of raw pointers, grgsm::burst_to_fn_time's
* constructor is in a private implementation
* class. grgsm::burst_to_fn_time::make is the public interface for
* creating new instances.
*/
static sptr make();
};
} // namespace gsm
} // namespace gr
#endif /* INCLUDED_GRGSM_BURST_TO_FN_TIME_H */

View File

@ -37,5 +37,6 @@ add_sources(
fn_time.cc
udp_socket.cc
trx_burst_if_impl.cc
burst_to_fn_time_impl.cc
)

View File

@ -0,0 +1,84 @@
/* -*- c++ -*- */
/* @file
* @author Piotr Krysik <ptrkrysik@gmail.com>
* @author Vadim Yanitskiy <axilirator@gmail.com>
* @section LICENSE
*
* Gr-gsm is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* Gr-gsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gr-gsm; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "burst_to_fn_time_impl.h"
namespace gr {
namespace gsm {
burst_to_fn_time::sptr
burst_to_fn_time::make(void)
{
return gnuradio::get_initial_sptr
(new burst_to_fn_time_impl());
}
/*
* The private constructor
*/
burst_to_fn_time_impl::burst_to_fn_time_impl(void)
: gr::block("burst_to_fn_time",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0))
{
// Register I/O ports
message_port_register_in(pmt::mp("bursts_in"));
message_port_register_out(pmt::mp("fn_time_out"));
// Bind a port handler
set_msg_handler(pmt::mp("bursts_in"),
boost::bind(&burst_to_fn_time_impl::handle_burst, this, _1));
}
/*
* Our virtual destructor.
*/
burst_to_fn_time_impl::~burst_to_fn_time_impl()
{
}
void
burst_to_fn_time_impl::handle_burst(pmt::pmt_t msg_in)
{
// Obtain fn_time tag from message
pmt::pmt_t blob = pmt::car(msg_in);
pmt::pmt_t fn_time = pmt::dict_ref(blob,
pmt::intern("fn_time"), pmt::PMT_NIL);
// Drop messages without required tag
if (fn_time == pmt::PMT_NIL)
return;
// Compose and send a new message
pmt::pmt_t msg_out = pmt::dict_add(pmt::make_dict(),
pmt::intern("fn_time"), fn_time);
message_port_pub(pmt::mp("fn_time_out"), msg_out);
}
} /* namespace gsm */
} /* namespace gr */

View File

@ -0,0 +1,45 @@
/* -*- c++ -*- */
/* @file
* @author Piotr Krysik <ptrkrysik@gmail.com>
* @author Vadim Yanitskiy <axilirator@gmail.com>
* @section LICENSE
*
* Gr-gsm is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* Gr-gsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gr-gsm; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef INCLUDED_GRGSM_BURST_TO_FN_TIME_IMPL_H
#define INCLUDED_GRGSM_BURST_TO_FN_TIME_IMPL_H
#include <grgsm/misc_utils/burst_to_fn_time.h>
namespace gr {
namespace gsm {
class burst_to_fn_time_impl : public burst_to_fn_time
{
private:
void handle_burst(pmt::pmt_t msg_in);
public:
burst_to_fn_time_impl(void);
~burst_to_fn_time_impl(void);
};
} // namespace gsm
} // namespace gr
#endif /* INCLUDED_GRGSM_BURST_TO_FN_TIME_IMPL_H */

View File

@ -90,15 +90,14 @@ namespace gr {
void txtime_setter_impl::process_fn_time_reference(pmt::pmt_t msg)
{
pmt::pmt_t not_found = pmt::intern("not_found");
pmt::pmt_t fn_time, time_hint;
fn_time = pmt::dict_ref(msg,
pmt::intern("fn_time"), not_found);
pmt::intern("fn_time"), pmt::PMT_NIL);
time_hint = pmt::dict_ref(msg,
pmt::intern("fn_time"), not_found);
pmt::intern("time_hint"), pmt::PMT_NIL);
if (fn_time != not_found) {
if (fn_time != pmt::PMT_NIL) {
uint32_t fn_ref = static_cast<uint32_t>
(pmt::to_uint64(pmt::car(pmt::car(fn_time))));
uint32_t ts = static_cast<uint32_t>
@ -109,7 +108,7 @@ namespace gr {
pmt::cdr(pmt::cdr(fn_time)));
set_fn_time_reference(fn_ref, ts, time_secs, time_fracs);
} else if (time_hint != not_found) {
} else if (time_hint != pmt::PMT_NIL) {
set_time_hint(pmt::to_uint64(pmt::car(fn_time)),
pmt::to_double(pmt::cdr(fn_time)));
}

View File

@ -58,7 +58,6 @@ from gsm_sdcch8_demapper import gsm_sdcch8_demapper
from gsm_gmsk_mod import gsm_gmsk_mod
from fn_time import *
from txtime_bursts_tagger import *
from burst_to_fn_time import *
import arfcn

View File

@ -23,6 +23,5 @@ GR_PYTHON_INSTALL(
clock_offset_corrector_tagged.py
hier_block.py
fn_time.py
burst_to_fn_time.py
DESTINATION ${GR_PYTHON_DIR}/grgsm
)

View File

@ -1,28 +0,0 @@
"""
Embedded Python Blocks:
Each this file is saved, GRC will instantiate the first class it finds to get
ports and parameters of your block. The arguments to __init__ will be the
parameters. All of them are required to have default values!
"""
import numpy as np
from gnuradio import gr
import pmt
class burst_to_fn_time(gr.basic_block):
def __init__(self): # only default arguments here
gr.basic_block.__init__(
self,
name='Burst to fn_time',
in_sig=[],
out_sig=[]
)
self.message_port_register_in(pmt.intern("bursts_in"))
self.message_port_register_out(pmt.intern("fn_time_out"))
self.set_msg_handler(pmt.intern("bursts_in"), self.convert)
def convert(self, msg):
fn_time = pmt.dict_ref(pmt.car(msg),pmt.intern("fn_time"),pmt.PMT_NIL)
fn_time_msg = pmt.dict_add(pmt.make_dict(), pmt.intern("fn_time"), fn_time)
if pmt.to_python(fn_time) is not None:
self.message_port_pub(pmt.intern("fn_time_out"), fn_time_msg)

View File

@ -62,6 +62,7 @@ class ctrl_if_bb(ctrl_if):
if self.tb.trx_started:
print("[i] Stopping transceiver...")
self.tb.trx_started = False
self.tb.set_ta(0)
self.tb.stop()
self.tb.wait()
@ -144,6 +145,19 @@ class ctrl_if_bb(ctrl_if):
return (0, [meas_dbm])
# Timing Advance control
elif self.verify_cmd(request, "SETTA", 1):
print("[i] Recv SETTA cmd")
# Check TA range
ta = int(request[1])
if ta < 0 or ta > 63:
print("[!] TA value must be in range: 0..63")
return -1
self.tb.set_ta(ta)
return 0
# Misc
elif self.verify_cmd(request, "ECHO", 0):
print("[i] Recv ECHO cmd")

View File

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# GR-GSM based transceiver
# Extending a GRC flowgraph gr-gsm/examples/trx_radio_if/radio_if_grc.grc
# Follow graph implementation
#
# (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
# (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com>
@ -23,37 +23,267 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from grgsm.trx import radio_if_grc
import pmt
import time
import grgsm
import osmosdr
from math import pi
from gnuradio import digital
from gnuradio import blocks
from gnuradio import uhd
from gnuradio import gr
from gnuradio import filter
from gnuradio.filter import firdes
# HACK: should be implemented in C++!
class dict_toggle_sign(gr.basic_block):
def __init__(self): # only default arguments here
gr.basic_block.__init__(self,
name='Change sign of elts in dict',
in_sig=[],
out_sig=[]
)
self.message_port_register_in(pmt.intern("dict_in"))
self.message_port_register_out(pmt.intern("dict_out"))
self.set_msg_handler(pmt.intern("dict_in"), self.change_sign)
def change_sign(self, msg):
if pmt.is_dict(msg):
d = pmt.to_python(msg)
for key, value in d.items():
d[key] *= -1
self.message_port_pub(pmt.intern("dict_out"), pmt.to_pmt(d))
class radio_if(gr.top_block):
# PHY specific variables
rx_freq = 935e6
tx_freq = 890e6
osr = 4
class radio_if(radio_if_grc):
# Application state flags
trx_started = False
# GSM timings (in microseconds [uS])
# One timeslot duration is 576.9 μs = 15/26 ms,
# or 156.25 symbol periods (a symbol period is 48/13 μs)
GSM_SYM_PERIOD_uS = 48.0 / 13.0
GSM_TS_PERIOD_uS = GSM_SYM_PERIOD_uS * 156.25
GSM_UL_DL_SHIFT_uS = -(GSM_TS_PERIOD_uS * 3)
# FIXME: shall be measured (automatically?) for
# particular device and particular clock rate.
# The current value is measured for USRP B2X0 at 26e6.
delay_correction = (285.616 + 2 * GSM_SYM_PERIOD_uS) * 1e-6
def __init__(self, phy_args, phy_sample_rate,
phy_rx_gain, phy_tx_gain, phy_ppm,
phy_rx_antenna, phy_tx_antenna,
trx_remote_addr, trx_base_port,
phy_tx_freq=938900000,
phy_rx_freq=938900000-45e6,
delay_correction=285.616e-6,
uplink_shift=-(6.0/1625000*(156.25)*3),
timing_advance=0):
trx_remote_addr, trx_base_port):
print("[i] Init Radio interface")
radio_if_grc.__init__(self,
samp_rate=phy_sample_rate,
tx_gain=phy_tx_gain, rx_gain=phy_rx_gain,
tx_freq=phy_tx_freq, rx_freq=phy_rx_freq,
osr=4, ppm=phy_ppm,
trx_base_port=str(trx_base_port),
trx_remote_addr=trx_remote_addr,
delay_correction=delay_correction,
uplink_shift=uplink_shift,
timing_advance=timing_advance)
# PHY specific variables
self.sample_rate = phy_sample_rate
self.rx_gain = phy_rx_gain
self.tx_gain = phy_tx_gain
self.ppm = phy_ppm
gr.top_block.__init__(self, "GR-GSM TRX")
# TRX Burst Interface
self.trx_burst_if = grgsm.trx_burst_if(
trx_remote_addr, str(trx_base_port))
# RX path definition
self.phy_src = uhd.usrp_source(phy_args,
uhd.stream_args(cpu_format="fc32",
channels=range(1)))
self.phy_src.set_clock_rate(26e6, uhd.ALL_MBOARDS)
self.phy_src.set_center_freq(self.rx_freq, 0)
self.phy_src.set_antenna(phy_rx_antenna, 0)
self.phy_src.set_samp_rate(phy_sample_rate)
self.phy_src.set_bandwidth(650e3, 0)
self.phy_src.set_gain(phy_rx_gain)
self.msg_to_tag_src = grgsm.msg_to_tag()
self.rotator_src = grgsm.controlled_rotator_cc(
self.calc_phase_inc(self.rx_freq))
self.lpf = filter.fir_filter_ccf(1, firdes.low_pass(
1, phy_sample_rate, 125e3, 5e3, firdes.WIN_HAMMING, 6.76))
self.gsm_receiver = grgsm.receiver(self.osr, ([0]), ([]))
self.ts_filter = grgsm.burst_timeslot_filter(0)
self.ts_filter.set_policy(grgsm.FILTER_POLICY_DROP_ALL)
# Connections
self.connect(
(self.phy_src, 0),
(self.msg_to_tag_src, 0))
self.connect(
(self.msg_to_tag_src, 0),
(self.rotator_src, 0))
self.connect(
(self.rotator_src, 0),
(self.lpf, 0))
self.connect(
(self.lpf, 0),
(self.gsm_receiver, 0))
self.msg_connect(
(self.gsm_receiver, 'C0'),
(self.ts_filter, 'in'))
self.msg_connect(
(self.ts_filter, 'out'),
(self.trx_burst_if, 'bursts'))
# TX Path Definition
self.phy_sink = uhd.usrp_sink(phy_args,
uhd.stream_args(cpu_format="fc32",
channels=range(1)), "packet_len")
self.phy_sink.set_clock_rate(26e6, uhd.ALL_MBOARDS)
self.phy_sink.set_antenna(phy_tx_antenna, 0)
self.phy_sink.set_samp_rate(phy_sample_rate)
self.phy_sink.set_center_freq(self.tx_freq, 0)
self.phy_sink.set_gain(self.tx_gain)
self.tx_time_setter = grgsm.txtime_setter(
0xffffffff, 0, 0, 0, 0, 0,
self.delay_correction + self.GSM_UL_DL_SHIFT_uS * 1e-6)
self.tx_burst_proc = grgsm.preprocess_tx_burst()
self.pdu_to_tagged_stream = blocks.pdu_to_tagged_stream(
blocks.byte_t, 'packet_len')
self.gmsk_mod = grgsm.gsm_gmsk_mod(
BT = 0.3, pulse_duration = 4, sps = self.osr)
self.burst_shaper = digital.burst_shaper_cc(
(firdes.window(firdes.WIN_HANN, 16, 0)),
0, 20, False, "packet_len")
self.msg_to_tag_sink = grgsm.msg_to_tag()
self.rotator_sink = grgsm.controlled_rotator_cc(
-self.calc_phase_inc(self.tx_freq))
# Connections
self.msg_connect(
(self.trx_burst_if, 'bursts'),
(self.tx_time_setter, 'bursts_in'))
self.msg_connect(
(self.tx_time_setter, 'bursts_out'),
(self.tx_burst_proc, 'bursts_in'))
self.msg_connect(
(self.tx_burst_proc, 'bursts_out'),
(self.pdu_to_tagged_stream, 'pdus'))
self.connect(
(self.pdu_to_tagged_stream, 0),
(self.gmsk_mod, 0))
self.connect(
(self.gmsk_mod, 0),
(self.burst_shaper, 0))
self.connect(
(self.burst_shaper, 0),
(self.msg_to_tag_sink, 0))
self.connect(
(self.msg_to_tag_sink, 0),
(self.rotator_sink, 0))
self.connect(
(self.rotator_sink, 0),
(self.phy_sink, 0))
# RX & TX synchronization
self.bt_filter = grgsm.burst_type_filter([3])
self.burst_to_fn_time = grgsm.burst_to_fn_time()
# Connections
self.msg_connect(
(self.gsm_receiver, 'C0'),
(self.bt_filter, 'bursts_in'))
self.msg_connect(
(self.bt_filter, 'bursts_out'),
(self.burst_to_fn_time, 'bursts_in'))
self.msg_connect(
(self.burst_to_fn_time, 'fn_time_out'),
(self.tx_time_setter, 'fn_time'))
# AFC (Automatic Frequency Correction)
self.gsm_clck_ctrl = grgsm.clock_offset_control(
self.rx_freq, phy_sample_rate, osr = self.osr)
self.dict_toggle_sign = dict_toggle_sign()
# Connections
self.msg_connect(
(self.gsm_receiver, 'measurements'),
(self.gsm_clck_ctrl, 'measurements'))
self.msg_connect(
(self.gsm_clck_ctrl, 'ctrl'),
(self.msg_to_tag_src, 'msg'))
self.msg_connect(
(self.gsm_clck_ctrl, 'ctrl'),
(self.dict_toggle_sign, 'dict_in'))
self.msg_connect(
(self.dict_toggle_sign, 'dict_out'),
(self.msg_to_tag_sink, 'msg'))
def shutdown(self):
print("[i] Shutdown Radio interface")
self.stop()
self.wait()
def calc_phase_inc(self, fc):
return self.ppm / 1.0e6 * 2 * pi * fc / self.sample_rate
def set_rx_freq(self, fc):
self.phy_src.set_center_freq(fc, 0)
self.rotator_src.set_phase_inc(self.calc_phase_inc(fc))
self.rx_freq = fc
def set_tx_freq(self, fc):
self.phy_sink.set_center_freq(fc, 0)
self.rotator_sink.set_phase_inc(-self.calc_phase_inc(fc))
self.tx_freq = fc
def set_rx_gain(self, gain):
self.phy_src.set_gain(gain, 0)
self.rx_gain = gain
def set_tx_gain(self, gain):
self.phy_sink.set_gain(gain, 0)
self.tx_gain = gain
def set_ta(self, ta):
print("[i] Setting TA value %d" % ta)
advance_time_sec = ta * self.GSM_SYM_PERIOD_uS * 1e-6
self.tx_time_setter.set_timing_advance(advance_time_sec)

View File

@ -1,7 +1,7 @@
/* -*- c++ -*- */
/*
* @file
* @author (C) 2014 by Piotr Krysik <ptrkrysik@gmail.com>
* @author (C) 2014-2017 by Piotr Krysik <ptrkrysik@gmail.com>
* @section LICENSE
*
* Gr-gsm is free software; you can redistribute it and/or modify
@ -69,7 +69,7 @@
#include "grgsm/misc_utils/message_file_source.h"
#include "grgsm/misc_utils/msg_to_tag.h"
#include "grgsm/misc_utils/controlled_fractional_resampler_cc.h"
//#include "grgsm/misc_utils/time_spec.h"
#include "grgsm/misc_utils/burst_to_fn_time.h"
#include "grgsm/misc_utils/fn_time.h"
#include "grgsm/transmitter/txtime_setter.h"
#include "grgsm/transmitter/preprocess_tx_burst.h"
@ -148,6 +148,10 @@ GR_SWIG_BLOCK_MAGIC2(gsm, controlled_fractional_resampler_cc);
GR_SWIG_BLOCK_MAGIC2(gsm, extract_cmc);
%include "grgsm/misc_utils/extract_assignment_cmd.h"
GR_SWIG_BLOCK_MAGIC2(gsm, extract_assignment_cmd);
%include "grgsm/misc_utils/trx_burst_if.h"
GR_SWIG_BLOCK_MAGIC2(gsm, trx_burst_if);
%include "grgsm/misc_utils/burst_to_fn_time.h"
GR_SWIG_BLOCK_MAGIC2(gsm, burst_to_fn_time);
%include "grgsm/qa_utils/burst_sink.h"
GR_SWIG_BLOCK_MAGIC2(gsm, burst_sink);
@ -158,37 +162,10 @@ GR_SWIG_BLOCK_MAGIC2(gsm, message_source);
%include "grgsm/qa_utils/message_sink.h"
GR_SWIG_BLOCK_MAGIC2(gsm, message_sink);
//#pragma SWIG nowarn=319
//%include "grgsm/misc_utils/time_spec.h"
//%extend gr::gsm::time_spec_t{
// gr::gsm::time_spec_t __add__(const gr::gsm::time_spec_t &what)
// {
// gr::gsm::time_spec_t temp = *self;
// temp += what;
// return temp;
// }
// gr::gsm::time_spec_t __sub__(const gr::gsm::time_spec_t &what)
// {
// gr::gsm::time_spec_t temp = *self;
// temp -= what;
// return temp;
// }
// bool __eq__(const gr::gsm::time_spec_t &what)
// {
// return (what == *self);
// }
//};
%include "grgsm/misc_utils/fn_time.h"
%include "grgsm/transmitter/txtime_setter.h"
GR_SWIG_BLOCK_MAGIC2(gsm, txtime_setter);
%include "grgsm/transmitter/preprocess_tx_burst.h"
GR_SWIG_BLOCK_MAGIC2(gsm, preprocess_tx_burst);
%include "grgsm/transmitter/gen_test_ab.h"
GR_SWIG_BLOCK_MAGIC2(gsm, gen_test_ab);
%include "grgsm/misc_utils/trx_burst_if.h"
GR_SWIG_BLOCK_MAGIC2(gsm, trx_burst_if);