blob: f1a915c4da2e0215ea34e3719c1f8c926f588b0b [file] [log] [blame]
Ericb7253c62022-11-28 19:21:08 +01001
2/*
3 * (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Eric Wild <ewild@sysmocom.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22#include "GSMCommon.h"
23#include <atomic>
24#include <cassert>
Eric Wildea6cec52024-03-20 19:39:05 +010025
Ericb7253c62022-11-28 19:21:08 +010026#include <iostream>
27#include <cstdlib>
28#include <cstdio>
Ericb7253c62022-11-28 19:21:08 +010029
Ericb7253c62022-11-28 19:21:08 +010030#include "ms.h"
Ericb7253c62022-11-28 19:21:08 +010031
Eric989fe752023-10-06 16:06:13 +020032#include "threadsched.h"
33
Ericb7253c62022-11-28 19:21:08 +010034dummylog ms_trx::dummy_log;
35
36#ifdef DBGXX
37const int offsetrange = 200;
38const int offset_start = -15;
39static int offset_ctr = 0;
40#endif
41
Eric2e6c3622023-05-02 14:34:49 +020042template <>
Eric40978042023-05-23 10:59:58 +020043std::atomic<bool> ms_trx::base::stop_lower_threads_flag(false);
Ericb7253c62022-11-28 19:21:08 +010044
Ericb7253c62022-11-28 19:21:08 +010045int ms_trx::init_dev_and_streams()
46{
47 int status = 0;
Ericdf4520d2023-05-03 19:37:48 +020048 status = init_device(rx_bh(), tx_bh());
Ericb7253c62022-11-28 19:21:08 +010049 if (status < 0) {
50 std::cerr << "failed to init dev!" << std::endl;
51 return -1;
52 }
53 return status;
54}
55
56bh_fn_t ms_trx::rx_bh()
57{
58 return [this](dev_buf_t *rcd) -> int {
59 if (this->search_for_sch(rcd) == SCH_STATE::FOUND)
60 this->grab_bursts(rcd);
61 return 0;
62 };
63}
64
65bh_fn_t ms_trx::tx_bh()
66{
67 return [this](dev_buf_t *rcd) -> int {
68#pragma GCC diagnostic push
69#pragma GCC diagnostic ignored "-Wunused-variable"
70 auto y = this;
71#pragma GCC diagnostic pop
72 /* nothing to do here */
73 return 0;
74 };
75}
76
Ericc3e515a2023-05-08 12:56:56 +020077void ms_trx::start_lower_ms()
Ericb7253c62022-11-28 19:21:08 +010078{
Eric40978042023-05-23 10:59:58 +020079 if (stop_lower_threads_flag)
Ericb3157b92023-05-23 11:32:34 +020080 return;
Ericb7253c62022-11-28 19:21:08 +010081 auto fn = get_rx_burst_handler_fn(rx_bh());
Eric989fe752023-10-06 16:06:13 +020082 lower_rx_task = spawn_worker_thread(sched_params::thread_names::RXRUN, fn, this);
Ericb7253c62022-11-28 19:21:08 +010083
84 usleep(1000);
85 auto fn2 = get_tx_burst_handler_fn(tx_bh());
Eric989fe752023-10-06 16:06:13 +020086 lower_tx_task = spawn_worker_thread(sched_params::thread_names::TXRUN, fn2, this);
Eric805e0d92023-05-23 11:29:18 +020087
Ericb3157b92023-05-23 11:32:34 +020088 actually_enable_streams();
Ericb7253c62022-11-28 19:21:08 +010089}
90
91void ms_trx::set_upper_ready(bool is_ready)
92{
93 upper_is_ready = is_ready;
94}
95
96void ms_trx::stop_threads()
97{
Ericb3157b92023-05-23 11:32:34 +020098 std::cerr << "killing threads..." << std::endl;
Eric40978042023-05-23 10:59:58 +020099 stop_lower_threads_flag = true;
Ericb7253c62022-11-28 19:21:08 +0100100 close_device();
Ericb3157b92023-05-23 11:32:34 +0200101 std::cerr << "dev closed..." << std::endl;
Eric989fe752023-10-06 16:06:13 +0200102 pthread_join(lower_rx_task, nullptr);
Ericb3157b92023-05-23 11:32:34 +0200103 std::cerr << "L rx dead..." << std::endl;
Eric989fe752023-10-06 16:06:13 +0200104 pthread_join(lower_tx_task, nullptr);
Ericb3157b92023-05-23 11:32:34 +0200105 std::cerr << "L tx dead..." << std::endl;
Ericb7253c62022-11-28 19:21:08 +0100106}
107
108void ms_trx::submit_burst(blade_sample_type *buffer, int len, GSM::Time target)
109{
110 int64_t now_ts;
111 GSM::Time now_time;
112 target.incTN(3); // ul dl offset
113 int target_fn = target.FN();
114 int target_tn = target.TN();
115 timekeeper.get_both(&now_time, &now_ts);
116
117 auto diff_fn = GSM::FNDelta(target_fn, now_time.FN());
118 int diff_tn = (target_tn - (int)now_time.TN()) % 8;
119 auto tosend = GSM::Time(diff_fn, 0);
120
121 if (diff_tn > 0)
122 tosend.incTN(diff_tn);
123 else
124 tosend.decTN(-diff_tn);
125
126 // in theory fn equal and tn+3 equal is also a problem...
Eric0f4381d2023-09-20 15:19:13 +0200127 if (diff_fn < 0 || (diff_fn == 0 && (target_tn-now_time.TN() < 3))) {
Ericb7253c62022-11-28 19:21:08 +0100128 std::cerr << "## TX too late?! fn DIFF:" << diff_fn << " tn LOCAL: " << now_time.TN()
129 << " tn OTHER: " << target_tn << std::endl;
130 return;
131 }
132
Ericb7253c62022-11-28 19:21:08 +0100133 int64_t send_ts = now_ts + tosend.FN() * 8 * ONE_TS_BURST_LEN + tosend.TN() * ONE_TS_BURST_LEN - timing_advance;
134#ifdef DBGXX
Ericf57a8612023-07-24 20:44:06 +0200135 auto check = now_time + tosend;
Ericb7253c62022-11-28 19:21:08 +0100136 std::cerr << "## fn DIFF: " << diff_fn << " ## tn DIFF: " << diff_tn << " tn LOCAL/OTHER: " << now_time.TN()
137 << "/" << target_tn << " tndiff" << diff_tn << " tosend:" << tosend.FN() << ":" << tosend.TN()
138 << " check: " << check.FN() << ":" << check.TN() << " target: " << target.FN() << ":" << target.TN()
139 << " ts now: " << now_ts << " target ts:" << send_ts << std::endl;
140#endif
Ericf57a8612023-07-24 20:44:06 +0200141#if 0
142 auto check = now_time + tosend;
Ericb7253c62022-11-28 19:21:08 +0100143 unsigned int pad = 4 * 4;
144 blade_sample_type buf2[len + pad];
145 std::fill(buf2, buf2 + pad, 0);
146 memcpy(&buf2[pad], buffer, len * sizeof(blade_sample_type));
147
148 assert(target.FN() == check.FN());
149 assert(target.TN() == check.TN());
150 submit_burst_ts(buf2, len + pad, send_ts - pad);
151#else
152 submit_burst_ts(buffer, len, send_ts);
153#endif
154}