Change in gr-gsm[master]: python/trx: introduce and use Transceiver class

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Vadim Yanitskiy gerrit-no-reply at lists.osmocom.org
Sat Jan 19 04:37:15 UTC 2019


Vadim Yanitskiy has uploaded this change for review. ( https://gerrit.osmocom.org/12635


Change subject: python/trx: introduce and use Transceiver class
......................................................................

python/trx: introduce and use Transceiver class

Change-Id: I6dc88edbb69a68746cc8e01206dc86f7ea2fa80f
---
M apps/grgsm_trx
M python/trx/CMakeLists.txt
M python/trx/__init__.py
M python/trx/ctrl_if_bb.py
M python/trx/radio_if.py
A python/trx/transceiver.py
6 files changed, 142 insertions(+), 54 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/gr-gsm refs/changes/35/12635/1

diff --git a/apps/grgsm_trx b/apps/grgsm_trx
index c3e83d9..5e5e3be 100755
--- a/apps/grgsm_trx
+++ b/apps/grgsm_trx
@@ -29,8 +29,8 @@
 from argparse import ArgumentTypeError
 from gnuradio import eng_notation
 
-from grgsm.trx import CTRLInterfaceBB
 from grgsm.trx import RadioInterface
+from grgsm.trx import Transceiver
 
 COPYRIGHT = \
 	"Copyright (C) 2016-2018 by Vadim Yanitskiy <axilirator at gmail.com>\n" \
@@ -64,18 +64,17 @@
 			self.phy_freq_offset, self.bind_addr,
 			self.remote_addr, self.base_port)
 
-		# Init TRX CTRL interface
-		self.server = CTRLInterfaceBB(
-			self.remote_addr, self.base_port + 101,
-			self.bind_addr, self.base_port + 1,
-			self.radio)
+		# Init Transceiver
+		self.trx = Transceiver(self.bind_addr,
+			self.remote_addr, self.base_port,
+			radio_if = self.radio)
 
 		print("[i] Init complete")
 
 	def run(self):
 		# Enter main loop
 		while True:
-			self.server.loop()
+			self.trx.ctrl_if.loop()
 
 	def shutdown(self):
 		print("[i] Shutting down...")
diff --git a/python/trx/CMakeLists.txt b/python/trx/CMakeLists.txt
index 4333407..11290f3 100644
--- a/python/trx/CMakeLists.txt
+++ b/python/trx/CMakeLists.txt
@@ -25,6 +25,7 @@
     ctrl_if_bb.py
     radio_if.py
     radio_if_grc.py
+    transceiver.py
     dict_toggle_sign.py
     DESTINATION ${GR_PYTHON_DIR}/grgsm/trx
 )
diff --git a/python/trx/__init__.py b/python/trx/__init__.py
index 7b20699..00d370b 100644
--- a/python/trx/__init__.py
+++ b/python/trx/__init__.py
@@ -25,5 +25,6 @@
 from ctrl_if_bb import CTRLInterfaceBB
 from radio_if_grc import RadioInterfaceGRC
 from radio_if import RadioInterface
+from transceiver import Transceiver
 
 from dict_toggle_sign import dict_toggle_sign
diff --git a/python/trx/ctrl_if_bb.py b/python/trx/ctrl_if_bb.py
index 0e194d0..4814263 100644
--- a/python/trx/ctrl_if_bb.py
+++ b/python/trx/ctrl_if_bb.py
@@ -4,7 +4,7 @@
 # GR-GSM based transceiver
 # CTRL interface for OsmocomBB
 #
-# (C) 2016-2017 by Vadim Yanitskiy <axilirator at gmail.com>
+# (C) 2016-2019 by Vadim Yanitskiy <axilirator at gmail.com>
 #
 # All Rights Reserved
 #
@@ -22,49 +22,32 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import grgsm
-
 from ctrl_if import CTRLInterface
 
 class CTRLInterfaceBB(CTRLInterface):
