aboutsummaryrefslogtreecommitdiffstats
path: root/python/trx
diff options
context:
space:
mode:
authorVadim Yanitskiy <axilirator@gmail.com>2017-12-03 23:49:09 +0700
committerVadim Yanitskiy <axilirator@gmail.com>2017-12-04 00:22:39 +0700
commitd222ee58bbc260ea70cc995c70d797768f00f895 (patch)
tree3d64a030a637b13b73a77f85ce5e6f32fd8addcb /python/trx
parent63703bb1ff93d024a175983e57d1045dba997b3b (diff)
trx/radio_if.py: implement AFC for both RX and TX paths
AFC (Automatic Frequency Control) was previously only utilized in the receive path of the radio interface. Now we also need to keep the transmitter frequency as accurate as possible.
Diffstat (limited to 'python/trx')
-rw-r--r--python/trx/radio_if.py104
1 files changed, 84 insertions, 20 deletions
diff --git a/python/trx/radio_if.py b/python/trx/radio_if.py
index dbccae7..1ded337 100644
--- a/python/trx/radio_if.py
+++ b/python/trx/radio_if.py
@@ -29,12 +29,14 @@ import osmosdr
from math import pi
-from gnuradio.filter import firdes
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 burst_to_fn_time(gr.basic_block):
@@ -55,10 +57,29 @@ class burst_to_fn_time(gr.basic_block):
if pmt.to_python(fn_time) is not None:
self.message_port_pub(pmt.intern("fn_time_out"), fn_time_msg)
+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
# Application state flags
trx_started = False
@@ -75,8 +96,10 @@ class radio_if(gr.top_block):
print("[i] Init Radio interface")
# 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")
@@ -97,14 +120,15 @@ class radio_if(gr.top_block):
self.phy_src.set_bandwidth(650e3, 0)
self.phy_src.set_gain(phy_rx_gain)
- self.gsm_input = grgsm.gsm_input(
- ppm = phy_ppm - int(phy_ppm), osr = 4,
- fc = self.rx_freq, samp_rate_in = phy_sample_rate)
+ self.msg_to_tag_src = grgsm.msg_to_tag()
- self.gsm_receiver = grgsm.receiver(4, ([0]), ([]))
+ self.rotator_src = grgsm.controlled_rotator_cc(
+ self.calc_phase_inc(self.rx_freq))
- self.gsm_clck_ctrl = grgsm.clock_offset_control(
- self.rx_freq, phy_sample_rate, osr = 4)
+ 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)
@@ -112,10 +136,18 @@ class radio_if(gr.top_block):
# Connections
self.connect(
(self.phy_src, 0),
- (self.gsm_input, 0))
+ (self.msg_to_tag_src, 0))
self.connect(
- (self.gsm_input, 0),
+ (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(
@@ -126,14 +158,6 @@ class radio_if(gr.top_block):
(self.ts_filter, 'out'),
(self.trx_burst_if, 'bursts'))
- self.msg_connect(
- (self.gsm_receiver, 'measurements'),
- (self.gsm_clck_ctrl, 'measurements'))
-
- self.msg_connect(
- (self.gsm_clck_ctrl, 'ctrl'),
- (self.gsm_input, 'ctrl_in'))
-
# TX Path Definition
self.phy_sink = uhd.usrp_sink(phy_args,
@@ -156,12 +180,17 @@ class radio_if(gr.top_block):
blocks.byte_t, 'packet_len')
self.gmsk_mod = grgsm.gsm_gmsk_mod(
- BT = 4, pulse_duration = 4, sps = 4)
+ 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'),
@@ -185,6 +214,14 @@ class radio_if(gr.top_block):
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))
@@ -205,19 +242,46 @@ class radio_if(gr.top_block):
(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.gsm_clck_ctrl.set_fc(fc)
- self.gsm_input.set_fc(fc)
+ 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):