blob: 1cb25428ed9ac75df725cd643121f96a496ef745 [file] [log] [blame]
Pau Espin Pedrolf570b4a2018-09-20 15:02:03 +02001[[code_architecture]]
2== Code Architecture
3
4[[fig-code-architecture-general]]
5.General overview of main OsmoTRX components
6[graphviz]
7----
8digraph hierarchy {
9node[shape=record,style=filled,fillcolor=gray95]
10edge[dir=back, arrowtail=empty]
11
Pau Espin Pedrol8fd51cb2024-03-26 18:14:08 +0100122[label = "{Transceiver|+ constructor()\l+ destructor()\l+ init()\l+ numChans()\l+ receiveFIFO()\l+ setSignalHandler()\l}"]
Pau Espin Pedrolf570b4a2018-09-20 15:02:03 +0200133[label = "{RadioInterface|...}"]
144[label = "{RadioInterfaceResamp|...}"]
155[label = "{RadioInterfaceMulti|...}"]
166[label = "{RadioDevice|...}"]
177[label = "{UHDDevice|...}"]
188[label = "{LMSDevice|...}"]
199[label = "{USRPDevice|...}"]
20
212->3[arrowtail=odiamond]
223->4[constraint=false]
233->5[constraint=false]
243->6[arrowtail=odiamond]
256->7
266->8
276->9
28}
29----
30
31[[fig-code-architecture-threads]]
32.Example of thread architecture with OsmoTRX configured to use 2 logical RF channels (Trx=Transceiver, RI=RadioIface)
33[graphviz]
34----
35digraph hierarchy {
36node[shape=record,style=filled,fillcolor=gray95]
37
38trans [label="Transceiver"];
39radioiface [label="RadioInterface"];
40radiodev [label="RadioDevice"];
41
Pau Espin Pedrolc62a0512020-07-01 12:24:52 +020042trans:nw->trans:ne [label="Main"];
Pau Espin Pedrolf570b4a2018-09-20 15:02:03 +020043trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_0"];
44trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_1"];
45radioiface:e->trans:e [label="Trx.RxServiceLoop_0"];
46radioiface:e->trans:e [label="Trx.RxServiceLoop_1"];
47radioiface->radiodev[label="RI.AlignRadioServiceLoop"];
48radioiface:sw->radiodev:nw [label="Trx.TxLowerLoop"];
49radiodev:ne->radioiface:se [label="Trx.RxLowerLoop"];
50}
51----
52
53[[code_component_transceiver]]
54=== Transceiver
55
56The Transceiver is the main component managing the other components running in
57the OsmoTRX process. There's a unique instance per process.
58
59This class is quite complex from code point of view, as it starts lots of
60different threads and hence the interaction with this class from the outside is
61quite limited. Only interaction possible is to:
62
63* `Transceiver()`: Create an instance through its constructor, at this time most
64 configuration is handed to it.
65* `init()`: Start running all the threads.
66* `receiveFIFO()`: Attach a `radioInterface` channel FIFO in order to use it.
67* `setSignalHandler()`: Used to set up a callback to receive certain events
68 asynchronously from the Transceiver. No assumptions can be made about from
69 which thread is the callback being called, which means multi-thread locking
70 precautions may be required in certain cases, similar to usual signal handler
71 processing. One important event received through this path is for instance
72 when the Transceiver detected a fatal error which requires it to stop. Since
73 it cannot stop itself (see destructor below), stopping procedure must be
74 delegated to the user who created the instance.
75* `~Transceiver()`: The destructor, which stops all running threads created at
76 `init()` time. Destroying the object is the only way to stop the `Transceiver`
77 completely, and must be called from a thread not managed by the
78 `Transceiver`, otherwise it will deadlock. Usually it is stopped from the main
79 thread, the one that called the constructor during startup.
80
81During `init()` time, `Transceiver` will create a noticeable amount of threads,
82which may vary depending on the amount of RF channels requested.
83
84Static amount of Threads (1 per `Transceiver` instance):
85
86* `RxLowerLoop`: This thread is responsible for reading bursts from the
87 `RadioInterface`, storing them into its FIFO and sending Clock Indications
88 (<<trx_if_clock_ind>>) to _osmo-bts_trx_.
89* `TxLowerLoop`: Manages pushing bursts from buffers in the FIFO into the
90 `RadioInterface` at expected correct time based on the Transceiver clock.
91
92Dynamic amount of Threads (1 per RF logical channel on the `Transceiver` instance):
93
Pau Espin Pedrolf570b4a2018-09-20 15:02:03 +020094* `RxServiceLoop`: Each thread of this type pulls bursts from the
95 `RadioInterface` FIFO for one specific logical RF channel and handles it
96 according to the slot and burst correlation type, finally sending proper data
97 over the TRX Manager UDP socket (<<trx_if>>).
98* `TxPriorityQueueServiceLoop`: Blocks reading from one ARFCN specific TRX
99 Manager UDP socket (<<trx_if>>), and fills the `RadioInterface` with it
100 setting clock related information.
101
Pau Espin Pedrolc62a0512020-07-01 12:24:52 +0200102All the Per-ARFCN Control Interface socket (<<trx_if_control>>) commands are
103handled by the event loop runnnig on the main thread. This is the only thread
104expected to use the private `start()` and `stop()` methods.
105
Pau Espin Pedrolf570b4a2018-09-20 15:02:03 +0200106[[code_component_radioiface]]
107=== RadioInterface
108
109The `RadioInterface` sits between the `Transceiver` and the `RadioDevice`, and
110provides extra features to the pipe like channelizers, resamplers, Tx/Rx
111synchronization on some devices, etc.
112
113If the `RadioDevice` it drives requires it (only _USRP1_ so far), the
114`RadioIntercace` will start and manage a thread internally called
115`AlignRadioServiceLoop` which will align current RX and TX timestamps.
116
117Different features are offered through different `RadioInterface` subclasses
118which are selected based on configuration and device detected at runtime. Using
119these features may impact on the amount of CPU required to run the entire pipe.
120
121==== RadioInterfaceResamp
122
123This subclass of `RadioInterface` is automatically selected when some known
124specific UHD are to be used, since they require resampling to work properly.
125Some of this devices are for instance Ettus B100, USRP2 and X3XX models.
126
127==== RadioInterfaceMulti
128
129This subclass of `RadioInterface` is used when <<multiarfcn_mode>> is requested.
130
131[[code_component_radiodev]]
132=== RadioDevice
133
134The `RadioDevice` class is responsible for driving the actual Hardware device.
135It is actually only an interface, and it is implemented in each backend which in
136turn becomes a specific OsmoTRX binary, see <<trx_backends>>.