blob: 45312e6f2b762f092c62db351acb38f7d116b6b8 [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#
Vadim Yanitskiy473b35b2018-08-10 00:20:03 +07006# (C) 2016-2018 by Vadim Yanitskiy <axilirator@gmail.com>
Piotr Krysik902f4eb2017-09-19 08:04:33 +02007#
8# All Rights Reserved
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24import signal
25import getopt
26import sys
27
Vadim Yanitskiy97dc84e2018-08-10 05:29:23 +070028from gnuradio import eng_notation
29
Vadim Yanitskiyba7ad292017-10-17 07:21:59 +070030from grgsm.trx import ctrl_if_bb
31from grgsm.trx import radio_if
32from grgsm.trx import fake_pm
Piotr Krysik902f4eb2017-09-19 08:04:33 +020033
34COPYRIGHT = \
Vadim Yanitskiy473b35b2018-08-10 00:20:03 +070035 "Copyright (C) 2016-2018 by Vadim Yanitskiy <axilirator@gmail.com>\n" \
Piotr Krysik1cc264f2018-09-06 19:57:57 +020036 "Copyright (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com>\n" \
Piotr Krysik902f4eb2017-09-19 08:04:33 +020037 "License GPLv2+: GNU GPL version 2 or later " \
38 "<http://gnu.org/licenses/gpl.html>\n" \
39 "This is free software: you are free to change and redistribute it.\n" \
40 "There is NO WARRANTY, to the extent permitted by law.\n"
41
Piotr Krysik1cc264f2018-09-06 19:57:57 +020042class Application:
43 # Application variables
44 remote_addr = "127.0.0.1"
45 bind_addr = "0.0.0.0"
46 base_port = 6700
47
48 # PHY specific
49 phy_sample_rate = 4 * 1625000 / 6
50 phy_freq_offset_hz = None
51 phy_tx_antenna = "TX/RX"
52 phy_rx_antenna = "RX2"
53 phy_rx_gain = 30
54 phy_tx_gain = 10
55 phy_args = ""
56 phy_ppm = 0
57
58 def __init__(self):
59 self.print_copyright()
60 self.parse_argv()
Piotr Krysik902f4eb2017-09-19 08:04:33 +020061
62 # Set up signal handlers
63 signal.signal(signal.SIGINT, self.sig_handler)
64
65 def run(self):
66 # Init Radio interface
Vadim Yanitskiy5d68aa52017-10-17 11:14:48 +070067 self.radio = radio_if(self.phy_args, self.phy_sample_rate,
Vadim Yanitskiy790b6f02017-10-17 11:47:36 +070068 self.phy_rx_gain, self.phy_tx_gain, self.phy_ppm,
Piotr Krysik1cc264f2018-09-06 19:57:57 +020069 self.phy_rx_antenna, self.phy_tx_antenna,
Vadim Yanitskiy473b35b2018-08-10 00:20:03 +070070 self.bind_addr, self.remote_addr,
71 self.base_port)
Piotr Krysik902f4eb2017-09-19 08:04:33 +020072
Piotr Krysik1cc264f2018-09-06 19:57:57 +020073 # Optional frequency offset
74 if self.phy_freq_offset_hz is not None:
75 self.radio.freq_offset_hz = self.phy_freq_offset_hz
76
Piotr Krysik902f4eb2017-09-19 08:04:33 +020077 # Power measurement emulation
78 # Noise: -120 .. -105
79 # BTS: -75 .. -50
Vadim Yanitskiyba7ad292017-10-17 07:21:59 +070080 self.pm = fake_pm(-120, -105, -75, -50)
Piotr Krysik902f4eb2017-09-19 08:04:33 +020081
82 # Init TRX CTRL interface
Vadim Yanitskiy473b35b2018-08-10 00:20:03 +070083 self.server = ctrl_if_bb(
84 self.remote_addr, self.base_port + 101,
85 self.bind_addr, self.base_port + 1,
Piotr Krysik902f4eb2017-09-19 08:04:33 +020086 self.radio, self.pm)
87
88 print("[i] Init complete")
89
90 # Enter main loop
91 while True:
92 self.server.loop()
93
94 def shutdown(self):
95 print("[i] Shutting down...")
Piotr Krysik902f4eb2017-09-19 08:04:33 +020096 self.radio.shutdown()
97
Piotr Krysik1cc264f2018-09-06 19:57:57 +020098 def print_copyright(self):
99 print(COPYRIGHT)
100
101 def print_help(self):
102 s = " Usage: " + sys.argv[0] + " [options]\n\n" \
103 " Some help...\n" \
104 " -h --help this text\n\n"
105
106 # TRX specific
107 s += " TRX interface specific\n" \
108 " -i --remote-addr Set remote address (default %s)\n" \
109 " -b --bind-addr Set bind address (default %s)\n" \
110 " -p --base-port Set base port number (default %d)\n\n"
111
112 # PHY specific
113 s += " Radio interface specific\n" \
114 " -a --device-args Set device arguments\n" \
115 " -s --sample-rate Set sample rate\n" \
116 " -g --rx-gain Set RX gain (default %d)\n" \
117 " -G --tx-gain Set TX gain (default %d)\n" \
118 " --rx-antenna Set RX antenna (default %s)\n" \
119 " --tx-antenna Set TX antenna (default %s)\n" \
120 " --freq-offset Shift baseband freq. (e.g. -500M)\n" \
121 " --ppm Set frequency correction (default %d)\n"
122
123 print(s % (
124 self.remote_addr,
125 self.bind_addr,
126 self.base_port,
127 self.phy_rx_gain,
128 self.phy_tx_gain,
129 self.phy_rx_antenna,
130 self.phy_tx_antenna,
131 self.phy_ppm))
132
133 def parse_argv(self):
134 try:
135 opts, args = getopt.getopt(sys.argv[1:],
136 "i:b:p:a:s:g:G:h",
137 ["help", "remote-addr=", "bind-addr=", "base-port=",
138 "device-args=", "sample-rate=", "rx-gain=", "tx-gain=",
139 "ppm=", "rx-antenna=", "tx-antenna=", "freq-offset="])
140 except getopt.GetoptError as err:
141 # Print(help and exit)
142 self.print_help()
143 print("[!] " + str(err))
144 sys.exit(2)
145
146 for o, v in opts:
147 if o in ("-h", "--help"):
148 self.print_help()
149 sys.exit(2)
150
151 # TRX specific
152 elif o in ("-i", "--remote-addr"):
153 self.remote_addr = v
154 elif o in ("-b", "--bind-addr"):
155 self.bind_addr = v
156 elif o in ("-p", "--base-port"):
157 if int(v) >= 0 and int(v) <= 65535:
158 self.base_port = int(v)
159 else:
160 print("[!] The port number should be in range [0-65536]")
161 sys.exit(2)
162
163 # PHY specific
164 elif o in ("-a", "--device-args"):
165 self.phy_args = v
166 elif o in ("-s", "--sample-rate"):
167 self.phy_sample_rate = int(v)
168 elif o in ("-g", "--rx-gain"):
169 self.phy_rx_gain = int(v)
170 elif o in ("-G", "--tx-gain"):
171 self.phy_tx_gain = int(v)
172 elif o in ("--rx-antenna"):
173 self.phy_rx_antenna = v
174 elif o in ("--tx-antenna"):
175 self.phy_tx_antenna = v
176 elif o in ("--ppm"):
177 self.phy_ppm = int(v)
178 elif o in ("--freq-offset"):
179 # Convert /\d+(\.\d+)?(M|k)?/ to Hz
180 offset_hz = eng_notation.str_to_num(v)
181 self.phy_freq_offset_hz = offset_hz
182
Piotr Krysik902f4eb2017-09-19 08:04:33 +0200183 def sig_handler(self, signum, frame):
184 print("Signal %d received" % signum)
185 if signum is signal.SIGINT:
186 self.shutdown()
187 sys.exit(0)
188
Piotr Krysikc62a3d92018-09-05 21:36:34 +0200189if __name__ == '__main__':
Piotr Krysik1cc264f2018-09-06 19:57:57 +0200190 app = Application()
191 app.run()