-	def __init__(self, remote_addr, remote_port, bind_addr, bind_port, tb):
-		CTRLInterface.__init__(self, remote_addr, remote_port,
-			bind_addr, bind_port)
-
+	def __init__(self, trx, *ctrl_if_args):
+		CTRLInterface.__init__(self, *ctrl_if_args)
 		print("[i] Init CTRL interface (%s)" % self.desc_link())
 
-		# Set link to the follow graph (top block)
-		self.tb = tb
+		# Transceiver instance we belong to
+		self.trx = trx
 
 	def parse_cmd(self, request):
 		# Power control
 		if self.verify_cmd(request, "POWERON", 0):
 			print("[i] Recv POWERON CMD")
 
-			# Ensure transceiver isn't working
-			if self.tb.trx_started:
-				print("[!] Transceiver already started")
+			# Start transceiver
+			if not self.trx.start():
 				return -1
 
-			print("[i] Starting transceiver...")
-			self.tb.trx_started = True
-			self.tb.start()
-
 			return 0
 
 		elif self.verify_cmd(request, "POWEROFF", 0):
 			print("[i] Recv POWEROFF cmd")
 
-			# TODO: flush all buffers between blocks
-			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()
-
-			# POWEROFF is also used to reset transceiver
-			self.tb.reset()
+			# Stop transceiver
+			self.trx.stop()
 
 			return 0
 
@@ -74,7 +57,7 @@
 
 			# TODO: check gain value
 			gain = int(request[1])
-			self.tb.set_rx_gain(gain)
+			self.trx.radio_if.set_rx_gain(gain)
 
 			return 0
 
@@ -83,7 +66,7 @@
 
 			# TODO: check gain value
 			gain = int(request[1])
-			self.tb.set_tx_gain(gain)
+			self.trx.radio_if.set_tx_gain(gain)
 
 			return 0
 
@@ -93,7 +76,7 @@
 
 			# TODO: check freq range
 			freq = int(request[1]) * 1000
-			self.tb.set_rx_freq(freq)
+			self.trx.radio_if.set_rx_freq(freq)
 
 			return 0
 
@@ -102,7 +85,7 @@
 
 			# TODO: check freq range
 			freq = int(request[1]) * 1000
-			self.tb.set_tx_freq(freq)
+			self.trx.radio_if.set_tx_freq(freq)
 
 			return 0
 
@@ -116,19 +99,12 @@
 				print("[!] TS index should be in range: 0..7")
 				return -1
 
-			# Ignore timeslot type for now
+			# Channel combination number (see GSM TS 05.02)
+			# TODO: check this value
 			config = int(request[2])
-			print("[i] Configure timeslot filter to: %s"
-				% ("drop all" if config == 0 else "TS %d" % tn))
 
-			if config == 0:
-				# Value 0 means 'drop all'
-				self.tb.ts_filter.set_policy(
-					grgsm.FILTER_POLICY_DROP_ALL)
-			else:
-				self.tb.ts_filter.set_policy(
-					grgsm.FILTER_POLICY_DEFAULT)
-				self.tb.ts_filter.set_tn(tn)
+			# TODO: check return value
+			self.trx.radio_if.set_slot(tn, config)
 
 			return 0
 
@@ -138,9 +114,11 @@
 
 			# TODO: check freq range
 			meas_freq = int(request[1]) * 1000
-			meas_dbm = str(self.tb.measure(meas_freq))
+			meas_dbm = self.trx.measure(meas_freq)
+			if meas_dbm is None:
+				return -1
 
-			return (0, [meas_dbm])
+			return (0, [str(meas_dbm)])
 
 		# Timing Advance control
 		elif self.verify_cmd(request, "SETTA", 1):
@@ -152,7 +130,7 @@
 				print("[!] TA value must be in range: 0..63")
 				return -1
 
-			self.tb.set_ta(ta)
+			self.trx.radio_if.set_ta(ta)
 			return 0
 
 		# Misc
diff --git a/python/trx/radio_if.py b/python/trx/radio_if.py
index ed5a8de..ec9cd5f 100644
--- a/python/trx/radio_if.py
+++ b/python/trx/radio_if.py
@@ -47,9 +47,6 @@
 	tx_freq = None
 	osr = 4
 
