blob: 2e8bc11fd3b3bf24f485f23f6fc5d33858e4f661 [file] [log] [blame]
Ericb7253c62022-11-28 19:21:08 +01001/*
2 * (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * All Rights Reserved
4 *
5 * Author: Eric Wild <ewild@sysmocom.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
Eric135d64b2023-04-21 13:59:56 +020022#include <csignal>
Ericb7253c62022-11-28 19:21:08 +010023#include "sigProcLib.h"
24#include "ms.h"
25#include <signalVector.h>
26#include <radioVector.h>
27#include <radioInterface.h>
28#include <grgsm_vitac/grgsm_vitac.h>
29
Ericd372eb22023-08-29 23:23:24 +020030// #define TXDEBUG
31
Ericb7253c62022-11-28 19:21:08 +010032extern "C" {
Ericb7253c62022-11-28 19:21:08 +010033
34#include "sch.h"
35#include "convolve.h"
36#include "convert.h"
37
Vadim Yanitskiy70ed3d52023-09-06 01:54:52 +070038#include <osmocom/core/application.h>
Eric135d64b2023-04-21 13:59:56 +020039#include <osmocom/gsm/gsm_utils.h>
Vadim Yanitskiy70ed3d52023-09-06 01:54:52 +070040
Eric135d64b2023-04-21 13:59:56 +020041#include <osmocom/bb/trxcon/trxcon.h>
42#include <osmocom/bb/trxcon/trxcon_fsm.h>
43#include <osmocom/bb/trxcon/l1ctl_server.h>
44
45extern void trxc_log_init(void *tallctx);
Ericb7253c62022-11-28 19:21:08 +010046#ifdef LSANDEBUG
47void __lsan_do_recoverable_leak_check();
48#endif
49}
50
Eric135d64b2023-04-21 13:59:56 +020051#include "ms_trxcon_if.h"
Ericb7253c62022-11-28 19:21:08 +010052#include "ms_upper.h"
Eric989fe752023-10-06 16:06:13 +020053#include "threadsched.h"
Ericb7253c62022-11-28 19:21:08 +010054
Ericb7253c62022-11-28 19:21:08 +010055extern bool trxc_l1ctl_init(void *tallctx);
Eric135d64b2023-04-21 13:59:56 +020056struct trxcon_inst *g_trxcon;
57tx_queue_t txq;
58cmd_queue_t cmdq_to_phy;
59cmdr_queue_t cmdq_from_phy;
Ericb7253c62022-11-28 19:21:08 +010060
61#ifdef LOG
62#undef LOG
63#define LOG(...) upper_trx::dummy_log()
64#endif
65
66#define DBGLG(...) upper_trx::dummy_log()
67
68std::atomic<bool> g_exit_flag;
69
Ericb3157b92023-05-23 11:32:34 +020070void upper_trx::stop_upper_threads()
71{
72 g_exit_flag = true;
73
Ericd372eb22023-08-29 23:23:24 +020074 pthread_join(thr_control, NULL);
75 pthread_join(thr_tx, NULL);
Ericb3157b92023-05-23 11:32:34 +020076}
Ericd372eb22023-08-29 23:23:24 +020077
Ericb7253c62022-11-28 19:21:08 +010078void upper_trx::start_threads()
79{
Ericd372eb22023-08-29 23:23:24 +020080 DBGLG(...) << "spawning threads.." << std::endl;
81
82 thr_control = spawn_worker_thread(
83 sched_params::thread_names::U_CTL,
84 [](void *args) -> void * {
85 upper_trx *t = reinterpret_cast<upper_trx *>(args);
86#ifdef TXDEBUG
87 struct sched_param param;
88 int policy;
89 pthread_getschedparam(pthread_self(), &policy, &param);
90 printf("ID: %lu, CPU: %d policy = %d priority = %d\n", pthread_self(), sched_getcpu(), policy,
91 param.sched_priority);
92#endif
93 std::cerr << "started U control!" << std::endl;
94 while (!g_exit_flag) {
95 t->driveControl();
96 }
97 std::cerr << "exit U control!" << std::endl;
98
99 return 0;
100 },
101 this);
102 thr_tx = spawn_worker_thread(
103 sched_params::thread_names::U_TX,
104 [](void *args) -> void * {
105 upper_trx *t = reinterpret_cast<upper_trx *>(args);
106#ifdef TXDEBUG
107 struct sched_param param;
108 int policy;
109 pthread_getschedparam(pthread_self(), &policy, &param);
110 printf("ID: %lu, CPU: %d policy = %d priority = %d\n", pthread_self(), sched_getcpu(), policy,
111 param.sched_priority);
112#endif
113 std::cerr << "started U tx!" << std::endl;
114 while (!g_exit_flag) {
115 t->driveTx();
116 }
117 std::cerr << "exit U tx!" << std::endl;
118
119 return 0;
120 },
121 this);
Ericb7253c62022-11-28 19:21:08 +0100122
Ericb7253c62022-11-28 19:21:08 +0100123#ifdef LSANDEBUG
124 std::thread([this] {
Eric805e0d92023-05-23 11:29:18 +0200125 set_name_aff_sched(sched_params::thread_names::LEAKCHECK);
Ericb7253c62022-11-28 19:21:08 +0100126
127 while (1) {
128 std::this_thread::sleep_for(std::chrono::seconds{ 5 });
129 __lsan_do_recoverable_leak_check();
130 }
131 }).detach();
132#endif
133}
134
Ericc3e515a2023-05-08 12:56:56 +0200135void upper_trx::main_loop()
Ericb7253c62022-11-28 19:21:08 +0100136{
Ericc3e515a2023-05-08 12:56:56 +0200137 set_name_aff_sched(sched_params::thread_names::U_RX);
138 set_upper_ready(true);
139 while (!g_exit_flag) {
140 driveReceiveFIFO();
141 osmo_select_main(1);
142
143 trxcon_phyif_rsp r;
144 if (cmdq_from_phy.spsc_pop(&r)) {
145 DBGLG() << "HAVE RESP:" << r.type << std::endl;
146 trxcon_phyif_handle_rsp(g_trxcon, &r);
147 }
148 }
149 set_upper_ready(false);
150 std::cerr << "exit U rx!" << std::endl;
151 mOn = false;
Ericb7253c62022-11-28 19:21:08 +0100152}
153
154// signalvector is owning despite claiming not to, but we can pretend, too..
155static void static_free(void *wData){};
156static void *static_alloc(size_t newSize)
157{
158 return 0;
159};
160
161bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
162{
163 float pow, avg = 1.0;
164 const auto zero_pad_len = 40; // give the VA some runway for misaligned bursts
165 const auto workbuf_size = zero_pad_len + ONE_TS_BURST_LEN + zero_pad_len;
166 static complex workbuf[workbuf_size];
167
168 static signalVector sv(workbuf, zero_pad_len, ONE_TS_BURST_LEN, static_alloc, static_free);
169 one_burst e;
170 auto ss = reinterpret_cast<std::complex<float> *>(&workbuf[zero_pad_len]);
171 std::fill(workbuf, workbuf + workbuf_size, 0);
172 // assert(sv.begin() == &workbuf[40]);
173
174 while (!rxqueue.spsc_pop(&e)) {
175 rxqueue.spsc_prep_pop();
176 }
177
178 wTime = e.gsmts;
179
180 const auto is_sch = gsm_sch_check_ts(wTime.TN(), wTime.FN());
181 const auto is_fcch = gsm_fcch_check_ts(wTime.TN(), wTime.FN());
182
Eric135d64b2023-04-21 13:59:56 +0200183 trxcon_phyif_rtr_ind i = { static_cast<uint32_t>(wTime.FN()), static_cast<uint8_t>(wTime.TN()) };
184 trxcon_phyif_rtr_rsp r = {};
185 trxcon_phyif_handle_rtr_ind(g_trxcon, &i, &r);
Ericb7253c62022-11-28 19:21:08 +0100186 if (!(r.flags & TRXCON_PHYIF_RTR_F_ACTIVE))
187 return false;
188
189 if (is_fcch) {
190 // return trash
191 return true;
192 }
193
194 if (is_sch) {
195 for (int i = 0; i < 148; i++)
196 (demodded_softbits)[i] = (e.sch_bits[i]);
197 RSSI = 10;
198 timingOffset = 0;
199 return true;
200 }
201
Eric Wildd8a1dee2024-02-21 19:33:09 +0100202#if 1
Eric Wild621a49e2023-01-12 16:21:58 +0100203 convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
Ericb7253c62022-11-28 19:21:08 +0100204
205 pow = energyDetect(sv, 20 * 4 /*sps*/);
206 if (pow < -1) {
207 LOG(ALERT) << "Received empty burst";
208 return false;
209 }
210
211 avg = sqrt(pow);
212 {
213 float ncmax;
214 std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
215 auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, mTSC);
216#ifdef DBGXX
217 float dcmax;
218 std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
219 auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
220 auto is_nb = ncmax > dcmax;
221 // DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start
222 // << " o db: " << dummy_burst_start << std::endl;
223#endif
224 normal_burst_start = normal_burst_start < 39 ? normal_burst_start : 39;
225 normal_burst_start = normal_burst_start > -39 ? normal_burst_start : -39;
226#ifdef DBGXX
227 // fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
228 // if (is_nb)
229#endif
Erica5a22752023-01-09 22:46:41 +0100230 detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
Ericb7253c62022-11-28 19:21:08 +0100231#ifdef DBGXX
232 // else
233 // detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
234#endif
235 }
Eric Wildd8a1dee2024-02-21 19:33:09 +0100236#else
237
238 // lower layer sch detection offset, easy to verify by just printing the detected value using both the va+sigproc code.
239 convert_and_scale(ss + 16, e.burst, ONE_TS_BURST_LEN * 2, 15);
240
241 pow = energyDetect(sv, 20 * 4 /*sps*/);
242 if (pow < -1) {
243 LOG(ALERT) << "Received empty burst";
244 return false;
245 }
246
247 avg = sqrt(pow);
248
249 /* Detect normal or RACH bursts */
250 CorrType type = CorrType::TSC;
251 struct estim_burst_params ebp;
252 auto rc = detectAnyBurst(sv, mTSC, 3, 4, type, 48, &ebp);
253 if (rc > 0) {
254 type = (CorrType)rc;
255 }
256
257 if (rc < 0) {
258 std::cerr << "UR : \x1B[31m rx fail \033[0m @ toa:" << ebp.toa << " " << e.gsmts.FN() << ":"
259 << e.gsmts.TN() << std::endl;
260 return false;
261 }
262 SoftVector *bits = demodAnyBurst(sv, type, 4, &ebp);
263
264 SoftVector::const_iterator burstItr = bits->begin();
265 // invert and fix to +-127 sbits
266 for (int ii = 0; ii < 148; ii++) {
267 demodded_softbits[ii] = *burstItr++ > 0.0f ? -127 : 127;
268 }
269 delete bits;
270
271#endif
Ericb7253c62022-11-28 19:21:08 +0100272 RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
273 // FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
274 timingOffset = (int)round(0);
275
276 return true;
277}
278
279void upper_trx::driveReceiveFIFO()
280{
281 int RSSI;
282 int TOA; // in 1/256 of a symbol
283 GSM::Time burstTime;
284
285 if (!mOn)
286 return;
287
288 if (pullRadioVector(burstTime, RSSI, TOA)) {
Eric135d64b2023-04-21 13:59:56 +0200289 trxcon_phyif_burst_ind bi;
Ericb7253c62022-11-28 19:21:08 +0100290 bi.fn = burstTime.FN();
291 bi.tn = burstTime.TN();
292 bi.rssi = RSSI;
293 bi.toa256 = TOA;
294 bi.burst = (sbit_t *)demodded_softbits;
295 bi.burst_len = sizeof(demodded_softbits);
Eric135d64b2023-04-21 13:59:56 +0200296 trxcon_phyif_handle_burst_ind(g_trxcon, &bi);
Ericb7253c62022-11-28 19:21:08 +0100297 }
298
Eric0f4381d2023-09-20 15:19:13 +0200299 burstTime.incTN(2);
Eric135d64b2023-04-21 13:59:56 +0200300 struct trxcon_phyif_rts_ind rts {
Ericb7253c62022-11-28 19:21:08 +0100301 static_cast<uint32_t>(burstTime.FN()), static_cast<uint8_t>(burstTime.TN())
302 };
Eric135d64b2023-04-21 13:59:56 +0200303 trxcon_phyif_handle_rts_ind(g_trxcon, &rts);
Ericb7253c62022-11-28 19:21:08 +0100304}
305
306void upper_trx::driveTx()
307{
Eric135d64b2023-04-21 13:59:56 +0200308 internal_q_tx_buf e;
Ericb7253c62022-11-28 19:21:08 +0100309 static BitVector newBurst(sizeof(e.buf));
Eric135d64b2023-04-21 13:59:56 +0200310 while (!txq.spsc_pop(&e)) {
311 txq.spsc_prep_pop();
Ericb7253c62022-11-28 19:21:08 +0100312 }
313
314 // ensure our tx cb is tickled and can exit
315 if (g_exit_flag) {
Ericb3157b92023-05-23 11:32:34 +0200316 submit_burst_ts(0, 1337, 1);
Ericb7253c62022-11-28 19:21:08 +0100317 return;
318 }
319
Eric135d64b2023-04-21 13:59:56 +0200320 internal_q_tx_buf *burst = &e;
Ericb7253c62022-11-28 19:21:08 +0100321
Ericd372eb22023-08-29 23:23:24 +0200322#ifdef TXDEBUG2
Ericb7253c62022-11-28 19:21:08 +0100323 DBGLG() << "got burst!" << burst->r.fn << ":" << burst->ts << " current: " << timekeeper.gsmtime().FN()
324 << " dff: " << (int64_t)((int64_t)timekeeper.gsmtime().FN() - (int64_t)burst->r.fn) << std::endl;
325#endif
326
327 auto currTime = GSM::Time(burst->r.fn, burst->r.tn);
328 int RSSI = (int)burst->r.pwr;
329
330 BitVector::iterator itr = newBurst.begin();
331 auto *bufferItr = burst->buf;
332 while (itr < newBurst.end())
333 *itr++ = *bufferItr++;
334
335 auto txburst = modulateBurst(newBurst, 8 + (currTime.TN() % 4 == 0), 4);
336 scaleVector(*txburst, txFullScale * pow(10, -RSSI / 10));
337
338 // float -> int16
339 blade_sample_type burst_buf[txburst->size()];
Eric Wild621a49e2023-01-12 16:21:58 +0100340 convert_and_scale(burst_buf, txburst->begin(), txburst->size() * 2, 1);
Ericd372eb22023-08-29 23:23:24 +0200341#ifdef TXDEBUG2
Ericb7253c62022-11-28 19:21:08 +0100342 auto check = signalVector(txburst->size(), 40);
Eric Wild621a49e2023-01-12 16:21:58 +0100343 convert_and_scale(check.begin(), burst_buf, txburst->size() * 2, 1);
Ericb7253c62022-11-28 19:21:08 +0100344 estim_burst_params ebp;
345 auto d = detectAnyBurst(check, 2, 4, 4, CorrType::RACH, 40, &ebp);
346 if (d)
347 DBGLG() << "RACH D! " << ebp.toa << std::endl;
348 else
349 DBGLG() << "RACH NOOOOOOOOOO D! " << ebp.toa << std::endl;
350
351 // memory read --binary --outfile /tmp/mem.bin &burst_buf[0] --count 2500 --force
352#endif
353 submit_burst(burst_buf, txburst->size(), currTime);
354 delete txburst;
355}
356
357#ifdef TXDEBUG
Eric135d64b2023-04-21 13:59:56 +0200358static const char *cmd2str(trxcon_phyif_cmd_type c)
Ericb7253c62022-11-28 19:21:08 +0100359{
360 switch (c) {
Eric135d64b2023-04-21 13:59:56 +0200361 case TRXCON_PHYIF_CMDT_RESET:
Ericb7253c62022-11-28 19:21:08 +0100362 return "TRXCON_PHYIF_CMDT_RESET";
Eric135d64b2023-04-21 13:59:56 +0200363 case TRXCON_PHYIF_CMDT_POWERON:
Ericb7253c62022-11-28 19:21:08 +0100364 return "TRXCON_PHYIF_CMDT_POWERON";
Eric135d64b2023-04-21 13:59:56 +0200365 case TRXCON_PHYIF_CMDT_POWEROFF:
Ericb7253c62022-11-28 19:21:08 +0100366 return "TRXCON_PHYIF_CMDT_POWEROFF";
Eric135d64b2023-04-21 13:59:56 +0200367 case TRXCON_PHYIF_CMDT_MEASURE:
Ericb7253c62022-11-28 19:21:08 +0100368 return "TRXCON_PHYIF_CMDT_MEASURE";
Eric135d64b2023-04-21 13:59:56 +0200369 case TRXCON_PHYIF_CMDT_SETFREQ_H0:
Ericb7253c62022-11-28 19:21:08 +0100370 return "TRXCON_PHYIF_CMDT_SETFREQ_H0";
Eric135d64b2023-04-21 13:59:56 +0200371 case TRXCON_PHYIF_CMDT_SETFREQ_H1:
Ericb7253c62022-11-28 19:21:08 +0100372 return "TRXCON_PHYIF_CMDT_SETFREQ_H1";
Eric135d64b2023-04-21 13:59:56 +0200373 case TRXCON_PHYIF_CMDT_SETSLOT:
Ericb7253c62022-11-28 19:21:08 +0100374 return "TRXCON_PHYIF_CMDT_SETSLOT";
Eric135d64b2023-04-21 13:59:56 +0200375 case TRXCON_PHYIF_CMDT_SETTA:
Ericb7253c62022-11-28 19:21:08 +0100376 return "TRXCON_PHYIF_CMDT_SETTA";
377 default:
378 return "UNKNOWN COMMAND!";
379 }
380}
381
Eric135d64b2023-04-21 13:59:56 +0200382static void print_cmd(trxcon_phyif_cmd_type c)
Ericb7253c62022-11-28 19:21:08 +0100383{
Ericd372eb22023-08-29 23:23:24 +0200384 DBGLG() << "handling " << cmd2str(c) << std::endl;
Ericb7253c62022-11-28 19:21:08 +0100385}
386#endif
387
388bool upper_trx::driveControl()
389{
Eric135d64b2023-04-21 13:59:56 +0200390 trxcon_phyif_rsp r;
391 trxcon_phyif_cmd cmd;
392 while (!cmdq_to_phy.spsc_pop(&cmd)) {
393 cmdq_to_phy.spsc_prep_pop();
Ericd372eb22023-08-29 23:23:24 +0200394 if (g_exit_flag)
395 return false;
Ericb7253c62022-11-28 19:21:08 +0100396 }
397
398 if (g_exit_flag)
399 return false;
400
401#ifdef TXDEBUG
402 print_cmd(cmd.type);
403#endif
404
405 switch (cmd.type) {
Eric135d64b2023-04-21 13:59:56 +0200406 case TRXCON_PHYIF_CMDT_RESET:
Ericb7253c62022-11-28 19:21:08 +0100407 set_ta(0);
408 break;
Eric135d64b2023-04-21 13:59:56 +0200409 case TRXCON_PHYIF_CMDT_POWERON:
Ericb7253c62022-11-28 19:21:08 +0100410 if (!mOn) {
Ericb7253c62022-11-28 19:21:08 +0100411 mOn = true;
Ericc3e515a2023-05-08 12:56:56 +0200412 start_lower_ms();
Ericb7253c62022-11-28 19:21:08 +0100413 }
414 break;
Eric135d64b2023-04-21 13:59:56 +0200415 case TRXCON_PHYIF_CMDT_POWEROFF:
Ericb7253c62022-11-28 19:21:08 +0100416 break;
Eric135d64b2023-04-21 13:59:56 +0200417 case TRXCON_PHYIF_CMDT_MEASURE:
418 r.type = trxcon_phyif_cmd_type::TRXCON_PHYIF_CMDT_MEASURE;
Ericb7253c62022-11-28 19:21:08 +0100419 r.param.measure.band_arfcn = cmd.param.measure.band_arfcn;
420 // FIXME: do we want to measure anything, considering the transceiver just syncs by.. syncing?
421 r.param.measure.dbm = -80;
Eric135d64b2023-04-21 13:59:56 +0200422 tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
423 tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
424 cmdq_from_phy.spsc_push(&r);
Ericb7253c62022-11-28 19:21:08 +0100425 break;
Eric135d64b2023-04-21 13:59:56 +0200426 case TRXCON_PHYIF_CMDT_SETFREQ_H0:
427 tuneRx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 0) * 1000 * 100);
428 tuneTx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 1) * 1000 * 100);
Ericb7253c62022-11-28 19:21:08 +0100429 break;
Eric135d64b2023-04-21 13:59:56 +0200430 case TRXCON_PHYIF_CMDT_SETFREQ_H1:
Ericb7253c62022-11-28 19:21:08 +0100431 break;
Eric135d64b2023-04-21 13:59:56 +0200432 case TRXCON_PHYIF_CMDT_SETSLOT:
Ericb7253c62022-11-28 19:21:08 +0100433 break;
Eric135d64b2023-04-21 13:59:56 +0200434 case TRXCON_PHYIF_CMDT_SETTA:
Ericb7253c62022-11-28 19:21:08 +0100435 set_ta(cmd.param.setta.ta);
436 break;
437 }
438 return false;
439}
440
Ericb7253c62022-11-28 19:21:08 +0100441void sighandler(int sigset)
442{
443 // we might get a sigpipe in case the l1ctl ud socket disconnects because mobile quits
Ericb3157b92023-05-23 11:32:34 +0200444 if (sigset == SIGPIPE || sigset == SIGINT) {
Ericb7253c62022-11-28 19:21:08 +0100445 g_exit_flag = true;
446
447 // we know the flag is atomic and it prevents the trxcon cb handlers from writing
448 // to the queues, so submit some trash to unblock the threads & exit
Eric135d64b2023-04-21 13:59:56 +0200449 trxcon_phyif_cmd cmd = {};
450 internal_q_tx_buf b = {};
451 txq.spsc_push(&b);
452 cmdq_to_phy.spsc_push(&cmd);
Ericb3157b92023-05-23 11:32:34 +0200453 msleep(200);
Ericb7253c62022-11-28 19:21:08 +0100454
455 return;
456 }
457}
458
459int main(int argc, char *argv[])
460{
461 auto tall_trxcon_ctx = talloc_init("trxcon context");
462 signal(SIGPIPE, sighandler);
Ericb3157b92023-05-23 11:32:34 +0200463 signal(SIGINT, sighandler);
Ericb7253c62022-11-28 19:21:08 +0100464
Eric135d64b2023-04-21 13:59:56 +0200465 msgb_talloc_ctx_init(tall_trxcon_ctx, 0);
Ericb7253c62022-11-28 19:21:08 +0100466 trxc_log_init(tall_trxcon_ctx);
467
Vadim Yanitskiy70ed3d52023-09-06 01:54:52 +0700468 /* Configure pretty logging */
469 log_set_print_extended_timestamp(osmo_stderr_target, 1);
470 log_set_print_category_hex(osmo_stderr_target, 0);
471 log_set_print_category(osmo_stderr_target, 1);
472 log_set_print_level(osmo_stderr_target, 1);
473
474 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
475 log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
476
477 osmo_fsm_log_timeouts(true);
478
Eric1499f032023-07-25 18:42:48 +0200479 g_trxcon = trxcon_inst_alloc(tall_trxcon_ctx, 0);
Eric135d64b2023-04-21 13:59:56 +0200480 g_trxcon->gsmtap = nullptr;
481 g_trxcon->phyif = nullptr;
482 g_trxcon->phy_quirks.fbsb_extend_fns = 866; // 4 seconds, known to work.
Ericb7253c62022-11-28 19:21:08 +0100483
484 convolve_init();
485 convert_init();
486 sigProcLibSetup();
487 initvita();
488
489 int status = 0;
490 auto trx = new upper_trx();
491 trx->do_auto_gain = true;
492
493 status = trx->init_dev_and_streams();
Eric Wild10b4e312023-01-11 18:53:48 +0100494 if (status < 0) {
495 std::cerr << "Error initializing hardware, quitting.." << std::endl;
496 return -1;
497 }
Eric989fe752023-10-06 16:06:13 +0200498 set_name_aff_sched(sched_params::thread_names::MAIN);
Ericb7253c62022-11-28 19:21:08 +0100499
Eric135d64b2023-04-21 13:59:56 +0200500 if (!trxc_l1ctl_init(tall_trxcon_ctx)) {
Ericb7253c62022-11-28 19:21:08 +0100501 std::cerr << "Error initializing l1ctl, quitting.." << std::endl;
502 return -1;
503 }
504
Ericb3157b92023-05-23 11:32:34 +0200505 // blocking, will return when global exit is requested
Ericb7253c62022-11-28 19:21:08 +0100506 trx->start_threads();
Ericc3e515a2023-05-08 12:56:56 +0200507 trx->main_loop();
Ericb7253c62022-11-28 19:21:08 +0100508 trx->stop_threads();
Ericb3157b92023-05-23 11:32:34 +0200509 trx->stop_upper_threads();
Ericb7253c62022-11-28 19:21:08 +0100510
511 return status;
512}