From a270d9375b9ca2b973578937b68583ea2bf6fc1b Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 20 Sep 2018 15:02:03 +0200 Subject: osmotrx: Introduce code architecture chapter Change-Id: I21084e6315d79a1adcb305e12343da218837dc31 --- OsmoTRX/chapters/code-architecture.adoc | 141 ++++++++++++++++++++++++++++++++ OsmoTRX/osmotrx-usermanual.adoc | 2 + common/chapters/trx_if.adoc | 2 + 3 files changed, 145 insertions(+) create mode 100644 OsmoTRX/chapters/code-architecture.adoc 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]] +== 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 + (<>) 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 (<>). 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 (<>). +* `TxPriorityQueueServiceLoop`: Blocks reading from one ARFCN specific TRX + Manager UDP socket (<>), 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 <> 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 <>. 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[] include::chapters/trx-backends.adoc[] +include::chapters/code-architecture.adoc[] + include::../common/chapters/trx_if.adoc[] include::../common/chapters/port_numbers.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. +[[trx_if_clock_ind]] === 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 ---- +[[trx_if_control]] === Commands on the Per-ARFCN Control Interface The per-ARFCN control interface uses a command-reponse protocol. Commands are -- cgit v1.2.3