blob: dbccae7a1e45e0a8a36fde2663aa6adb43224c0e [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++!
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070040class burst_to_fn_time(gr.basic_block):
41 def __init__(self): # only default arguments here
42 gr.basic_block.__init__(
43 self,
44 name='Burst to fn_time',
45 in_sig=[],
46 out_sig=[]
47 )
48 self.message_port_register_in(pmt.intern("bursts_in"))
49 self.message_port_register_out(pmt.intern("fn_time_out"))
50 self.set_msg_handler(pmt.intern("bursts_in"), self.convert)
51
52 def convert(self, msg):
53 fn_time = pmt.dict_ref(pmt.car(msg),pmt.intern("fn_time"),pmt.PMT_NIL)
54 fn_time_msg = pmt.dict_add(pmt.make_dict(), pmt.intern("fn_time"), fn_time)
55 if pmt.to_python(fn_time) is not None:
56 self.message_port_pub(pmt.intern("fn_time_out"), fn_time_msg)
57
Vadim Yanitskiy873e44e2017-10-17 06:52:01 +070058class radio_if(gr.top_block):
Piotr Krysik902f4eb2017-09-19 08:04:33 +020059 # PHY specific variables
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070060 rx_freq = 935e6
61 tx_freq = 890e6
Piotr Krysik902f4eb2017-09-19 08:04:33 +020062
63 # Application state flags
64 trx_started = False
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070065
66 # GSM timings
67 delay_correction = 285.616e-6
68 ul_dl_shift = -(6.0/1625000*(156.25)*3)
Piotr Krysik902f4eb2017-09-19 08:04:33 +020069
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070070 def __init__(self, phy_args, phy_sample_rate,
71 phy_rx_gain, phy_tx_gain, phy_ppm,
72 phy_rx_antenna, phy_tx_antenna,
Vadim Yanitskiy5d68aa52017-10-17 11:14:48 +070073 trx_remote_addr, trx_base_port):
Piotr Krysik902f4eb2017-09-19 08:04:33 +020074
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070075 print("[i] Init Radio interface")
Piotr Krysik902f4eb2017-09-19 08:04:33 +020076
77 # PHY specific variables
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070078 self.rx_gain = phy_rx_gain
79 self.tx_gain = phy_tx_gain
Piotr Krysik902f4eb2017-09-19 08:04:33 +020080
81 gr.top_block.__init__(self, "GR-GSM TRX")
Piotr Krysik902f4eb2017-09-19 08:04:33 +020082
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070083 # TRX Burst Interface
84 self.trx_burst_if = grgsm.trx_burst_if(
85 trx_remote_addr, str(trx_base_port))
Piotr Krysik902f4eb2017-09-19 08:04:33 +020086
Piotr Krysik902f4eb2017-09-19 08:04:33 +020087
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070088 # RX path definition
89 self.phy_src = uhd.usrp_source(phy_args,
90 uhd.stream_args(cpu_format="fc32",
91 channels=range(1)))
92
Vadim Yanitskiy63703bb2017-12-03 23:40:21 +070093 self.phy_src.set_clock_rate(26e6, uhd.ALL_MBOARDS)
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +070094 self.phy_src.set_center_freq(self.rx_freq, 0)
95 self.phy_src.set_antenna(phy_rx_antenna, 0)
96 self.phy_src.set_samp_rate(phy_sample_rate)
97 self.phy_src.set_bandwidth(650e3, 0)
98 self.phy_src.set_gain(phy_rx_gain)
Piotr Krysik902f4eb2017-09-19 08:04:33 +020099
100 self.gsm_input = grgsm.gsm_input(
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700101 ppm = phy_ppm - int(phy_ppm), osr = 4,
102 fc = self.rx_freq, samp_rate_in = phy_sample_rate)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200103
104 self.gsm_receiver = grgsm.receiver(4, ([0]), ([]))
105
106 self.gsm_clck_ctrl = grgsm.clock_offset_control(
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700107 self.rx_freq, phy_sample_rate, osr = 4)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200108
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700109 self.ts_filter = grgsm.burst_timeslot_filter(0)
110 self.ts_filter.set_policy(grgsm.FILTER_POLICY_DROP_ALL)
Vadim Yanitskiy962e2d82017-10-17 09:24:55 +0700111
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200112 # Connections
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700113 self.connect(
114 (self.phy_src, 0),
115 (self.gsm_input, 0))
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200116
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700117 self.connect(
118 (self.gsm_input, 0),
119 (self.gsm_receiver, 0))
120
121 self.msg_connect(
122 (self.gsm_receiver, 'C0'),
123 (self.ts_filter, 'in'))
124
125 self.msg_connect(
126 (self.ts_filter, 'out'),
127 (self.trx_burst_if, 'bursts'))
128
129 self.msg_connect(
130 (self.gsm_receiver, 'measurements'),
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200131 (self.gsm_clck_ctrl, 'measurements'))
132
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700133 self.msg_connect(
134 (self.gsm_clck_ctrl, 'ctrl'),
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200135 (self.gsm_input, 'ctrl_in'))
136
Vadim Yanitskiy962e2d82017-10-17 09:24:55 +0700137
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700138 # TX Path Definition
139 self.phy_sink = uhd.usrp_sink(phy_args,
140 uhd.stream_args(cpu_format="fc32",
141 channels=range(1)), "packet_len")
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200142
Vadim Yanitskiy63703bb2017-12-03 23:40:21 +0700143 self.phy_sink.set_clock_rate(26e6, uhd.ALL_MBOARDS)
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700144 self.phy_sink.set_antenna(phy_tx_antenna, 0)
145 self.phy_sink.set_samp_rate(phy_sample_rate)
146 self.phy_sink.set_center_freq(self.tx_freq, 0)
147 self.phy_sink.set_gain(self.tx_gain)
148
149 self.tx_time_setter = grgsm.txtime_setter(
150 0xffffffff, 0, 0, 0, 0, 0,
151 self.delay_correction + self.ul_dl_shift)
152
153 self.tx_burst_proc = grgsm.preprocess_tx_burst()
154
155 self.pdu_to_tagged_stream = blocks.pdu_to_tagged_stream(
156 blocks.byte_t, 'packet_len')
157
158 self.gmsk_mod = grgsm.gsm_gmsk_mod(
159 BT = 4, pulse_duration = 4, sps = 4)
160
161 self.burst_shaper = digital.burst_shaper_cc(
162 (firdes.window(firdes.WIN_HANN, 16, 0)),
163 0, 20, False, "packet_len")
164
165 # Connections
166 self.msg_connect(
167 (self.trx_burst_if, 'bursts'),
168 (self.tx_time_setter, 'bursts_in'))
169
170 self.msg_connect(
171 (self.tx_time_setter, 'bursts_out'),
172 (self.tx_burst_proc, 'bursts_in'))
173
174 self.msg_connect(
175 (self.tx_burst_proc, 'bursts_out'),
176 (self.pdu_to_tagged_stream, 'pdus'))
177
178 self.connect(
179 (self.pdu_to_tagged_stream, 0),
180 (self.gmsk_mod, 0))
181
182 self.connect(
183 (self.gmsk_mod, 0),
184 (self.burst_shaper, 0))
185
186 self.connect(
187 (self.burst_shaper, 0),
188 (self.phy_sink, 0))
189
190
191 # RX & TX synchronization
Vadim Yanitskiy4650fad2017-12-01 05:08:35 +0700192 self.bt_filter = grgsm.burst_type_filter([3])
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700193 self.burst_to_fn_time = burst_to_fn_time()
194
195 # Connections
196 self.msg_connect(
197 (self.gsm_receiver, 'C0'),
198 (self.bt_filter, 'bursts_in'))
199
200 self.msg_connect(
201 (self.bt_filter, 'bursts_out'),
202 (self.burst_to_fn_time, 'bursts_in'))
203
204 self.msg_connect(
205 (self.burst_to_fn_time, 'fn_time_out'),
206 (self.tx_time_setter, 'fn_time'))
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200207
208 def shutdown(self):
209 print("[i] Shutdown Radio interface")
210 self.stop()
211 self.wait()
212
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700213 def set_rx_freq(self, fc):
214 self.phy_src.set_center_freq(fc, 0)
215 self.gsm_clck_ctrl.set_fc(fc)
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200216 self.gsm_input.set_fc(fc)
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700217 self.rx_freq = fc
218
219 def set_tx_freq(self, fc):
220 self.phy_sink.set_center_freq(fc, 0)
221 self.tx_freq = fc
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200222
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700223 def set_rx_gain(self, gain):
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700224 self.phy_src.set_gain(gain, 0)
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700225 self.rx_gain = gain
226
227 def set_tx_gain(self, gain):
Vadim Yanitskiy89aa4692017-11-14 00:15:20 +0700228 self.phy_sink.set_gain(gain, 0)
Vadim Yanitskiy01c6afd2017-10-19 01:14:24 +0700229 self.tx_gain = gain