blob: e8d8e0e8b7b9d55598f810afc728b496b33da17e [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
22#include "sigProcLib.h"
23#include "signalVector.h"
24#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
33extern "C" {
34#include "sch.h"
35}
36
37#ifdef LOG
38#undef LOG
39#endif
40
41#if !defined(SYNCTHINGONLY) //|| !defined(NODAMNLOG)
42#define DBGLG(...) ms_trx::dummy_log()
43#else
44#define DBGLG(...) std::cerr
45#endif
46
47#if !defined(SYNCTHINGONLY) || !defined(NODAMNLOG)
48#define DBGLG2(...) ms_trx::dummy_log()
49#else
50#define DBGLG2(...) std::cerr
51#endif
52
53#define PRINT_Q_OVERFLOW
54bool ms_trx::decode_sch(float *bits, bool update_global_clock)
55{
56 int fn;
57 struct sch_info sch;
58 ubit_t info[GSM_SCH_INFO_LEN];
59 sbit_t data[GSM_SCH_CODED_LEN];
60
61 float_to_sbit(&bits[3], &data[0], 1, 39);
62 float_to_sbit(&bits[106], &data[39], 1, 39);
63
64 if (!gsm_sch_decode(info, data)) {
65 gsm_sch_parse(info, &sch);
66
67 if (update_global_clock) {
68 DBGLG() << "SCH : Decoded values" << std::endl;
69 DBGLG() << " BSIC: " << sch.bsic << std::endl;
70 DBGLG() << " TSC: " << (sch.bsic & 0x7) << std::endl;
71 DBGLG() << " T1 : " << sch.t1 << std::endl;
72 DBGLG() << " T2 : " << sch.t2 << std::endl;
73 DBGLG() << " T3p : " << sch.t3p << std::endl;
74 DBGLG() << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
75 }
76
77 fn = gsm_sch_to_fn(&sch);
78 if (fn < 0) { // how? wh?
79 DBGLG() << "SCH : Failed to convert FN " << std::endl;
80 return false;
81 }
82
83 if (update_global_clock) {
84 mBSIC = sch.bsic;
85 mTSC = sch.bsic & 0x7;
86 timekeeper.set(fn, 0);
87 // global_time_keeper.FN(fn);
88 // global_time_keeper.TN(0);
89 }
90#ifdef SYNCTHINGONLY
91 else {
92 int t3 = sch.t3p * 10 + 1;
93 if (t3 == 11) {
94 // timeslot hitter attempt @ fn 21 in mf
95 DBGLG2() << "sch @ " << t3 << std::endl;
96 auto e = GSM::Time(fn, 0);
97 e += 10;
98 ts_hitter_q.spsc_push(&e);
99 }
100 }
101#endif
102
103 return true;
104 }
105 return false;
106}
107
108void ms_trx::maybe_update_gain(one_burst &brst)
109{
110 static_assert((sizeof(brst.burst) / sizeof(brst.burst[0])) == ONE_TS_BURST_LEN, "wtf, buffer size mismatch?");
111 const int avgburst_num = 8 * 20; // ~ 50*4.5ms = 90ms?
112 static_assert(avgburst_num * 577 > (50 * 1000), "can't update faster then blade wait time?");
113 const unsigned int rx_max_cutoff = (rxFullScale * 2) / 3;
114 static int gain_check = 0;
115 static float runmean = 0;
116 float sum = 0;
117 for (auto i : brst.burst)
118 sum += abs(i.real()) + abs(i.imag());
119 sum /= ONE_TS_BURST_LEN * 2;
120
121 runmean = gain_check ? (runmean * (gain_check + 2) - 1 + sum) / (gain_check + 2) : sum;
122
123 if (gain_check == avgburst_num - 1) {
124 DBGLG2() << "\x1B[32m #RXG \033[0m" << rxgain << " " << runmean << " " << sum << std::endl;
125 auto gainoffset = runmean < (rxFullScale / 4 ? 4 : 2);
126 gainoffset = runmean < (rxFullScale / 2 ? 2 : 1);
127 float newgain = runmean < rx_max_cutoff ? rxgain + gainoffset : rxgain - gainoffset;
128 // FIXME: gian cutoff
129 if (newgain != rxgain && newgain <= 60)
130 std::thread([this, newgain] { setRxGain(newgain); }).detach();
131 runmean = 0;
132 }
133 gain_check = (gain_check + 1) % avgburst_num;
134}
135
136static char sch_demod_bits[148];
137
138bool ms_trx::handle_sch_or_nb()
139{
140 one_burst brst;
141 const auto current_gsm_time = timekeeper.gsmtime();
142 const auto is_sch = gsm_sch_check_ts(current_gsm_time.TN(), current_gsm_time.FN());
143
144 //either pass burst to upper layer for demod, OR pass demodded SCH to upper layer so we don't waste time processing it twice
145 brst.gsmts = current_gsm_time;
146
147 if (!is_sch) {
148 memcpy(brst.burst, burst_copy_buffer, sizeof(blade_sample_type) * ONE_TS_BURST_LEN);
149 } else {
150 handle_sch(false);
151 memcpy(brst.sch_bits, sch_demod_bits, sizeof(sch_demod_bits));
152 }
153#ifndef SYNCTHINGONLY
154 if (upper_is_ready) { // this is blocking, so only submit if there is a reader - only if upper exists!
155#endif
156 while (!rxqueue.spsc_push(&brst))
157 ;
158#ifndef SYNCTHINGONLY
159 }
160#endif
161
162 if (do_auto_gain)
163 maybe_update_gain(brst);
164
165 return false;
166}
167
168static float sch_acq_buffer[SCH_LEN_SPS * 2];
169
170bool ms_trx::handle_sch(bool is_first_sch_acq)
171{
172 auto current_gsm_time = timekeeper.gsmtime();
173 const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
174 const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
175 const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
176 const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
177 std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
178
179 int start;
180 memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
181 if (is_first_sch_acq) {
182 float max_corr = 0;
Eric Wild621a49e2023-01-12 16:21:58 +0100183 convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
Ericb7253c62022-11-28 19:21:08 +0100184 start = get_sch_buffer_chan_imp_resp(ss, &channel_imp_resp[0], buf_len, &max_corr);
185 detect_burst(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
186 } else {
Eric Wild621a49e2023-01-12 16:21:58 +0100187 convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
Ericb7253c62022-11-28 19:21:08 +0100188 start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
189 start = start < 39 ? start : 39;
190 start = start > -39 ? start : -39;
191 detect_burst(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
192 }
193
194 SoftVector bitss(148);
195 for (int i = 0; i < 148; i++) {
196 bitss[i] = (sch_demod_bits[i]);
197 }
198
199 auto sch_decode_success = decode_sch(bitss.begin(), is_first_sch_acq);
200
201 if (sch_decode_success) {
202 const auto ts_offset_symb = 0;
203 if (is_first_sch_acq) {
204 // update ts to first sample in sch buffer, to allow delay calc for current ts
205 first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
206 } else if (abs(start) > 1) {
207 // continuous sch tracking, only update if off too much
208 temp_ts_corr_offset += -start;
209 std::cerr << "offs: " << start << " " << temp_ts_corr_offset << std::endl;
210 }
211
212 return true;
213 } else {
214 DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
215 << ":" << current_gsm_time.TN() << std::endl;
216 }
217 return false;
218}
219
220SCH_STATE ms_trx::search_for_sch(dev_buf_t *rcd)
221{
222 static unsigned int sch_pos = 0;
223 if (sch_thread_done)
224 return SCH_STATE::FOUND;
225
226 if (rcv_done)
227 return SCH_STATE::SEARCHING;
228
229 auto to_copy = SCH_LEN_SPS - sch_pos;
230
231 if (SCH_LEN_SPS == to_copy) // first time
232 first_sch_buf_rcv_ts = rcd->get_first_ts();
233
234 if (!to_copy) {
235 sch_pos = 0;
236 rcv_done = true;
237 std::thread([this] {
Eric805e0d92023-05-23 11:29:18 +0200238 set_name_aff_sched(sched_params::thread_names::SCH_SEARCH);
Ericb7253c62022-11-28 19:21:08 +0100239
240 auto ptr = reinterpret_cast<const int16_t *>(first_sch_buf);
241 const auto target_val = rxFullScale / 8;
242 float sum = 0;
243 for (unsigned int i = 0; i < SCH_LEN_SPS * 2; i++)
244 sum += std::abs(ptr[i]);
245 sum /= SCH_LEN_SPS * 2;
246
247 //FIXME: arbitrary value, gain cutoff
248 if (sum > target_val || rxgain >= 60) // enough ?
249 sch_thread_done = this->handle_sch(true);
250 else {
251 std::cerr << "\x1B[32m #RXG \033[0m gain " << rxgain << " -> " << rxgain + 4
252 << " sample avg:" << sum << " target: >=" << target_val << std::endl;
253 setRxGain(rxgain + 4);
254 }
255
256 if (!sch_thread_done)
257 rcv_done = false; // retry!
258 return (bool)sch_thread_done;
259 }).detach();
260 }
261
262 auto spsmax = rcd->actual_samples_per_buffer();
263 if (to_copy > (unsigned int)spsmax)
264 sch_pos += rcd->readall(first_sch_buf + sch_pos);
265 else
266 sch_pos += rcd->read_n(first_sch_buf + sch_pos, 0, to_copy);
267
268 return SCH_STATE::SEARCHING;
269}
270
271void ms_trx::grab_bursts(dev_buf_t *rcd)
272{
273 // partial burst samples read from the last buffer
274 static int partial_rdofs = 0;
275 static bool first_call = true;
276 int to_skip = 0;
277
278 // round up to next burst by calculating the time between sch detection and now
279 if (first_call) {
280 const auto next_burst_start = rcd->get_first_ts() - first_sch_ts_start;
281 const auto fullts = next_burst_start / ONE_TS_BURST_LEN;
282 const auto fracts = next_burst_start % ONE_TS_BURST_LEN;
283 to_skip = ONE_TS_BURST_LEN - fracts;
284
285 for (unsigned int i = 0; i < fullts; i++)
286 timekeeper.inc_and_update(first_sch_ts_start + i * ONE_TS_BURST_LEN);
287
288 if (fracts)
289 timekeeper.inc_both();
290 // timekeeper.inc_and_update(first_sch_ts_start + 1 * ONE_TS_BURST_LEN);
291
292 timekeeper.dec_by_one(); // oops, off by one?
293
294 timekeeper.set(timekeeper.gsmtime(), rcd->get_first_ts() - ONE_TS_BURST_LEN + to_skip);
295
296 DBGLG() << "this ts: " << rcd->get_first_ts() << " diff full TN: " << fullts << " frac TN: " << fracts
297 << " GSM now: " << timekeeper.gsmtime().FN() << ":" << timekeeper.gsmtime().TN() << " is sch? "
298 << gsm_sch_check_fn(timekeeper.gsmtime().FN()) << std::endl;
299 first_call = false;
300 }
301
302 if (partial_rdofs) {
303 auto first_remaining = ONE_TS_BURST_LEN - partial_rdofs;
304 auto rd = rcd->read_n(burst_copy_buffer + partial_rdofs, 0, first_remaining);
305 if (rd != (int)first_remaining) {
306 partial_rdofs += rd;
307 return;
308 }
309
310 timekeeper.inc_and_update_safe(rcd->get_first_ts() - partial_rdofs);
311 handle_sch_or_nb();
312 to_skip = first_remaining;
313 }
314
315 // apply sample rate slippage compensation
316 to_skip -= temp_ts_corr_offset;
317
318 // FIXME: happens rarely, read_n start -1 blows up
319 // this is fine: will just be corrected one buffer later
320 if (to_skip < 0)
321 to_skip = 0;
322 else
323 temp_ts_corr_offset = 0;
324
325 const auto left_after_burst = rcd->actual_samples_per_buffer() - to_skip;
326
327 const int full = left_after_burst / ONE_TS_BURST_LEN;
328 const int frac = left_after_burst % ONE_TS_BURST_LEN;
329
330 for (int i = 0; i < full; i++) {
331 rcd->read_n(burst_copy_buffer, to_skip + i * ONE_TS_BURST_LEN, ONE_TS_BURST_LEN);
332 timekeeper.inc_and_update_safe(rcd->get_first_ts() + to_skip + i * ONE_TS_BURST_LEN);
333 handle_sch_or_nb();
334 }
335
336 if (frac)
337 rcd->read_n(burst_copy_buffer, to_skip + full * ONE_TS_BURST_LEN, frac);
338 partial_rdofs = frac;
339}