aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2018-09-20 15:02:03 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-11-27 18:36:18 +0100
commitf570b4af62868bb3a3acab674ceeae73e5bdbe2b (patch)
tree669232262602bf319aab1d334981315029353bcb
parent46560ea2546f1338f693ea8ea5a2ea2db6a7adf5 (diff)
osmotrx: Introduce code architecture chapter
-rw-r--r--doc/manuals/chapters/code-architecture.adoc141
-rw-r--r--doc/manuals/osmotrx-usermanual.adoc2
2 files changed, 143 insertions, 0 deletions
diff --git a/doc/manuals/chapters/code-architecture.adoc b/doc/manuals/chapters/code-architecture.adoc
new file mode 100644
index 0000000..18d0e3a
--- /dev/null
+++ b/doc/manuals/chapters/code-architecture.adoc
@@ -0,0 +1,141 @@
+[[code_architecture]]
+== Code Architecture
+
+[[fig-code-architecture-general]]
+.General overview of main OsmoTRX components
+[graphviz]
+----
+digraph hierarchy {
+node[shape=record,style=filled,fillcolor=gray95]
+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|...}"]
+
+2->3[arrowtail=odiamond]
+3->4[constraint=false]
+3->5[constraint=false]
+3->6[arrowtail=odiamond]
+6->7
+6->8
+6->9
+}
+----
+
+[[fig-code-architecture-threads]]
+.Example of thread architecture with OsmoTRX configured to use 2 logical RF channels (Trx=Transceiver, RI=RadioIface)
+[graphviz]
+----
+digraph hierarchy {
+node[shape=record,style=filled,fillcolor=gray95]
+
+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->radiodev[label="RI.AlignRadioServiceLoop"];
+radioiface:sw->radiodev:nw [label="Trx.TxLowerLoop"];
+radiodev:ne->radioiface:se [label="Trx.RxLowerLoop"];
+}
+----
+
+[[code_component_transceiver]]
+=== 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.
+
+[[code_component_radioiface]]
+=== 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.
+
+[[code_component_radiodev]]
+=== 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/doc/manuals/osmotrx-usermanual.adoc b/doc/manuals/osmotrx-usermanual.adoc
index a713e4a..14f5514 100644
--- a/doc/manuals/osmotrx-usermanual.adoc
+++ b/doc/manuals/osmotrx-usermanual.adoc
@@ -29,6 +29,8 @@ include::chapters/trx-devices.adoc[]
include::chapters/trx-backends.adoc[]
+include::chapters/code-architecture.adoc[]
+
include::../common/chapters/trx_if.adoc[]
include::../common/chapters/port_numbers.adoc[]