blob: c2adda32a733386b8b1a52610480b832554d6735 [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
Ericb7253c62022-11-28 19:21:08 +010022#include <atomic>
23#include <cassert>
24#include <complex>
25#include <iostream>
26#include <future>
27
28#include "ms.h"
29#include "grgsm_vitac/grgsm_vitac.h"
30
Eric3e7f4b02023-05-23 12:50:25 +020031#include "threadpool.h"
32
Ericb7253c62022-11-28 19:21:08 +010033extern "C" {
34#include "sch.h"
35}
36
37#ifdef LOG
38#undef LOG
39#endif
40
Ericea7bd5f2023-05-02 15:21:45 +020041#if !defined(NODAMNLOG)
Ericb7253c62022-11-28 19:21:08 +010042#define DBGLG(...) ms_trx::dummy_log()
43#else
44#define DBGLG(...) std::cerr
45#endif
46
Ericea7bd5f2023-05-02 15:21:45 +020047#if !defined(NODAMNLOG)
Ericb7253c62022-11-28 19:21:08 +010048#define DBGLG2(...) ms_trx::dummy_log()
49#else
50#define DBGLG2(...) std::cerr
51#endif
52
53#define PRINT_Q_OVERFLOW
Eric Wild2f40abd2023-05-22 22:50:43 +020054
55bool ms_trx::decode_sch(char *bits, bool update_global_clock)
Ericb7253c62022-11-28 19:21:08 +010056{
57 int fn;
58 struct sch_info sch;
59 ubit_t info[GSM_SCH_INFO_LEN];
60 sbit_t data[GSM_SCH_CODED_LEN];
61
Eric Wild2f40abd2023-05-22 22:50:43 +020062 memcpy(&data[0], &bits[3], 39);
63 memcpy(&data[39], &bits[106], 39);
Ericb7253c62022-11-28 19:21:08 +010064
65 if (!gsm_sch_decode(info, data)) {
66 gsm_sch_parse(info, &sch);
67
68 if (update_global_clock) {
69 DBGLG() << "SCH : Decoded values" << std::endl;
70 DBGLG() << " BSIC: " << sch.bsic << std::endl;
71 DBGLG() << " TSC: " << (sch.bsic & 0x7) << std::endl;
72 DBGLG() << " T1 : " << sch.t1 << std::endl;
73 DBGLG() << " T2 : " << sch.t2 << std::endl;
74 DBGLG() << " T3p : " << sch.t3p << std::endl;
75 DBGLG() << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
76 }
77
78 fn = gsm_sch_to_fn(&sch);
79 if (fn < 0) { // how? wh?
80 DBGLG() << "SCH : Failed to convert FN " << std::endl;
81 return false;
82 }
83
84 if (update_global_clock) {
85 mBSIC = sch.bsic;
86 mTSC = sch.bsic & 0x7;
87 timekeeper.set(fn, 0);
88 // global_time_keeper.FN(fn);
89 // global_time_keeper.TN(0);
90 }
Ericb7253c62022-11-28 19:21:08 +010091
92 return true;
93 }
94 return false;
95}
96
97void ms_trx::maybe_update_gain(one_burst &brst)
98{
99 static_assert((sizeof(brst.burst) / sizeof(brst.burst[0])) == ONE_TS_BURST_LEN, "wtf, buffer size mismatch?");
100 const int avgburst_num = 8 * 20; // ~ 50*4.5ms = 90ms?
101 static_assert(avgburst_num * 577 > (50 * 1000), "can't update faster then blade wait time?");
102 const unsigned int rx_max_cutoff = (rxFullScale * 2) / 3;
103 static int gain_check = 0;
104 static float runmean = 0;
Eric6a3e4b32023-04-26 22:12:06 +0200105 float sum = normed_abs_sum(&brst.burst[0], ONE_TS_BURST_LEN);
Ericb7253c62022-11-28 19:21:08 +0100106 runmean = gain_check ? (runmean * (gain_check + 2) - 1 + sum) / (gain_check + 2) : sum;
107
108 if (gain_check == avgburst_num - 1) {
109 DBGLG2() << "\x1B[32m #RXG \033[0m" << rxgain << " " << runmean << " " << sum << std::endl;
110 auto gainoffset = runmean < (rxFullScale / 4 ? 4 : 2);
111 gainoffset = runmean < (rxFullScale / 2 ? 2 : 1);
112 float newgain = runmean < rx_max_cutoff ? rxgain + gainoffset : rxgain - gainoffset;
113 // FIXME: gian cutoff
Eric3e7f4b02023-05-23 12:50:25 +0200114 if (newgain != rxgain && newgain <= 60) {
115 auto gain_fun = [this, newgain] { setRxGain(newgain); };
116 worker_thread.add_task(gain_fun);
117 }
118
Ericb7253c62022-11-28 19:21:08 +0100119 runmean = 0;
120 }
121 gain_check = (gain_check + 1) % avgburst_num;
122}
123
124static char sch_demod_bits[148];
125
126bool ms_trx::handle_sch_or_nb()
127{
128 one_burst brst;
129 const auto current_gsm_time = timekeeper.gsmtime();
130 const auto is_sch = gsm_sch_check_ts(current_gsm_time.TN(), current_gsm_time.FN());
131
132 //either pass burst to upper layer for demod, OR pass demodded SCH to upper layer so we don't waste time processing it twice
133 brst.gsmts = current_gsm_time;
134
135 if (!is_sch) {
136 memcpy(brst.burst, burst_copy_buffer, sizeof(blade_sample_type) * ONE_TS_BURST_LEN);
137 } else {
138 handle_sch(false);
139 memcpy(brst.sch_bits, sch_demod_bits, sizeof(sch_demod_bits));
140 }
Ericea7bd5f2023-05-02 15:21:45 +0200141
Ericc3e515a2023-05-08 12:56:56 +0200142 while (upper_is_ready && !rxqueue.spsc_push(&brst))
143 ;
Ericb7253c62022-11-28 19:21:08 +0100144
145 if (do_auto_gain)
146 maybe_update_gain(brst);
147
148 return false;
149}
150
151static float sch_acq_buffer[SCH_LEN_SPS * 2];
152
153bool ms_trx::handle_sch(bool is_first_sch_acq)
154{
155 auto current_gsm_time = timekeeper.gsmtime();
156 const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
157 const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
158 const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
159 const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
160 std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
161
162 int start;
163 memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
Ericbcaafca2023-04-26 13:57:26 +0200164 convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
Ericb7253c62022-11-28 19:21:08 +0100165 if (is_first_sch_acq) {
166 float max_corr = 0;
Ericb7253c62022-11-28 19:21:08 +0100167 start = get_sch_buffer_chan_imp_resp(ss, &channel_imp_resp[0], buf_len, &max_corr);
Ericb7253c62022-11-28 19:21:08 +0100168 } else {
Ericb7253c62022-11-28 19:21:08 +0100169 start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
170 start = start < 39 ? start : 39;
171 start = start > -39 ? start : -39;
Ericb7253c62022-11-28 19:21:08 +0100172 }
Erica5a22752023-01-09 22:46:41 +0100173 detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
Ericb7253c62022-11-28 19:21:08 +0100174
Eric Wild2f40abd2023-05-22 22:50:43 +0200175 auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
Ericb7253c62022-11-28 19:21:08 +0100176
177 if (sch_decode_success) {
178 const auto ts_offset_symb = 0;
179 if (is_first_sch_acq) {
180 // update ts to first sample in sch buffer, to allow delay calc for current ts
181 first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
182 } else if (abs(start) > 1) {
183 // continuous sch tracking, only update if off too much
184 temp_ts_corr_offset += -start;
185 std::cerr << "offs: " << start << " " << temp_ts_corr_offset << std::endl;
186 }
187
188 return true;
189 } else {
190 DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
191 << ":" << current_gsm_time.TN() << std::endl;
192 }
193 return false;
194}
195
Eric3e7f4b02023-05-23 12:50:25 +0200196/*
197accumulates a full big buffer consisting of 8*12 timeslots, then:
198either
1991) adjusts gain if necessary and starts over
2002) searches and finds SCH and is done
201*/
Ericb7253c62022-11-28 19:21:08 +0100202SCH_STATE ms_trx::search_for_sch(dev_buf_t *rcd)
203{
204 static unsigned int sch_pos = 0;
Eric3e7f4b02023-05-23 12:50:25 +0200205 auto to_copy = SCH_LEN_SPS - sch_pos;
206
Ericb7253c62022-11-28 19:21:08 +0100207 if (sch_thread_done)
208 return SCH_STATE::FOUND;
209
210 if (rcv_done)
211 return SCH_STATE::SEARCHING;
212
Eric3e7f4b02023-05-23 12:50:25 +0200213 if (sch_pos == 0) // keep first ts for time delta calc
Ericb7253c62022-11-28 19:21:08 +0100214 first_sch_buf_rcv_ts = rcd->get_first_ts();
215
Eric3e7f4b02023-05-23 12:50:25 +0200216 if (to_copy) {
217 auto spsmax = rcd->actual_samples_per_buffer();
218 if (to_copy > (unsigned int)spsmax)
219 sch_pos += rcd->readall(first_sch_buf + sch_pos);
220 else
221 sch_pos += rcd->read_n(first_sch_buf + sch_pos, 0, to_copy);
222 } else { // (!to_copy)
Ericb7253c62022-11-28 19:21:08 +0100223 sch_pos = 0;
224 rcv_done = true;
Eric3e7f4b02023-05-23 12:50:25 +0200225 auto sch_search_fun = [this] {
Ericb7253c62022-11-28 19:21:08 +0100226 const auto target_val = rxFullScale / 8;
Eric6a3e4b32023-04-26 22:12:06 +0200227 float sum = normed_abs_sum(first_sch_buf, SCH_LEN_SPS);
Ericb7253c62022-11-28 19:21:08 +0100228
229 //FIXME: arbitrary value, gain cutoff
230 if (sum > target_val || rxgain >= 60) // enough ?
231 sch_thread_done = this->handle_sch(true);
232 else {
233 std::cerr << "\x1B[32m #RXG \033[0m gain " << rxgain << " -> " << rxgain + 4
234 << " sample avg:" << sum << " target: >=" << target_val << std::endl;
235 setRxGain(rxgain + 4);
236 }
237
238 if (!sch_thread_done)
239 rcv_done = false; // retry!
Eric3e7f4b02023-05-23 12:50:25 +0200240 };
241 worker_thread.add_task(sch_search_fun);
Ericb7253c62022-11-28 19:21:08 +0100242 }
Ericb7253c62022-11-28 19:21:08 +0100243 return SCH_STATE::SEARCHING;
244}
245
246void ms_trx::grab_bursts(dev_buf_t *rcd)
247{
248 // partial burst samples read from the last buffer
249 static int partial_rdofs = 0;
250 static bool first_call = true;
251 int to_skip = 0;
252
253 // round up to next burst by calculating the time between sch detection and now
254 if (first_call) {
255 const auto next_burst_start = rcd->get_first_ts() - first_sch_ts_start;
256 const auto fullts = next_burst_start / ONE_TS_BURST_LEN;
257 const auto fracts = next_burst_start % ONE_TS_BURST_LEN;
258 to_skip = ONE_TS_BURST_LEN - fracts;
259
260 for (unsigned int i = 0; i < fullts; i++)
261 timekeeper.inc_and_update(first_sch_ts_start + i * ONE_TS_BURST_LEN);
262
263 if (fracts)
264 timekeeper.inc_both();
265 // timekeeper.inc_and_update(first_sch_ts_start + 1 * ONE_TS_BURST_LEN);
266
267 timekeeper.dec_by_one(); // oops, off by one?
268
269 timekeeper.set(timekeeper.gsmtime(), rcd->get_first_ts() - ONE_TS_BURST_LEN + to_skip);
270
271 DBGLG() << "this ts: " << rcd->get_first_ts() << " diff full TN: " << fullts << " frac TN: " << fracts
272 << " GSM now: " << timekeeper.gsmtime().FN() << ":" << timekeeper.gsmtime().TN() << " is sch? "
273 << gsm_sch_check_fn(timekeeper.gsmtime().FN()) << std::endl;
274 first_call = false;
275 }
276
277 if (partial_rdofs) {
278 auto first_remaining = ONE_TS_BURST_LEN - partial_rdofs;
279 auto rd = rcd->read_n(burst_copy_buffer + partial_rdofs, 0, first_remaining);
280 if (rd != (int)first_remaining) {
281 partial_rdofs += rd;
282 return;
283 }
284
285 timekeeper.inc_and_update_safe(rcd->get_first_ts() - partial_rdofs);
286 handle_sch_or_nb();
287 to_skip = first_remaining;
288 }
289
290 // apply sample rate slippage compensation
291 to_skip -= temp_ts_corr_offset;
292
293 // FIXME: happens rarely, read_n start -1 blows up
294 // this is fine: will just be corrected one buffer later
295 if (to_skip < 0)
296 to_skip = 0;
297 else
298 temp_ts_corr_offset = 0;
299
300 const auto left_after_burst = rcd->actual_samples_per_buffer() - to_skip;
301
302 const int full = left_after_burst / ONE_TS_BURST_LEN;
303 const int frac = left_after_burst % ONE_TS_BURST_LEN;
304
305 for (int i = 0; i < full; i++) {
306 rcd->read_n(burst_copy_buffer, to_skip + i * ONE_TS_BURST_LEN, ONE_TS_BURST_LEN);
307 timekeeper.inc_and_update_safe(rcd->get_first_ts() + to_skip + i * ONE_TS_BURST_LEN);
308 handle_sch_or_nb();
309 }
310
311 if (frac)
312 rcd->read_n(burst_copy_buffer, to_skip + full * ONE_TS_BURST_LEN, frac);
313 partial_rdofs = frac;
314}