blob: 18d0e3ab840d984085289b9fddeda55a0818e244 [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
122[label = "{Transceiver|+ constructor()\l+ destructor()\l+ init()\l+ numChans()\l+ receiveFIFO()\l+ setSignalHandler()}"]
133[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
42trans:nw->trans:ne [label="Trx.ControlServiceLoop_0"];
43trans:nw->trans:ne [label="Trx.ControlServiceLoop_1"];
44trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_0"];
45trans:w->radioiface:w [label="Trx.TxPriorityQueueServiceLoop_1"];
46radioiface:e->trans:e [label="Trx.RxServiceLoop_0"];
47radioiface:e->trans:e [label="Trx.RxServiceLoop_1"];
48radioiface->radiodev[label="RI.AlignRadioServiceLoop"];
49radioiface:sw->radiodev:nw [label="Trx.TxLowerLoop"];
50radiodev:ne->radioiface:se [label="Trx.RxLowerLoop"];
51}
52----
53
54[[code_component_transceiver]]
55=== Transceiver
56
57The Transceiver is the main component managing the other components running in
58the OsmoTRX process. There's a unique instance per process.
59
60This class is quite complex from code point of view, as it starts lots of
61different threads and hence the interaction with this class from the outside is
62quite limited. Only interaction possible is to:
63
64* `Transceiver()`: Create an instance through its constructor, at this time most
65 configuration is handed to it.
66* `init()`: Start running all the threads.
67* `receiveFIFO()`: Attach a `radioInterface` channel FIFO in order to use it.
68* `setSignalHandler()`: Used to set up a callback to receive certain events
69 asynchronously from the Transceiver. No assumptions can be made about from
70 which thread is the callback being called, which means multi-thread locking
71 precautions may be required in certain cases, similar to usual signal handler
72 processing. One important event received through this path is for instance
73 when the Transceiver detected a fatal error which requires it to stop. Since
74 it cannot stop itself (see destructor below), stopping procedure must be
75 delegated to the user who created the instance.
76* `~Transceiver()`: The destructor, which stops all running threads created at
77 `init()` time. Destroying the object is the only way to stop the `Transceiver`
78 completely, and must be called from a thread not managed by the
79 `Transceiver`, otherwise it will deadlock. Usually it is stopped from the main
80 thread, the one that called the constructor during startup.
81
82During `init()` time, `Transceiver` will create a noticeable amount of threads,
83which may vary depending on the amount of RF channels requested.
84
85Static amount of Threads (1 per `Transceiver` instance):
86
87* `RxLowerLoop`: This thread is responsible for reading bursts from the
88 `RadioInterface`, storing them into its FIFO and sending Clock Indications
89 (<<trx_if_clock_ind>>) to _osmo-bts_trx_.
90* `TxLowerLoop`: Manages pushing bursts from buffers in the FIFO into the
91 `RadioInterface` at expected correct time based on the Transceiver clock.
92
93Dynamic amount of Threads (1 per RF logical channel on the `Transceiver` instance):
94
95* `ControlServiceLoop`: Handles commands from the Per-ARFCN Control Interface
96 socket (<<trx_if_control>>). Each thread is responsible for managing one
97 socket related to one ARFCN or which is the same, to one RF logical channel.
98 These are the only threads expected to use the private `start()` and `stop()`
99 methods of the `Transceiver()` class, since those methods don't stop any of
100 the `ControlServiceLoop` threads as they must keep running to handle new
101 commands (for instance, to re-start processing samples with the _POWERON_
102 command).
103* `RxServiceLoop`: Each thread of this type pulls bursts from the
104 `RadioInterface` FIFO for one specific logical RF channel and handles it
105 according to the slot and burst correlation type, finally sending proper data
106 over the TRX Manager UDP socket (<<trx_if>>).
107* `TxPriorityQueueServiceLoop`: Blocks reading from one ARFCN specific TRX
108 Manager UDP socket (<<trx_if>>), and fills the `RadioInterface` with it
109 setting clock related information.
110
111[[code_component_radioiface]]
112=== RadioInterface
113
114The `RadioInterface` sits between the `Transceiver` and the `RadioDevice`, and
115provides extra features to the pipe like channelizers, resamplers, Tx/Rx
116synchronization on some devices, etc.
117
118If the `RadioDevice` it drives requires it (only _USRP1_ so far), the
119`RadioIntercace` will start and manage a thread internally called
120`AlignRadioServiceLoop` which will align current RX and TX timestamps.
121
122Different features are offered through different `RadioInterface` subclasses
123which are selected based on configuration and device detected at runtime. Using
124these features may impact on the amount of CPU required to run the entire pipe.
125
126==== RadioInterfaceResamp
127
128This subclass of `RadioInterface` is automatically selected when some known
129specific UHD are to be used, since they require resampling to work properly.
130Some of this devices are for instance Ettus B100, USRP2 and X3XX models.
131
132==== RadioInterfaceMulti
133
134This subclass of `RadioInterface` is used when <<multiarfcn_mode>> is requested.
135
136[[code_component_radiodev]]
137=== RadioDevice
138
139The `RadioDevice` class is responsible for driving the actual Hardware device.
140It is actually only an interface, and it is implemented in each backend which in
141turn becomes a specific OsmoTRX binary, see <<trx_backends>>.