blob: 3527a8badce756e457011363358592bf5bd2b20a [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
Eric Wildd8a1dee2024-02-21 19:33:09 +010022#include "sigProcLib.h"
23#include "signalVector.h"
Ericb7253c62022-11-28 19:21:08 +010024#include <atomic>
25#include <cassert>
26#include <complex>
27#include <iostream>
28#include <future>
29
30#include "ms.h"
31#include "grgsm_vitac/grgsm_vitac.h"
32
Eric3e7f4b02023-05-23 12:50:25 +020033#include "threadpool.h"
34
Ericb7253c62022-11-28 19:21:08 +010035extern "C" {
36#include "sch.h"
37}
38
39#ifdef LOG
40#undef LOG
41#endif
42
Ericea7bd5f2023-05-02 15:21:45 +020043#if !defined(NODAMNLOG)
Ericb7253c62022-11-28 19:21:08 +010044#define DBGLG(...) ms_trx::dummy_log()
45#else
46#define DBGLG(...) std::cerr
47#endif
48
Ericea7bd5f2023-05-02 15:21:45 +020049#if !defined(NODAMNLOG)
Ericb7253c62022-11-28 19:21:08 +010050#define DBGLG2(...) ms_trx::dummy_log()
51#else
52#define DBGLG2(...) std::cerr
53#endif
54
55#define PRINT_Q_OVERFLOW
Eric Wild2f40abd2023-05-22 22:50:43 +020056
Eric Wild98a50b72024-03-20 19:39:05 +010057extern std::atomic<bool> g_exit_flag;
58
Eric Wild2f40abd2023-05-22 22:50:43 +020059bool ms_trx::decode_sch(char *bits, bool update_global_clock)
Ericb7253c62022-11-28 19:21:08 +010060{
61 int fn;
62 struct sch_info sch;
63 ubit_t info[GSM_SCH_INFO_LEN];
64 sbit_t data[GSM_SCH_CODED_LEN];
65
Eric Wild2f40abd2023-05-22 22:50:43 +020066 memcpy(&data[0], &bits[3], 39);
67 memcpy(&data[39], &bits[106], 39);
Ericb7253c62022-11-28 19:21:08 +010068
69 if (!gsm_sch_decode(info, data)) {
70 gsm_sch_parse(info, &sch);
71
72 if (update_global_clock) {
73 DBGLG() << "SCH : Decoded values" << std::endl;
74 DBGLG() << " BSIC: " << sch.bsic << std::endl;
75 DBGLG() << " TSC: " << (sch.bsic & 0x7) << std::endl;
76 DBGLG() << " T1 : " << sch.t1 << std::endl;
77 DBGLG() << " T2 : " << sch.t2 << std::endl;
78 DBGLG() << " T3p : " << sch.t3p << std::endl;
79 DBGLG() << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
80 }
81
82 fn = gsm_sch_to_fn(&sch);
83 if (fn < 0) { // how? wh?
84 DBGLG() << "SCH : Failed to convert FN " << std::endl;
85 return false;
86 }
87
88 if (update_global_clock) {
89 mBSIC = sch.bsic;
90 mTSC = sch.bsic & 0x7;
91 timekeeper.set(fn, 0);
92 // global_time_keeper.FN(fn);
93 // global_time_keeper.TN(0);
94 }
Ericb7253c62022-11-28 19:21:08 +010095
96 return true;
97 }
98 return false;
99}
100
101void ms_trx::maybe_update_gain(one_burst &brst)
102{
103 static_assert((sizeof(brst.burst) / sizeof(brst.burst[0])) == ONE_TS_BURST_LEN, "wtf, buffer size mismatch?");
104 const int avgburst_num = 8 * 20; // ~ 50*4.5ms = 90ms?
105 static_assert(avgburst_num * 577 > (50 * 1000), "can't update faster then blade wait time?");
106 const unsigned int rx_max_cutoff = (rxFullScale * 2) / 3;
107 static int gain_check = 0;
108 static float runmean = 0;
Eric6a3e4b32023-04-26 22:12:06 +0200109 float sum = normed_abs_sum(&brst.burst[0], ONE_TS_BURST_LEN);
Ericb7253c62022-11-28 19:21:08 +0100110 runmean = gain_check ? (runmean * (gain_check + 2) - 1 + sum) / (gain_check + 2) : sum;
111
112 if (gain_check == avgburst_num - 1) {
Eric Wild238891f2024-03-20 19:39:05 +0100113 DBGLG2() << "\x1B[32m #RXG \033[0m" << cfg.rxgain << " " << runmean << " " << sum << std::endl;
Ericb7253c62022-11-28 19:21:08 +0100114 auto gainoffset = runmean < (rxFullScale / 4 ? 4 : 2);
115 gainoffset = runmean < (rxFullScale / 2 ? 2 : 1);
Eric Wild238891f2024-03-20 19:39:05 +0100116 float newgain = runmean < rx_max_cutoff ? cfg.rxgain + gainoffset : cfg.rxgain - gainoffset;
Ericb7253c62022-11-28 19:21:08 +0100117 // FIXME: gian cutoff
Eric Wild238891f2024-03-20 19:39:05 +0100118 if (newgain != cfg.rxgain && newgain <= 60) {
Eric3e7f4b02023-05-23 12:50:25 +0200119 auto gain_fun = [this, newgain] { setRxGain(newgain); };
120 worker_thread.add_task(gain_fun);
121 }
122
Ericb7253c62022-11-28 19:21:08 +0100123 runmean = 0;
124 }
125 gain_check = (gain_check + 1) % avgburst_num;
126}
127
128static char sch_demod_bits[148];
129
130bool ms_trx::handle_sch_or_nb()
131{
132 one_burst brst;
133 const auto current_gsm_time = timekeeper.gsmtime();
134 const auto is_sch = gsm_sch_check_ts(current_gsm_time.TN(), current_gsm_time.FN());
135
136 //either pass burst to upper layer for demod, OR pass demodded SCH to upper layer so we don't waste time processing it twice
137 brst.gsmts = current_gsm_time;
138
139 if (!is_sch) {
140 memcpy(brst.burst, burst_copy_buffer, sizeof(blade_sample_type) * ONE_TS_BURST_LEN);
141 } else {
142 handle_sch(false);
143 memcpy(brst.sch_bits, sch_demod_bits, sizeof(sch_demod_bits));
144 }
Ericea7bd5f2023-05-02 15:21:45 +0200145
Eric Wild98a50b72024-03-20 19:39:05 +0100146 while (!g_exit_flag && upper_is_ready && !rxqueue.spsc_push(&brst))
Ericc3e515a2023-05-08 12:56:56 +0200147 ;
Ericb7253c62022-11-28 19:21:08 +0100148
Eric Wild238891f2024-03-20 19:39:05 +0100149 if (!use_agc)
Ericb7253c62022-11-28 19:21:08 +0100150 maybe_update_gain(brst);
151
152 return false;
153}
154
155static float sch_acq_buffer[SCH_LEN_SPS * 2];
156
157bool ms_trx::handle_sch(bool is_first_sch_acq)
158{
159 auto current_gsm_time = timekeeper.gsmtime();
160 const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
161 const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100162 memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
Eric Wild238891f2024-03-20 19:39:05 +0100163 if (use_va) {
164 const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
165 const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
166 std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
167 int start;
168 convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
169 if (is_first_sch_acq) {
170 float max_corr = 0;
171 start = get_sch_buffer_chan_imp_resp(ss, &channel_imp_resp[0], buf_len, &max_corr);
172 } else {
173 start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
174 start = start < 39 ? start : 39;
175 start = start > -39 ? start : -39;
176 }
177 detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
Ericb7253c62022-11-28 19:21:08 +0100178
Eric Wild238891f2024-03-20 19:39:05 +0100179 auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
180#if 0 // useful to debug offset shifts
Eric Wildd8a1dee2024-02-21 19:33:09 +0100181 auto burst = new signalVector(buf_len, 50);
182 const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
183 struct estim_burst_params ebp;
Ericb7253c62022-11-28 19:21:08 +0100184
Eric Wildd8a1dee2024-02-21 19:33:09 +0100185 // scale like uhd, +-2k -> +-32k
186 convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
187
188 auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
189
190 int howmuchdelay = ebp.toa * 4;
191 std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
192 std::cerr << "voffs: " << start << " " << sch_decode_success << std::endl;
193#endif
Eric Wild238891f2024-03-20 19:39:05 +0100194 if (sch_decode_success) {
195 const auto ts_offset_symb = 4;
196 if (is_first_sch_acq) {
197 // update ts to first sample in sch buffer, to allow delay calc for current ts
198 first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
199 } else if (abs(start) > 1) {
200 // continuous sch tracking, only update if off too much
201 temp_ts_corr_offset += -start;
202 std::cerr << "offs: " << start << " " << temp_ts_corr_offset << std::endl;
203 }
204
205 return true;
206 } else {
207 DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " "
208 << current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
Ericb7253c62022-11-28 19:21:08 +0100209 }
Ericb7253c62022-11-28 19:21:08 +0100210 } else {
Eric Wild238891f2024-03-20 19:39:05 +0100211 const auto ts_offset_symb = 4;
212 auto burst = new signalVector(buf_len, 50);
213 const auto corr_type =
214 is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
215 struct estim_burst_params ebp;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100216
Eric Wild238891f2024-03-20 19:39:05 +0100217 // scale like uhd, +-2k -> +-32k
218 convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
Eric Wildd8a1dee2024-02-21 19:33:09 +0100219
Eric Wild238891f2024-03-20 19:39:05 +0100220 auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
Eric Wildd8a1dee2024-02-21 19:33:09 +0100221
Eric Wild238891f2024-03-20 19:39:05 +0100222 int howmuchdelay = ebp.toa * 4;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100223
Eric Wild238891f2024-03-20 19:39:05 +0100224 if (!rv) {
Eric Wildd8a1dee2024-02-21 19:33:09 +0100225 delete burst;
Eric Wild238891f2024-03-20 19:39:05 +0100226 DBGLG() << "SCH : \x1B[31m detect fail \033[0m NOOOOOOOOOOOOOOOOOO toa:" << ebp.toa << " "
227 << current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100228 return false;
229 }
230
Eric Wild238891f2024-03-20 19:39:05 +0100231 SoftVector *bits;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100232 if (is_first_sch_acq) {
Eric Wild238891f2024-03-20 19:39:05 +0100233 // can't be legit with a buf size spanning _at least_ one SCH but delay that implies partial sch burst
234 if (howmuchdelay < 0 || (buf_len - howmuchdelay) < ONE_TS_BURST_LEN) {
235 delete burst;
236 return false;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100237 }
Eric Wild238891f2024-03-20 19:39:05 +0100238
239 struct estim_burst_params ebp2;
240 // auto sch_chunk = new signalVector(ONE_TS_BURST_LEN, 50);
241 // auto sch_chunk_start = sch_chunk->begin();
242 // memcpy(sch_chunk_start, sch_buf_f.data() + howmuchdelay, sizeof(std::complex<float>) * ONE_TS_BURST_LEN);
243
244 auto delay = delayVector(burst, NULL, -howmuchdelay);
245
246 scaleVector(*delay, (complex)1.0 / ebp.amp);
247
248 auto rv2 = detectSCHBurst(*delay, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp2);
249 DBGLG() << "FIRST SCH : " << (rv2 ? "yes " : " ") << "Timing offset " << ebp2.toa
250 << " symbols" << std::endl;
251
252 bits = demodAnyBurst(*delay, SCH, 4, &ebp2);
253 delete delay;
254 } else {
255 bits = demodAnyBurst(*burst, SCH, 4, &ebp);
Eric Wildd8a1dee2024-02-21 19:33:09 +0100256 }
257
Eric Wild238891f2024-03-20 19:39:05 +0100258 delete burst;
259
260 // clamp to +-1.5 because +-127 softbits scaled by 64 after -0.5 can be at most +-1.5
261 clamp_array(bits->begin(), 148, 1.5f);
262
263 float_to_sbit(&bits->begin()[0], (signed char *)&sch_demod_bits[0], 62, 148);
264 // float_to_sbit(&bits->begin()[106], &data[39], 62, 39);
265
266 if (decode_sch((char *)sch_demod_bits, is_first_sch_acq)) {
267 auto current_gsm_time_updated = timekeeper.gsmtime();
268 if (is_first_sch_acq) {
269 // update ts to first sample in sch buffer, to allow delay calc for current ts
270 first_sch_ts_start = first_sch_buf_rcv_ts + howmuchdelay - (ts_offset_symb * 4);
271 } else {
272 // continuous sch tracking, only update if off too much
273 auto diff = [](float x, float y) { return x > y ? x - y : y - x; };
274
275 auto d = diff(ebp.toa, ts_offset_symb);
276 if (abs(d) > 0.3) {
277 if (ebp.toa < ts_offset_symb)
278 ebp.toa = d;
279 else
280 ebp.toa = -d;
281 temp_ts_corr_offset += ebp.toa * 4;
282
283 DBGLG() << "offs: " << ebp.toa << " " << temp_ts_corr_offset << std::endl;
284 }
285 }
286
287 auto a = gsm_sch_check_fn(current_gsm_time_updated.FN() - 1);
288 auto b = gsm_sch_check_fn(current_gsm_time_updated.FN());
289 auto c = gsm_sch_check_fn(current_gsm_time_updated.FN() + 1);
290 DBGLG() << "L SCH : Timing offset " << rv << " " << ebp.toa << " " << a << b << c << "fn "
291 << current_gsm_time_updated.FN() << ":" << current_gsm_time_updated.TN() << std::endl;
292
293 delete bits;
294 return true;
295 } else {
296 DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << ebp.toa << " "
297 << current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
298 }
Eric Wildd8a1dee2024-02-21 19:33:09 +0100299
300 delete bits;
Eric Wildd8a1dee2024-02-21 19:33:09 +0100301 }
Ericb7253c62022-11-28 19:21:08 +0100302 return false;
303}
304
Eric3e7f4b02023-05-23 12:50:25 +0200305/*
306accumulates a full big buffer consisting of 8*12 timeslots, then:
307either
3081) adjusts gain if necessary and starts over
3092) searches and finds SCH and is done
310*/
Ericb7253c62022-11-28 19:21:08 +0100311SCH_STATE ms_trx::search_for_sch(dev_buf_t *rcd)
312{
313 static unsigned int sch_pos = 0;
Eric3e7f4b02023-05-23 12:50:25 +0200314 auto to_copy = SCH_LEN_SPS - sch_pos;
315
Ericb7253c62022-11-28 19:21:08 +0100316 if (sch_thread_done)
317 return SCH_STATE::FOUND;
318
319 if (rcv_done)
320 return SCH_STATE::SEARCHING;
321
Eric3e7f4b02023-05-23 12:50:25 +0200322 if (sch_pos == 0) // keep first ts for time delta calc
Ericb7253c62022-11-28 19:21:08 +0100323 first_sch_buf_rcv_ts = rcd->get_first_ts();
324
Eric3e7f4b02023-05-23 12:50:25 +0200325 if (to_copy) {
326 auto spsmax = rcd->actual_samples_per_buffer();
327 if (to_copy > (unsigned int)spsmax)
328 sch_pos += rcd->readall(first_sch_buf + sch_pos);
329 else
330 sch_pos += rcd->read_n(first_sch_buf + sch_pos, 0, to_copy);
331 } else { // (!to_copy)
Ericb7253c62022-11-28 19:21:08 +0100332 sch_pos = 0;
333 rcv_done = true;
Eric3e7f4b02023-05-23 12:50:25 +0200334 auto sch_search_fun = [this] {
Ericb7253c62022-11-28 19:21:08 +0100335 const auto target_val = rxFullScale / 8;
Eric6a3e4b32023-04-26 22:12:06 +0200336 float sum = normed_abs_sum(first_sch_buf, SCH_LEN_SPS);
Ericb7253c62022-11-28 19:21:08 +0100337
338 //FIXME: arbitrary value, gain cutoff
Eric Wild238891f2024-03-20 19:39:05 +0100339 if (sum > target_val || cfg.rxgain >= 60) // enough ?
Ericb7253c62022-11-28 19:21:08 +0100340 sch_thread_done = this->handle_sch(true);
341 else {
Eric Wild238891f2024-03-20 19:39:05 +0100342 std::cerr << "\x1B[32m #RXG \033[0m gain " << cfg.rxgain << " -> " << cfg.rxgain + 4
Ericb7253c62022-11-28 19:21:08 +0100343 << " sample avg:" << sum << " target: >=" << target_val << std::endl;
Eric Wild238891f2024-03-20 19:39:05 +0100344 setRxGain(cfg.rxgain + 4);
Ericb7253c62022-11-28 19:21:08 +0100345 }
346
347 if (!sch_thread_done)
348 rcv_done = false; // retry!
Eric3e7f4b02023-05-23 12:50:25 +0200349 };
350 worker_thread.add_task(sch_search_fun);
Ericb7253c62022-11-28 19:21:08 +0100351 }
Ericb7253c62022-11-28 19:21:08 +0100352 return SCH_STATE::SEARCHING;
353}
354
355void ms_trx::grab_bursts(dev_buf_t *rcd)
356{
357 // partial burst samples read from the last buffer
358 static int partial_rdofs = 0;
359 static bool first_call = true;
360 int to_skip = 0;
361
362 // round up to next burst by calculating the time between sch detection and now
363 if (first_call) {
364 const auto next_burst_start = rcd->get_first_ts() - first_sch_ts_start;
365 const auto fullts = next_burst_start / ONE_TS_BURST_LEN;
366 const auto fracts = next_burst_start % ONE_TS_BURST_LEN;
367 to_skip = ONE_TS_BURST_LEN - fracts;
368
369 for (unsigned int i = 0; i < fullts; i++)
370 timekeeper.inc_and_update(first_sch_ts_start + i * ONE_TS_BURST_LEN);
371
372 if (fracts)
373 timekeeper.inc_both();
374 // timekeeper.inc_and_update(first_sch_ts_start + 1 * ONE_TS_BURST_LEN);
375
376 timekeeper.dec_by_one(); // oops, off by one?
377
378 timekeeper.set(timekeeper.gsmtime(), rcd->get_first_ts() - ONE_TS_BURST_LEN + to_skip);
379
380 DBGLG() << "this ts: " << rcd->get_first_ts() << " diff full TN: " << fullts << " frac TN: " << fracts
381 << " GSM now: " << timekeeper.gsmtime().FN() << ":" << timekeeper.gsmtime().TN() << " is sch? "
382 << gsm_sch_check_fn(timekeeper.gsmtime().FN()) << std::endl;
383 first_call = false;
384 }
385
386 if (partial_rdofs) {
387 auto first_remaining = ONE_TS_BURST_LEN - partial_rdofs;
388 auto rd = rcd->read_n(burst_copy_buffer + partial_rdofs, 0, first_remaining);
389 if (rd != (int)first_remaining) {
390 partial_rdofs += rd;
391 return;
392 }
393
394 timekeeper.inc_and_update_safe(rcd->get_first_ts() - partial_rdofs);
395 handle_sch_or_nb();
396 to_skip = first_remaining;
397 }
398
399 // apply sample rate slippage compensation
400 to_skip -= temp_ts_corr_offset;
401
402 // FIXME: happens rarely, read_n start -1 blows up
403 // this is fine: will just be corrected one buffer later
404 if (to_skip < 0)
405 to_skip = 0;
406 else
407 temp_ts_corr_offset = 0;
408
409 const auto left_after_burst = rcd->actual_samples_per_buffer() - to_skip;
410
411 const int full = left_after_burst / ONE_TS_BURST_LEN;
412 const int frac = left_after_burst % ONE_TS_BURST_LEN;
413
414 for (int i = 0; i < full; i++) {
415 rcd->read_n(burst_copy_buffer, to_skip + i * ONE_TS_BURST_LEN, ONE_TS_BURST_LEN);
416 timekeeper.inc_and_update_safe(rcd->get_first_ts() + to_skip + i * ONE_TS_BURST_LEN);
417 handle_sch_or_nb();
418 }
419
420 if (frac)
421 rcd->read_n(burst_copy_buffer, to_skip + full * ONE_TS_BURST_LEN, frac);
422 partial_rdofs = frac;
423}