diff options
authorPau Espin Pedrol <pespin@sysmocom.de>2018-09-20 15:02:03 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2018-09-20 15:03:56 +0200
commita270d9375b9ca2b973578937b68583ea2bf6fc1b (patch)
parent39e3dc9460ed29632c36cb3e119e5c5156a7c83e (diff)
osmotrx: Introduce code architecture chapter
3 files changed, 145 insertions, 0 deletions
diff --git a/OsmoTRX/chapters/code-architecture.adoc b/OsmoTRX/chapters/code-architecture.adoc
new file mode 100644
index 0000000..18d0e3a
--- /dev/null
+++ b/OsmoTRX/chapters/code-architecture.adoc
@@ -0,0 +1,141 @@
+== Code Architecture
+.General overview of main OsmoTRX components
+digraph hierarchy {
+edge[dir=back, arrowtail=empty]
+2[label = "{Transceiver|+ constructor()\l+ destructor()\l+ init()\l+ numChans()\l+ receiveFIFO()\l+ setSignalHandler()}"]
+3[label = "{RadioInterface|...}"]
+4[label = "{RadioInterfaceResamp|...}"]
+5[label = "{RadioInterfaceMulti|...}"]
+6[label = "{RadioDevice|...}"]
+7[label = "{UHDDevice|...}"]
+8[label = "{LMSDevice|...}"]
+9[label = "{USRPDevice|...}"]
+.Example of thread architecture with OsmoTRX configured to use 2 logical RF channels (Trx=Transceiver, RI=RadioIface)
+digraph hierarchy {
+trans [label="Transceiver"];
+radioiface [label="RadioInterface"];
+radiodev [label="RadioDevice"];
+trans:nw->trans:ne [label="Trx.ControlServiceLoop_0"];
+trans:nw->trans:ne [label="Trx.ControlServiceLoop_1"];
+trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_0"];
+trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_1"];
+radioiface:e->trans:e [label="Trx.RxServiceLoop_0"];
+radioiface:e->trans:e [label="Trx.RxServiceLoop_1"];
+radioiface:sw->radiodev:nw [label="Trx.TxLowerLoop"];
+radiodev:ne->radioiface:se [label="Trx.RxLowerLoop"];
+=== Transceiver
+The Transceiver is the main component managing the other components running in
+the OsmoTRX process. There's a unique instance per process.
+This class is quite complex from code point of view, as it starts lots of
+different threads and hence the interaction with this class from the outside is
+quite limited. Only interaction possible is to:
+* `Transceiver()`: Create an instance through its constructor, at this time most
+ configuration is handed to it.
+* `init()`: Start running all the threads.
+* `receiveFIFO()`: Attach a `radioInterface` channel FIFO in order to use it.
+* `setSignalHandler()`: Used to set up a callback to receive certain events
+ asynchronously from the Transceiver. No assumptions can be made about from
+ which thread is the callback being called, which means multi-thread locking
+ precautions may be required in certain cases, similar to usual signal handler
+ processing. One important event received through this path is for instance
+ when the Transceiver detected a fatal error which requires it to stop. Since
+ it cannot stop itself (see destructor below), stopping procedure must be
+ delegated to the user who created the instance.
+* `~Transceiver()`: The destructor, which stops all running threads created at
+ `init()` time. Destroying the object is the only way to stop the `Transceiver`
+ completely, and must be called from a thread not managed by the
+ `Transceiver`, otherwise it will deadlock. Usually it is stopped from the main
+ thread, the one that called the constructor during startup.
+During `init()` time, `Transceiver` will create a noticeable amount of threads,
+which may vary depending on the amount of RF channels requested.
+Static amount of Threads (1 per `Transceiver` instance):
+* `RxLowerLoop`: This thread is responsible for reading bursts from the
+ `RadioInterface`, storing them into its FIFO and sending Clock Indications
+ (<<trx_if_clock_ind>>) to _osmo-bts_trx_.
+* `TxLowerLoop`: Manages pushing bursts from buffers in the FIFO into the
+ `RadioInterface` at expected correct time based on the Transceiver clock.
+Dynamic amount of Threads (1 per RF logical channel on the `Transceiver` instance):
+* `ControlServiceLoop`: Handles commands from the Per-ARFCN Control Interface
+ socket (<<trx_if_control>>). Each thread is responsible for managing one
+ socket related to one ARFCN or which is the same, to one RF logical channel.
+ These are the only threads expected to use the private `start()` and `stop()`
+ methods of the `Transceiver()` class, since those methods don't stop any of
+ the `ControlServiceLoop` threads as they must keep running to handle new
+ commands (for instance, to re-start processing samples with the _POWERON_
+ command).
+* `RxServiceLoop`: Each thread of this type pulls bursts from the
+ `RadioInterface` FIFO for one specific logical RF channel and handles it
+ according to the slot and burst correlation type, finally sending proper data
+ over the TRX Manager UDP socket (<<trx_if>>).
+* `TxPriorityQueueServiceLoop`: Blocks reading from one ARFCN specific TRX
+ Manager UDP socket (<<trx_if>>), and fills the `RadioInterface` with it
+ setting clock related information.
+=== RadioInterface
+The `RadioInterface` sits between the `Transceiver` and the `RadioDevice`, and
+provides extra features to the pipe like channelizers, resamplers, Tx/Rx
+synchronization on some devices, etc.
+If the `RadioDevice` it drives requires it (only _USRP1_ so far), the
+`RadioIntercace` will start and manage a thread internally called
+`AlignRadioServiceLoop` which will align current RX and TX timestamps.
+Different features are offered through different `RadioInterface` subclasses
+which are selected based on configuration and device detected at runtime. Using
+these features may impact on the amount of CPU required to run the entire pipe.
+==== RadioInterfaceResamp
+This subclass of `RadioInterface` is automatically selected when some known
+specific UHD are to be used, since they require resampling to work properly.
+Some of this devices are for instance Ettus B100, USRP2 and X3XX models.
+==== RadioInterfaceMulti
+This subclass of `RadioInterface` is used when <<multiarfcn_mode>> is requested.
+=== RadioDevice
+The `RadioDevice` class is responsible for driving the actual Hardware device.
+It is actually only an interface, and it is implemented in each backend which in
+turn becomes a specific OsmoTRX binary, see <<trx_backends>>.
diff --git a/OsmoTRX/osmotrx-usermanual.adoc b/OsmoTRX/osmotrx-usermanual.adoc
index a713e4a..14f5514 100644
--- a/OsmoTRX/osmotrx-usermanual.adoc
+++ b/OsmoTRX/osmotrx-usermanual.adoc
@@ -29,6 +29,8 @@ include::chapters/trx-devices.adoc[]
diff --git a/common/chapters/trx_if.adoc b/common/chapters/trx_if.adoc
index 4fb8f9b..b684b7b 100644
--- a/common/chapters/trx_if.adoc
+++ b/common/chapters/trx_if.adoc
@@ -11,6 +11,7 @@ is on an odd numbered port P=B+2N+2. The corresponding core-side interface for
every socket is at P+100. For any given build, the number of ARFCN interfaces
can be fixed.
=== Indications on the Master Clock Interface
The master clock interface is output only (from the radio).
@@ -24,6 +25,7 @@ setting the the core should use to give better packet arrival times.
IND CLOCK <totalFrames>
=== Commands on the Per-ARFCN Control Interface
The per-ARFCN control interface uses a command-reponse protocol. Commands are