206 lines
6.0 KiB
C++
206 lines
6.0 KiB
C++
/*
|
|
* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
|
* All Rights Reserved
|
|
*
|
|
* Author: Eric Wild <ewild@sysmocom.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#include "ms.h"
|
|
#include "sigProcLib.h"
|
|
#include "signalVector.h"
|
|
#include "grgsm_vitac/grgsm_vitac.h"
|
|
extern "C" {
|
|
#include "sch.h"
|
|
}
|
|
|
|
#if !defined(SYNCTHINGONLY) || !defined(NODAMNLOG)
|
|
#define DBGLG(...) ms_trx::dummy_log()
|
|
#else
|
|
#define DBGLG(...) std::cerr
|
|
#endif
|
|
|
|
#if !defined(SYNCTHINGONLY)
|
|
#define DBGLG2(...) ms_trx::dummy_log()
|
|
#else
|
|
#define DBGLG2(...) std::cerr
|
|
#endif
|
|
|
|
static bool decode_sch(float *bits, bool update_global_clock)
|
|
{
|
|
struct sch_info sch;
|
|
ubit_t info[GSM_SCH_INFO_LEN];
|
|
sbit_t data[GSM_SCH_CODED_LEN];
|
|
|
|
float_to_sbit(&bits[3], &data[0], 62, 39);
|
|
float_to_sbit(&bits[106], &data[39], 62, 39);
|
|
|
|
if (!gsm_sch_decode(info, data)) {
|
|
gsm_sch_parse(info, &sch);
|
|
|
|
DBGLG() << "SCH : Decoded values" << std::endl;
|
|
DBGLG() << " BSIC: " << sch.bsic << std::endl;
|
|
DBGLG() << " TSC: " << (sch.bsic & 0x7) << std::endl;
|
|
DBGLG() << " T1 : " << sch.t1 << std::endl;
|
|
DBGLG() << " T2 : " << sch.t2 << std::endl;
|
|
DBGLG() << " T3p : " << sch.t3p << std::endl;
|
|
DBGLG() << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void check_rcv_fn(GSM::Time t, bool first, unsigned int &lastfn, unsigned int &fnbm)
|
|
{
|
|
if (first && t.TN() == 0) {
|
|
lastfn = t.FN();
|
|
fnbm = 1 << 0;
|
|
first = false;
|
|
}
|
|
if (!first && t.FN() != (int)lastfn) {
|
|
if (fnbm != 255)
|
|
std::cerr << "rx " << lastfn << ":" << fnbm << " " << __builtin_popcount(fnbm) << std::endl;
|
|
lastfn = t.FN();
|
|
fnbm = 1 << t.TN();
|
|
}
|
|
|
|
fnbm |= 1 << t.TN();
|
|
}
|
|
|
|
static void handle_it(one_burst &e, signalVector &burst, unsigned int tsc, int scale)
|
|
{
|
|
std::fill(burst.begin(), burst.begin() + burst.size(), 0.0);
|
|
const auto is_sch = gsm_sch_check_ts(e.gsmts.TN(), e.gsmts.FN());
|
|
const auto is_fcch = gsm_fcch_check_ts(e.gsmts.TN(), e.gsmts.FN());
|
|
|
|
if (is_fcch)
|
|
return;
|
|
|
|
if (is_sch) {
|
|
char outbin[148];
|
|
convert_and_scale(burst.begin(), e.burst, ONE_TS_BURST_LEN * 2, SAMPLE_SCALE_FACTOR);
|
|
std::stringstream dbgout;
|
|
#if 0
|
|
{
|
|
struct estim_burst_params ebp;
|
|
auto rv2 = detectSCHBurst(burst, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp);
|
|
auto bits = demodAnyBurst(burst, SCH, 4, &ebp);
|
|
// clamp_array(bits->begin(), 148, 1.5f);
|
|
for (auto &i : *bits)
|
|
i = (i > 0 ? 1 : -1);
|
|
|
|
auto rv = decode_sch(bits->begin(), false);
|
|
dbgout << "U DET@" << (rv2 ? "yes " : " ") << "Timing offset " << ebp.toa
|
|
<< " symbols, DECODE: " << (rv ? "yes" : "---") << " ";
|
|
|
|
delete bits;
|
|
}
|
|
#endif
|
|
{
|
|
convert_and_scale(burst.begin(), burst.begin(), ONE_TS_BURST_LEN * 2, 1.f / float(scale));
|
|
|
|
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
|
auto ss = reinterpret_cast<std::complex<float> *>(burst.begin());
|
|
int d_c0_burst_start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
|
|
detect_burst(ss, &channel_imp_resp[0], d_c0_burst_start, outbin);
|
|
|
|
SoftVector bits;
|
|
bits.resize(148);
|
|
for (int i = 0; i < 148; i++) {
|
|
bits[i] = (!outbin[i]); // < 1 ? -1 : 1;
|
|
}
|
|
|
|
auto rv = decode_sch(bits.begin(), false);
|
|
dbgout << "U SCH@"
|
|
<< " " << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << d_c0_burst_start
|
|
<< " DECODE:" << (rv ? "yes" : "---") << std::endl;
|
|
}
|
|
|
|
DBGLG() << dbgout.str();
|
|
return;
|
|
}
|
|
#if 1
|
|
convert_and_scale(burst.begin(), e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(scale));
|
|
// std::cerr << "@" << tsc << " " << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << ebp.toa << " "
|
|
// << std::endl;
|
|
|
|
char outbin[148];
|
|
auto ss = reinterpret_cast<std::complex<float> *>(burst.begin());
|
|
float ncmax, dcmax;
|
|
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR], chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
|
|
auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, tsc);
|
|
auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
|
|
auto is_nb = ncmax > dcmax;
|
|
|
|
DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start << " o db: " << dummy_burst_start
|
|
<< std::endl;
|
|
|
|
if (is_nb)
|
|
detect_burst(ss, &chan_imp_resp[0], normal_burst_start, outbin);
|
|
else
|
|
detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
|
|
;
|
|
#ifdef DBGXX
|
|
// auto bits = SoftVector(148);
|
|
// for (int i = 0; i < 148; i++)
|
|
// (bits)[i] = outbin[i] < 1 ? -1 : 1;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void rcv_bursts_test(rx_queue_t *q, unsigned int *tsc, int scale)
|
|
{
|
|
static bool first = true;
|
|
unsigned int lastfn = 0;
|
|
unsigned int fnbm = 0;
|
|
signalVector burst(ONE_TS_BURST_LEN, 100, 100);
|
|
|
|
cpu_set_t cpuset;
|
|
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(1, &cpuset);
|
|
|
|
auto rv = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
|
|
if (rv < 0) {
|
|
std::cerr << "affinity: errreur! " << std::strerror(errno);
|
|
exit(0);
|
|
}
|
|
|
|
int prio = sched_get_priority_max(SCHED_RR);
|
|
struct sched_param param;
|
|
param.sched_priority = prio;
|
|
rv = sched_setscheduler(0, SCHED_RR, ¶m);
|
|
if (rv < 0) {
|
|
std::cerr << "scheduler: errreur! " << std::strerror(errno);
|
|
exit(0);
|
|
}
|
|
|
|
while (1) {
|
|
one_burst e;
|
|
while (!q->spsc_pop(&e)) {
|
|
q->spsc_prep_pop();
|
|
}
|
|
|
|
check_rcv_fn(e.gsmts, first, lastfn, fnbm);
|
|
|
|
handle_it(e, burst, *tsc, scale);
|
|
#ifdef DBGXX
|
|
rv = detectSCHBurst(*burst, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp);
|
|
if (rv > 0)
|
|
std::cerr << "#" << e.gsmts.FN() << ":" << e.gsmts.TN() << " " << ebp.toa << std::endl;
|
|
sched_yield();
|
|
#endif
|
|
}
|
|
} |