blob: 69fca5ebf0b3bc7d3556727db63186f07cda5dba [file] [log] [blame]
Erica0e1ed32022-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#include "ms.h"
22#include "sigProcLib.h"
23#include "signalVector.h"
24#include "grgsm_vitac/grgsm_vitac.h"
25extern "C" {
26#include "sch.h"
27}
28
29#if !defined(SYNCTHINGONLY) || !defined(NODAMNLOG)
30#define DBGLG(...) ms_trx::dummy_log()
31#else
32#define DBGLG(...) std::cerr
33#endif
34
35#if !defined(SYNCTHINGONLY)
36#define DBGLG2(...) ms_trx::dummy_log()
37#else
38#define DBGLG2(...) std::cerr
39#endif
40
41static bool decode_sch(float *bits, bool update_global_clock)
42{
43 struct sch_info sch;
44 ubit_t info[GSM_SCH_INFO_LEN];
45 sbit_t data[GSM_SCH_CODED_LEN];
46
47 float_to_sbit(&bits[3], &data[0], 62, 39);
48 float_to_sbit(&bits[106], &data[39], 62, 39);
49
50 if (!gsm_sch_decode(info, data)) {
51 gsm_sch_parse(info, &sch);
52
53 DBGLG() << "SCH : Decoded values" << std::endl;
54 DBGLG() << " BSIC: " << sch.bsic << std::endl;
55 DBGLG() << " TSC: " << (sch.bsic & 0x7) << std::endl;
56 DBGLG() << " T1 : " << sch.t1 << std::endl;
57 DBGLG() << " T2 : " << sch.t2 << std::endl;
58 DBGLG() << " T3p : " << sch.t3p << std::endl;
59 DBGLG() << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
60 return true;
61 }
62 return false;
63}
64
65static void check_rcv_fn(GSM::Time t, bool first, unsigned int &lastfn, unsigned int &fnbm)
66{
67 if (first && t.TN() == 0) {
68 lastfn = t.FN();
69 fnbm = 1 << 0;
70 first = false;
71 }
72 if (!first && t.FN() != lastfn) {
73 if (fnbm != 255)
74 std::cerr << "rx " << lastfn << ":" << fnbm << " " << __builtin_popcount(fnbm) << std::endl;
75 lastfn = t.FN();
76 fnbm = 1 << t.TN();
77 }
78
79 fnbm |= 1 << t.TN();
80}
81
82static void handle_it(one_burst &e, signalVector &burst, unsigned int tsc, int scale)
83{
84 memset(burst.begin(), 0, burst.size() * sizeof(std::complex<float>));
85 const auto is_sch = gsm_sch_check_ts(e.gsmts.TN(), e.gsmts.FN());
86 const auto is_fcch = gsm_fcch_check_ts(e.gsmts.TN(), e.gsmts.FN());
87
88 if (is_fcch)
89 return;
90
91 if (is_sch) {
92 char outbin[148];
93 convert_and_scale_default<float, int16_t>(burst.begin(), e.burst, ONE_TS_BURST_LEN * 2);
94 std::stringstream dbgout;
95#if 0
96 {
97 struct estim_burst_params ebp;
98 auto rv2 = detectSCHBurst(burst, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp);
99 auto bits = demodAnyBurst(burst, SCH, 4, &ebp);
100 // clamp_array(bits->begin(), 148, 1.5f);
101 for (auto &i : *bits)
102 i = (i > 0 ? 1 : -1);
103
104 auto rv = decode_sch(bits->begin(), false);
105 dbgout << "U DET@" << (rv2 ? "yes " : " ") << "Timing offset " << ebp.toa
106 << " symbols, DECODE: " << (rv ? "yes" : "---") << " ";
107
108 delete bits;
109 }
110#endif
111 {
112 convert_and_scale<float, float>(burst.begin(), burst.begin(), ONE_TS_BURST_LEN * 2,
113 1.f / float(scale));
114
115 std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
116 auto ss = reinterpret_cast<std::complex<float> *>(burst.begin());
117 int d_c0_burst_start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
118 detect_burst(ss, &channel_imp_resp[0], d_c0_burst_start, outbin);
119
120 SoftVector bits;
121 bits.resize(148);
122 for (int i = 0; i < 148; i++) {
123 bits[i] = (!outbin[i]); // < 1 ? -1 : 1;
124 }
125
126 auto rv = decode_sch(bits.begin(), false);
127 dbgout << "U SCH@"
128 << " " << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << d_c0_burst_start
129 << " DECODE:" << (rv ? "yes" : "---") << std::endl;
130 }
131
132 DBGLG() << dbgout.str();
133 return;
134 }
135#if 1
136 convert_and_scale<float, int16_t>(burst.begin(), e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(scale));
137 // std::cerr << "@" << tsc << " " << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << ebp.toa << " "
138 // << std::endl;
139
140 char outbin[148];
141 auto ss = reinterpret_cast<std::complex<float> *>(burst.begin());
142 float ncmax, dcmax;
143 std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR], chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
144 auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, tsc);
145 auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
146 auto is_nb = ncmax > dcmax;
147
148 DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start << " o db: " << dummy_burst_start
149 << std::endl;
150
151 if (is_nb)
152 detect_burst(ss, &chan_imp_resp[0], normal_burst_start, outbin);
153 else
154 detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
155 ;
156#ifdef DBGXX
157 // auto bits = SoftVector(148);
158 // for (int i = 0; i < 148; i++)
159 // (bits)[i] = outbin[i] < 1 ? -1 : 1;
160#endif
161#endif
162}
163
164void rcv_bursts_test(rx_queue_t *q, unsigned int *tsc, int scale)
165{
166 static bool first = true;
167 unsigned int lastfn = 0;
168 unsigned int fnbm = 0;
169 signalVector burst(ONE_TS_BURST_LEN, 100, 100);
170
171 cpu_set_t cpuset;
172
173 CPU_ZERO(&cpuset);
174 CPU_SET(1, &cpuset);
175
176 auto rv = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
177 if (rv < 0) {
178 std::cerr << "affinity: errreur! " << std::strerror(errno);
179 exit(0);
180 }
181
182 int prio = sched_get_priority_max(SCHED_RR);
183 struct sched_param param;
184 param.sched_priority = prio;
185 rv = sched_setscheduler(0, SCHED_RR, &param);
186 if (rv < 0) {
187 std::cerr << "scheduler: errreur! " << std::strerror(errno);
188 exit(0);
189 }
190
191 while (1) {
192 one_burst e;
193 while (!q->spsc_pop(&e)) {
194 q->spsc_prep_pop();
195 }
196
197 check_rcv_fn(e.gsmts, first, lastfn, fnbm);
198
199 handle_it(e, burst, *tsc, scale);
200#ifdef DBGXX
201 rv = detectSCHBurst(*burst, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp);
202 if (rv > 0)
203 std::cerr << "#" << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << ebp.toa << std::endl;
204 sched_yield();
205#endif
206 }
207}