blob: 689f0747a464acf25cc511f845702b8e13c54f8c [file] [log] [blame]
Piotr Krysik902f4eb2017-09-19 08:04:33 +02001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
3
4# GR-GSM based transceiver
5# Follow graph implementation
6#
7# (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
8#
9# All Rights Reserved
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License along
22# with this program; if not, write to the Free Software Foundation, Inc.,
23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
25import pmt
26import time
27import grgsm
28import osmosdr
29
30from math import pi
31
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070032from gnuradio.filter import firdes
33from gnuradio import digital
Piotr Krysik902f4eb2017-09-19 08:04:33 +020034from gnuradio import blocks
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070035from gnuradio import uhd
Piotr Krysik902f4eb2017-09-19 08:04:33 +020036from gnuradio import gr
37
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070038
39# HACK: should be implemented in C++!
40import numpy as np
41
42class burst_type_filter(gr.sync_block):
43 def __init__(self, burst_types=[]):
44 gr.sync_block.__init__(
45 self,
46 name='Burst type filter',
47 in_sig=[],
48 out_sig=[]
49 )
50 self.burst_types = burst_types
51 self.message_port_register_in(pmt.intern("bursts_in"))
52 self.message_port_register_out(pmt.intern("bursts_out"))
53 self.set_msg_handler(pmt.intern("bursts_in"), self.filter)
54
55 def filter(self, msg):
56 burst_with_header = pmt.to_python(pmt.cdr(msg))
57 burst = burst_with_header[-148:]
58 header = np.ndarray.tolist(burst_with_header[0:-148])
59 burst_type = header[12]
60 if burst_type in self.burst_types:
61 self.message_port_pub(pmt.intern("bursts_out"), msg)
62
63class burst_to_fn_time(gr.basic_block):
64 def __init__(self): # only default arguments here
65 gr.basic_block.__init__(
66 self,
67 name='Burst to fn_time',
68 in_sig=[],
69 out_sig=[]
70 )
71 self.message_port_register_in(pmt.intern("bursts_in"))
72 self.message_port_register_out(pmt.intern("fn_time_out"))
73 self.set_msg_handler(pmt.intern("bursts_in"), self.convert)
74
75 def convert(self, msg):
76 fn_time = pmt.dict_ref(pmt.car(msg),pmt.intern("fn_time"),pmt.PMT_NIL)
77 fn_time_msg = pmt.dict_add(pmt.make_dict(), pmt.intern("fn_time"), fn_time)
78 if pmt.to_python(fn_time) is not None:
79 self.message_port_pub(pmt.intern("fn_time_out"), fn_time_msg)
80
Vadim Yanitskiy873e44e2017-10-17 06:52:01 +070081class radio_if(gr.top_block):
Piotr Krysik902f4eb2017-09-19 08:04:33 +020082 # PHY specific variables
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070083 rx_freq = 935e6
84 tx_freq = 890e6
Piotr Krysik902f4eb2017-09-19 08:04:33 +020085
86 # Application state flags
87 trx_started = False
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070088
89 # GSM timings
90 delay_correction = 285.616e-6
91 ul_dl_shift = -(6.0/1625000*(156.25)*3)
Piotr Krysik902f4eb2017-09-19 08:04:33 +020092
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070093 def __init__(self, phy_args, phy_sample_rate,
94 phy_rx_gain, phy_tx_gain, phy_ppm,
95 phy_rx_antenna, phy_tx_antenna,
Vadim Yanitskiy5d68aa52017-10-17 11:14:48 +070096 trx_remote_addr, trx_base_port):
Piotr Krysik902f4eb2017-09-19 08:04:33 +020097
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070098 print("[i] Init Radio interface")
Piotr Krysik902f4eb2017-09-19 08:04:33 +020099
100 # PHY specific variables
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +0700101 self.rx_gain = phy_rx_gain
102 self.tx_gain = phy_tx_gain
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200103
104 gr.top_block.__init__(self, "GR-GSM TRX")
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200105
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700106 # TRX Burst Interface
107 self.trx_burst_if = grgsm.trx_burst_if(
108 trx_remote_addr, str(trx_base_port))
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200109
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200110
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700111 # RX path definition
112 self.phy_src = uhd.usrp_source(phy_args,
113 uhd.stream_args(cpu_format="fc32",
114 channels=range(1)))
115
116 self.phy_src.set_center_freq(self.rx_freq, 0)
117 self.phy_src.set_antenna(phy_rx_antenna, 0)
118 self.phy_src.set_samp_rate(phy_sample_rate)
119 self.phy_src.set_bandwidth(650e3, 0)
120 self.phy_src.set_gain(phy_rx_gain)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200121
122 self.gsm_input = grgsm.gsm_input(
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700123 ppm = phy_ppm - int(phy_ppm), osr = 4,
124 fc = self.rx_freq, samp_rate_in = phy_sample_rate)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200125
126 self.gsm_receiver = grgsm.receiver(4, ([0]), ([]))
127
128 self.gsm_clck_ctrl = grgsm.clock_offset_control(
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700129 self.rx_freq, phy_sample_rate, osr = 4)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200130
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700131 self.ts_filter = grgsm.burst_timeslot_filter(0)
132 self.ts_filter.set_policy(grgsm.FILTER_POLICY_DROP_ALL)
Vadim Yanitskiy962e2d82017-10-17 09:24:55 +0700133
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200134 # Connections
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700135 self.connect(
136 (self.phy_src, 0),
137 (self.gsm_input, 0))
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200138
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700139 self.connect(
140 (self.gsm_input, 0),
141 (self.gsm_receiver, 0))
142
143 self.msg_connect(
144 (self.gsm_receiver, 'C0'),
145 (self.ts_filter, 'in'))
146
147 self.msg_connect(
148 (self.ts_filter, 'out'),
149 (self.trx_burst_if, 'bursts'))
150
151 self.msg_connect(
152 (self.gsm_receiver, 'measurements'),
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200153 (self.gsm_clck_ctrl, 'measurements'))
154
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700155 self.msg_connect(
156 (self.gsm_clck_ctrl, 'ctrl'),
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200157 (self.gsm_input, 'ctrl_in'))
158
Vadim Yanitskiy962e2d82017-10-17 09:24:55 +0700159
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700160 # TX Path Definition
161 self.phy_sink = uhd.usrp_sink(phy_args,
162 uhd.stream_args(cpu_format="fc32",
163 channels=range(1)), "packet_len")
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200164
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700165 self.phy_sink.set_antenna(phy_tx_antenna, 0)
166 self.phy_sink.set_samp_rate(phy_sample_rate)
167 self.phy_sink.set_center_freq(self.tx_freq, 0)
168 self.phy_sink.set_gain(self.tx_gain)
169
170 self.tx_time_setter = grgsm.txtime_setter(
171 0xffffffff, 0, 0, 0, 0, 0,
172 self.delay_correction + self.ul_dl_shift)
173
174 self.tx_burst_proc = grgsm.preprocess_tx_burst()
175
176 self.pdu_to_tagged_stream = blocks.pdu_to_tagged_stream(
177 blocks.byte_t, 'packet_len')
178
179 self.gmsk_mod = grgsm.gsm_gmsk_mod(
180 BT = 4, pulse_duration = 4, sps = 4)
181
182 self.burst_shaper = digital.burst_shaper_cc(
183 (firdes.window(firdes.WIN_HANN, 16, 0)),
184 0, 20, False, "packet_len")
185
186 # Connections
187 self.msg_connect(
188 (self.trx_burst_if, 'bursts'),
189 (self.tx_time_setter, 'bursts_in'))
190
191 self.msg_connect(
192 (self.tx_time_setter, 'bursts_out'),
193 (self.tx_burst_proc, 'bursts_in'))
194
195 self.msg_connect(
196 (self.tx_burst_proc, 'bursts_out'),
197 (self.pdu_to_tagged_stream, 'pdus'))
198
199 self.connect(
200 (self.pdu_to_tagged_stream, 0),
201 (self.gmsk_mod, 0))
202
203 self.connect(
204 (self.gmsk_mod, 0),
205 (self.burst_shaper, 0))
206
207 self.connect(
208 (self.burst_shaper, 0),
209 (self.phy_sink, 0))
210
211
212 # RX & TX synchronization
213 self.bt_filter = burst_type_filter([3])
214 self.burst_to_fn_time = burst_to_fn_time()
215
216 # Connections
217 self.msg_connect(
218 (self.gsm_receiver, 'C0'),
219 (self.bt_filter, 'bursts_in'))
220
221 self.msg_connect(
222 (self.bt_filter, 'bursts_out'),
223 (self.burst_to_fn_time, 'bursts_in'))
224
225 self.msg_connect(
226 (self.burst_to_fn_time, 'fn_time_out'),
227 (self.tx_time_setter, 'fn_time'))
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200228
229 def shutdown(self):
230 print("[i] Shutdown Radio interface")
231 self.stop()
232 self.wait()
233
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700234 def set_rx_freq(self, fc):
235 self.phy_src.set_center_freq(fc, 0)
236 self.gsm_clck_ctrl.set_fc(fc)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200237 self.gsm_input.set_fc(fc)
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700238 self.rx_freq = fc
239
240 def set_tx_freq(self, fc):
241 self.phy_sink.set_center_freq(fc, 0)
242 self.tx_freq = fc
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200243
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700244 def set_rx_gain(self, gain):
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700245 self.phy_src.set_gain(gain, 0)
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700246 self.rx_gain = gain
247
248 def set_tx_gain(self, gain):
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700249 self.phy_sink.set_gain(gain, 0)
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700250 self.tx_gain = gain