-	# 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)
@@ -304,6 +301,20 @@
 		self.phy_sink.set_gain(gain, 0)
 		self.tx_gain = gain
 
+	def set_slot(self, slot, config):
+		print("[i] Configure timeslot filter to: %s"
+			% ("drop all" if config == 0 else "tn=%d" % slot))
+
+		if config == 0:
+			# Value 0 is used for deactivation
+			self.ts_filter.set_policy(grgsm.FILTER_POLICY_DROP_ALL)
+		else:
+			# FIXME: ideally, we should (re)configure the Receiver
+			# block, but there is no API for that, and hard-coded
+			# timeslot configuration is used...
+			self.ts_filter.set_policy(grgsm.FILTER_POLICY_DEFAULT)
+			self.ts_filter.set_tn(slot)
+
 	def set_ta(self, ta):
 		print("[i] Setting TA value %d" % ta)
 		advance_time_sec = ta * self.GSM_SYM_PERIOD_uS * 1e-6
diff --git a/python/trx/transceiver.py b/python/trx/transceiver.py
new file mode 100644
index 0000000..837a61f
--- /dev/null
+++ b/python/trx/transceiver.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+# GR-GSM based transceiver
+# Transceiver implementation
+#
+# (C) 2018-2019 by Vadim Yanitskiy <axilirator at gmail.com>
+#
+# All Rights Reserved
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+from ctrl_if_bb import CTRLInterfaceBB
+
+class Transceiver:
+	""" Base transceiver implementation.
+
+	Represents a single transceiver, that can be used as for the BTS side,
+	as for the MS side. Each individual instance of Transceiver unifies
+	three basic interfaces built on three independent UDP connections:
+
+	  - CLCK (base port + 100/0) - clock indications from TRX to L1,
+	  - CTRL (base port + 101/1) - control interface for L1,
+	  - DATA (base port + 102/2) - bidirectional data interface for bursts.
+
+	A transceiver can be either in active (i.e. working), or in idle mode.
+
+	NOTE: both CLCK and DATA interfaces are handled by the flow-graph,
+	      (see RadioInterface), so we only initialize CTRL interface.
+
+	"""
+
+	def __init__(self, bind_addr, remote_addr, base_port, radio_if):
+		# Connection info
+		self.remote_addr = remote_addr
+		self.bind_addr = bind_addr
+		self.base_port = base_port
+
+		# Execution state (running or idle)
+		self.running = False
+
+		# Radio interface (handles both CLCK and DATA interfaces)
+		self.radio_if = radio_if
+
+		# Init CTRL interface
+		self.ctrl_if = CTRLInterfaceBB(self,
+			remote_addr, base_port + 101,
+			bind_addr, base_port + 1)
+
+	def start(self):
+		# Check execution state
+		if self.running:
+			print("[!] Transceiver is already started")
+			return False
+
+		# Make sure that Radio interface is ready, i.e.
+		# all parameters (e.g. RX / RX freq) are set.
+		if not self.radio_if.ready:
+			print("[!] RadioInterface is not ready")
+			return False
+
+		print("[i] Starting transceiver...")
+		self.radio_if.start()
+		self.running = True
+
+		return True
+
+	def stop(self):
+		# POWEROFF is also used to reset transceiver,
+		# so we should not complain that it isn't running.
+		if not self.running:
+			print("[i] Resetting transceiver")
+			self.radio_if.reset()
+			return
+
+		print("[i] Stopping transceiver...")
+
+		# TODO: flush all buffers between blocks
+		self.radio_if.stop()
+		self.radio_if.wait()
+
+		self.running = False
+
+	def measure(self, freq):
+		# TODO: transceiver should be in idle mode
+		return self.radio_if.measure(freq)

-- 
To view, visit https://gerrit.osmocom.org/12635
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: gr-gsm
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6dc88edbb69a68746cc8e01206dc86f7ea2fa80f
Gerrit-Change-Number: 12635
Gerrit-PatchSet: 1
Gerrit-Owner: Vadim Yanitskiy <axilirator at gmail.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190119/74755110/attachment.htm>


More information about the gerrit-log mailing list