blob: db15226fe18bf13b838c65272731f4c1a82ef293 [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"
53
Ericb7253c62022-11-28 19:21:08 +010054extern bool trxc_l1ctl_init(void *tallctx);
Eric135d64b2023-04-21 13:59:56 +020055struct trxcon_inst *g_trxcon;
56tx_queue_t txq;
57cmd_queue_t cmdq_to_phy;
58cmdr_queue_t cmdq_from_phy;
Ericb7253c62022-11-28 19:21:08 +010059
60#ifdef LOG
61#undef LOG
62#define LOG(...) upper_trx::dummy_log()
63#endif
64
65#define DBGLG(...) upper_trx::dummy_log()
66
67std::atomic<bool> g_exit_flag;
68
Ericb3157b92023-05-23 11:32:34 +020069void upper_trx::stop_upper_threads()
70{
71 g_exit_flag = true;
72
Ericd372eb22023-08-29 23:23:24 +020073 pthread_join(thr_control, NULL);
74 pthread_join(thr_tx, NULL);
Ericb3157b92023-05-23 11:32:34 +020075}
Ericd372eb22023-08-29 23:23:24 +020076
Ericb7253c62022-11-28 19:21:08 +010077void upper_trx::start_threads()
78{
Ericd372eb22023-08-29 23:23:24 +020079 DBGLG(...) << "spawning threads.." << std::endl;
80
81 thr_control = spawn_worker_thread(
82 sched_params::thread_names::U_CTL,
83 [](void *args) -> void * {
84 upper_trx *t = reinterpret_cast<upper_trx *>(args);
85#ifdef TXDEBUG
86 struct sched_param param;
87 int policy;
88 pthread_getschedparam(pthread_self(), &policy, &param);
89 printf("ID: %lu, CPU: %d policy = %d priority = %d\n", pthread_self(), sched_getcpu(), policy,
90 param.sched_priority);
91#endif
92 std::cerr << "started U control!" << std::endl;
93 while (!g_exit_flag) {
94 t->driveControl();
95 }
96 std::cerr << "exit U control!" << std::endl;
97
98 return 0;
99 },
100 this);
101 thr_tx = spawn_worker_thread(
102 sched_params::thread_names::U_TX,
103 [](void *args) -> void * {
104 upper_trx *t = reinterpret_cast<upper_trx *>(args);
105#ifdef TXDEBUG
106 struct sched_param param;
107 int policy;
108 pthread_getschedparam(pthread_self(), &policy, &param);
109 printf("ID: %lu, CPU: %d policy = %d priority = %d\n", pthread_self(), sched_getcpu(), policy,
110 param.sched_priority);
111#endif
112 std::cerr << "started U tx!" << std::endl;
113 while (!g_exit_flag) {
114 t->driveTx();
115 }
116 std::cerr << "exit U tx!" << std::endl;
117
118 return 0;
119 },
120 this);
Ericb7253c62022-11-28 19:21:08 +0100121
Ericb7253c62022-11-28 19:21:08 +0100122#ifdef LSANDEBUG
123 std::thread([this] {
Eric805e0d92023-05-23 11:29:18 +0200124 set_name_aff_sched(sched_params::thread_names::LEAKCHECK);
Ericb7253c62022-11-28 19:21:08 +0100125
126 while (1) {
127 std::this_thread::sleep_for(std::chrono::seconds{ 5 });
128 __lsan_do_recoverable_leak_check();
129 }
130 }).detach();
131#endif
132}
133
Ericc3e515a2023-05-08 12:56:56 +0200134void upper_trx::main_loop()
Ericb7253c62022-11-28 19:21:08 +0100135{
Ericc3e515a2023-05-08 12:56:56 +0200136 set_name_aff_sched(sched_params::thread_names::U_RX);
137 set_upper_ready(true);
138 while (!g_exit_flag) {
139 driveReceiveFIFO();
140 osmo_select_main(1);
141
142 trxcon_phyif_rsp r;
143 if (cmdq_from_phy.spsc_pop(&r)) {
144 DBGLG() << "HAVE RESP:" << r.type << std::endl;
145 trxcon_phyif_handle_rsp(g_trxcon, &r);
146 }
147 }
148 set_upper_ready(false);
149 std::cerr << "exit U rx!" << std::endl;
150 mOn = false;
Ericb7253c62022-11-28 19:21:08 +0100151}
152
153// signalvector is owning despite claiming not to, but we can pretend, too..
154static void static_free(void *wData){};
155static void *static_alloc(size_t newSize)
156{
157 return 0;
158};
159
160bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
161{
162 float pow, avg = 1.0;
163 const auto zero_pad_len = 40; // give the VA some runway for misaligned bursts
164 const auto workbuf_size = zero_pad_len + ONE_TS_BURST_LEN + zero_pad_len;
165 static complex workbuf[workbuf_size];
166
167 static signalVector sv(workbuf, zero_pad_len, ONE_TS_BURST_LEN, static_alloc, static_free);
168 one_burst e;
169 auto ss = reinterpret_cast<std::complex<float> *>(&workbuf[zero_pad_len]);
170 std::fill(workbuf, workbuf + workbuf_size, 0);
171 // assert(sv.begin() == &workbuf[40]);
172
173 while (!rxqueue.spsc_pop(&e)) {
174 rxqueue.spsc_prep_pop();
175 }
176
177 wTime = e.gsmts;
178
179 const auto is_sch = gsm_sch_check_ts(wTime.TN(), wTime.FN());
180 const auto is_fcch = gsm_fcch_check_ts(wTime.TN(), wTime.FN());
181
Eric135d64b2023-04-21 13:59:56 +0200182 trxcon_phyif_rtr_ind i = { static_cast<uint32_t>(wTime.FN()), static_cast<uint8_t>(wTime.TN()) };
183 trxcon_phyif_rtr_rsp r = {};
184 trxcon_phyif_handle_rtr_ind(g_trxcon, &i, &r);
Ericb7253c62022-11-28 19:21:08 +0100185 if (!(r.flags & TRXCON_PHYIF_RTR_F_ACTIVE))
186 return false;
187
188 if (is_fcch) {
189 // return trash
190 return true;
191 }
192
193 if (is_sch) {
194 for (int i = 0; i < 148; i++)
195 (demodded_softbits)[i] = (e.sch_bits[i]);
196 RSSI = 10;
197 timingOffset = 0;
198 return true;
199 }
200
Eric Wild621a49e2023-01-12 16:21:58 +0100201 convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
Ericb7253c62022-11-28 19:21:08 +0100202
203 pow = energyDetect(sv, 20 * 4 /*sps*/);
204 if (pow < -1) {
205 LOG(ALERT) << "Received empty burst";
206 return false;
207 }
208
209 avg = sqrt(pow);
210 {
211 float ncmax;
212 std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
213 auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, mTSC);
214#ifdef DBGXX
215 float dcmax;
216 std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
217 auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
218 auto is_nb = ncmax > dcmax;
219 // DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start
220 // << " o db: " << dummy_burst_start << std::endl;
221#endif
222 normal_burst_start = normal_burst_start < 39 ? normal_burst_start : 39;
223 normal_burst_start = normal_burst_start > -39 ? normal_burst_start : -39;
224#ifdef DBGXX
225 // fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
226 // if (is_nb)
227#endif
Erica5a22752023-01-09 22:46:41 +0100228 detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
Ericb7253c62022-11-28 19:21:08 +0100229#ifdef DBGXX
230 // else
231 // detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
232#endif
233 }
234 RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
235 // FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
236 timingOffset = (int)round(0);
237
238 return true;
239}
240
241void upper_trx::driveReceiveFIFO()
242{
243 int RSSI;
244 int TOA; // in 1/256 of a symbol
245 GSM::Time burstTime;
246
247 if (!mOn)
248 return;
249
250 if (pullRadioVector(burstTime, RSSI, TOA)) {
Eric135d64b2023-04-21 13:59:56 +0200251 trxcon_phyif_burst_ind bi;
Ericb7253c62022-11-28 19:21:08 +0100252 bi.fn = burstTime.FN();
253 bi.tn = burstTime.TN();
254 bi.rssi = RSSI;
255 bi.toa256 = TOA;
256 bi.burst = (sbit_t *)demodded_softbits;
257 bi.burst_len = sizeof(demodded_softbits);
Eric135d64b2023-04-21 13:59:56 +0200258 trxcon_phyif_handle_burst_ind(g_trxcon, &bi);
Ericb7253c62022-11-28 19:21:08 +0100259 }
260
Eric0f4381d2023-09-20 15:19:13 +0200261 burstTime.incTN(2);
Eric135d64b2023-04-21 13:59:56 +0200262 struct trxcon_phyif_rts_ind rts {
Ericb7253c62022-11-28 19:21:08 +0100263 static_cast<uint32_t>(burstTime.FN()), static_cast<uint8_t>(burstTime.TN())
264 };
Eric135d64b2023-04-21 13:59:56 +0200265 trxcon_phyif_handle_rts_ind(g_trxcon, &rts);
Ericb7253c62022-11-28 19:21:08 +0100266}
267
268void upper_trx::driveTx()
269{
Eric135d64b2023-04-21 13:59:56 +0200270 internal_q_tx_buf e;
Ericb7253c62022-11-28 19:21:08 +0100271 static BitVector newBurst(sizeof(e.buf));
Eric135d64b2023-04-21 13:59:56 +0200272 while (!txq.spsc_pop(&e)) {
273 txq.spsc_prep_pop();
Ericb7253c62022-11-28 19:21:08 +0100274 }
275
276 // ensure our tx cb is tickled and can exit
277 if (g_exit_flag) {
Ericb3157b92023-05-23 11:32:34 +0200278 submit_burst_ts(0, 1337, 1);
Ericb7253c62022-11-28 19:21:08 +0100279 return;
280 }
281
Eric135d64b2023-04-21 13:59:56 +0200282 internal_q_tx_buf *burst = &e;
Ericb7253c62022-11-28 19:21:08 +0100283
Ericd372eb22023-08-29 23:23:24 +0200284#ifdef TXDEBUG2
Ericb7253c62022-11-28 19:21:08 +0100285 DBGLG() << "got burst!" << burst->r.fn << ":" << burst->ts << " current: " << timekeeper.gsmtime().FN()
286 << " dff: " << (int64_t)((int64_t)timekeeper.gsmtime().FN() - (int64_t)burst->r.fn) << std::endl;
287#endif
288
289 auto currTime = GSM::Time(burst->r.fn, burst->r.tn);
290 int RSSI = (int)burst->r.pwr;
291
292 BitVector::iterator itr = newBurst.begin();
293 auto *bufferItr = burst->buf;
294 while (itr < newBurst.end())
295 *itr++ = *bufferItr++;
296
297 auto txburst = modulateBurst(newBurst, 8 + (currTime.TN() % 4 == 0), 4);
298 scaleVector(*txburst, txFullScale * pow(10, -RSSI / 10));
299
300 // float -> int16
301 blade_sample_type burst_buf[txburst->size()];
Eric Wild621a49e2023-01-12 16:21:58 +0100302 convert_and_scale(burst_buf, txburst->begin(), txburst->size() * 2, 1);
Ericd372eb22023-08-29 23:23:24 +0200303#ifdef TXDEBUG2
Ericb7253c62022-11-28 19:21:08 +0100304 auto check = signalVector(txburst->size(), 40);
Eric Wild621a49e2023-01-12 16:21:58 +0100305 convert_and_scale(check.begin(), burst_buf, txburst->size() * 2, 1);
Ericb7253c62022-11-28 19:21:08 +0100306 estim_burst_params ebp;
307 auto d = detectAnyBurst(check, 2, 4, 4, CorrType::RACH, 40, &ebp);
308 if (d)
309 DBGLG() << "RACH D! " << ebp.toa << std::endl;
310 else
311 DBGLG() << "RACH NOOOOOOOOOO D! " << ebp.toa << std::endl;
312
313 // memory read --binary --outfile /tmp/mem.bin &burst_buf[0] --count 2500 --force
314#endif
315 submit_burst(burst_buf, txburst->size(), currTime);
316 delete txburst;
317}
318
319#ifdef TXDEBUG
Eric135d64b2023-04-21 13:59:56 +0200320static const char *cmd2str(trxcon_phyif_cmd_type c)
Ericb7253c62022-11-28 19:21:08 +0100321{
322 switch (c) {
Eric135d64b2023-04-21 13:59:56 +0200323 case TRXCON_PHYIF_CMDT_RESET:
Ericb7253c62022-11-28 19:21:08 +0100324 return "TRXCON_PHYIF_CMDT_RESET";
Eric135d64b2023-04-21 13:59:56 +0200325 case TRXCON_PHYIF_CMDT_POWERON:
Ericb7253c62022-11-28 19:21:08 +0100326 return "TRXCON_PHYIF_CMDT_POWERON";
Eric135d64b2023-04-21 13:59:56 +0200327 case TRXCON_PHYIF_CMDT_POWEROFF:
Ericb7253c62022-11-28 19:21:08 +0100328 return "TRXCON_PHYIF_CMDT_POWEROFF";
Eric135d64b2023-04-21 13:59:56 +0200329 case TRXCON_PHYIF_CMDT_MEASURE:
Ericb7253c62022-11-28 19:21:08 +0100330 return "TRXCON_PHYIF_CMDT_MEASURE";
Eric135d64b2023-04-21 13:59:56 +0200331 case TRXCON_PHYIF_CMDT_SETFREQ_H0:
Ericb7253c62022-11-28 19:21:08 +0100332 return "TRXCON_PHYIF_CMDT_SETFREQ_H0";
Eric135d64b2023-04-21 13:59:56 +0200333 case TRXCON_PHYIF_CMDT_SETFREQ_H1:
Ericb7253c62022-11-28 19:21:08 +0100334 return "TRXCON_PHYIF_CMDT_SETFREQ_H1";
Eric135d64b2023-04-21 13:59:56 +0200335 case TRXCON_PHYIF_CMDT_SETSLOT:
Ericb7253c62022-11-28 19:21:08 +0100336 return "TRXCON_PHYIF_CMDT_SETSLOT";
Eric135d64b2023-04-21 13:59:56 +0200337 case TRXCON_PHYIF_CMDT_SETTA:
Ericb7253c62022-11-28 19:21:08 +0100338 return "TRXCON_PHYIF_CMDT_SETTA";
339 default:
340 return "UNKNOWN COMMAND!";
341 }
342}
343
Eric135d64b2023-04-21 13:59:56 +0200344static void print_cmd(trxcon_phyif_cmd_type c)
Ericb7253c62022-11-28 19:21:08 +0100345{
Ericd372eb22023-08-29 23:23:24 +0200346 DBGLG() << "handling " << cmd2str(c) << std::endl;
Ericb7253c62022-11-28 19:21:08 +0100347}
348#endif
349
350bool upper_trx::driveControl()
351{
Eric135d64b2023-04-21 13:59:56 +0200352 trxcon_phyif_rsp r;
353 trxcon_phyif_cmd cmd;
354 while (!cmdq_to_phy.spsc_pop(&cmd)) {
355 cmdq_to_phy.spsc_prep_pop();
Ericd372eb22023-08-29 23:23:24 +0200356 if (g_exit_flag)
357 return false;
Ericb7253c62022-11-28 19:21:08 +0100358 }
359
360 if (g_exit_flag)
361 return false;
362
363#ifdef TXDEBUG
364 print_cmd(cmd.type);
365#endif
366
367 switch (cmd.type) {
Eric135d64b2023-04-21 13:59:56 +0200368 case TRXCON_PHYIF_CMDT_RESET:
Ericb7253c62022-11-28 19:21:08 +0100369 set_ta(0);
370 break;
Eric135d64b2023-04-21 13:59:56 +0200371 case TRXCON_PHYIF_CMDT_POWERON:
Ericb7253c62022-11-28 19:21:08 +0100372 if (!mOn) {
Ericb7253c62022-11-28 19:21:08 +0100373 mOn = true;
Ericc3e515a2023-05-08 12:56:56 +0200374 start_lower_ms();
Ericb7253c62022-11-28 19:21:08 +0100375 }
376 break;
Eric135d64b2023-04-21 13:59:56 +0200377 case TRXCON_PHYIF_CMDT_POWEROFF:
Ericb7253c62022-11-28 19:21:08 +0100378 break;
Eric135d64b2023-04-21 13:59:56 +0200379 case TRXCON_PHYIF_CMDT_MEASURE:
380 r.type = trxcon_phyif_cmd_type::TRXCON_PHYIF_CMDT_MEASURE;
Ericb7253c62022-11-28 19:21:08 +0100381 r.param.measure.band_arfcn = cmd.param.measure.band_arfcn;
382 // FIXME: do we want to measure anything, considering the transceiver just syncs by.. syncing?
383 r.param.measure.dbm = -80;
Eric135d64b2023-04-21 13:59:56 +0200384 tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
385 tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
386 cmdq_from_phy.spsc_push(&r);
Ericb7253c62022-11-28 19:21:08 +0100387 break;
Eric135d64b2023-04-21 13:59:56 +0200388 case TRXCON_PHYIF_CMDT_SETFREQ_H0:
389 tuneRx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 0) * 1000 * 100);
390 tuneTx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 1) * 1000 * 100);
Ericb7253c62022-11-28 19:21:08 +0100391 break;
Eric135d64b2023-04-21 13:59:56 +0200392 case TRXCON_PHYIF_CMDT_SETFREQ_H1:
Ericb7253c62022-11-28 19:21:08 +0100393 break;
Eric135d64b2023-04-21 13:59:56 +0200394 case TRXCON_PHYIF_CMDT_SETSLOT:
Ericb7253c62022-11-28 19:21:08 +0100395 break;
Eric135d64b2023-04-21 13:59:56 +0200396 case TRXCON_PHYIF_CMDT_SETTA:
Ericb7253c62022-11-28 19:21:08 +0100397 set_ta(cmd.param.setta.ta);
398 break;
399 }
400 return false;
401}
402
Ericb7253c62022-11-28 19:21:08 +0100403void sighandler(int sigset)
404{
405 // we might get a sigpipe in case the l1ctl ud socket disconnects because mobile quits
Ericb3157b92023-05-23 11:32:34 +0200406 if (sigset == SIGPIPE || sigset == SIGINT) {
Ericb7253c62022-11-28 19:21:08 +0100407 g_exit_flag = true;
408
409 // we know the flag is atomic and it prevents the trxcon cb handlers from writing
410 // to the queues, so submit some trash to unblock the threads & exit
Eric135d64b2023-04-21 13:59:56 +0200411 trxcon_phyif_cmd cmd = {};
412 internal_q_tx_buf b = {};
413 txq.spsc_push(&b);
414 cmdq_to_phy.spsc_push(&cmd);
Ericb3157b92023-05-23 11:32:34 +0200415 msleep(200);
Ericb7253c62022-11-28 19:21:08 +0100416
417 return;
418 }
419}
420
421int main(int argc, char *argv[])
422{
423 auto tall_trxcon_ctx = talloc_init("trxcon context");
424 signal(SIGPIPE, sighandler);
Ericb3157b92023-05-23 11:32:34 +0200425 signal(SIGINT, sighandler);
Ericb7253c62022-11-28 19:21:08 +0100426
Eric135d64b2023-04-21 13:59:56 +0200427 msgb_talloc_ctx_init(tall_trxcon_ctx, 0);
Ericb7253c62022-11-28 19:21:08 +0100428 trxc_log_init(tall_trxcon_ctx);
429
Vadim Yanitskiy70ed3d52023-09-06 01:54:52 +0700430 /* Configure pretty logging */
431 log_set_print_extended_timestamp(osmo_stderr_target, 1);
432 log_set_print_category_hex(osmo_stderr_target, 0);
433 log_set_print_category(osmo_stderr_target, 1);
434 log_set_print_level(osmo_stderr_target, 1);
435
436 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
437 log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
438
439 osmo_fsm_log_timeouts(true);
440
Eric1499f032023-07-25 18:42:48 +0200441 g_trxcon = trxcon_inst_alloc(tall_trxcon_ctx, 0);
Eric135d64b2023-04-21 13:59:56 +0200442 g_trxcon->gsmtap = nullptr;
443 g_trxcon->phyif = nullptr;
444 g_trxcon->phy_quirks.fbsb_extend_fns = 866; // 4 seconds, known to work.
Ericb7253c62022-11-28 19:21:08 +0100445
446 convolve_init();
447 convert_init();
448 sigProcLibSetup();
449 initvita();
450
451 int status = 0;
452 auto trx = new upper_trx();
453 trx->do_auto_gain = true;
454
455 status = trx->init_dev_and_streams();
Eric Wild10b4e312023-01-11 18:53:48 +0100456 if (status < 0) {
457 std::cerr << "Error initializing hardware, quitting.." << std::endl;
458 return -1;
459 }
Eric805e0d92023-05-23 11:29:18 +0200460 trx->set_name_aff_sched(sched_params::thread_names::MAIN);
Ericb7253c62022-11-28 19:21:08 +0100461
Eric135d64b2023-04-21 13:59:56 +0200462 if (!trxc_l1ctl_init(tall_trxcon_ctx)) {
Ericb7253c62022-11-28 19:21:08 +0100463 std::cerr << "Error initializing l1ctl, quitting.." << std::endl;
464 return -1;
465 }
466
Ericb3157b92023-05-23 11:32:34 +0200467 // blocking, will return when global exit is requested
Ericb7253c62022-11-28 19:21:08 +0100468 trx->start_threads();
Ericc3e515a2023-05-08 12:56:56 +0200469 trx->main_loop();
Ericb7253c62022-11-28 19:21:08 +0100470 trx->stop_threads();
Ericb3157b92023-05-23 11:32:34 +0200471 trx->stop_upper_threads();
Ericb7253c62022-11-28 19:21:08 +0100472
473 return status;
474}