Compare commits

..

2 Commits

Author SHA1 Message Date
Eric Wild
9269aaa9cb Bump version: 1.6.0 → 1.6.1
Change-Id: I345ba6569ae0765b3d33e4024d07fc5d925bdf80
2023-11-09 15:25:47 +01:00
Eric
f97c53bc9c devices: fix wrong gain to power mapping
The dev type was set too early, but the actual dev is only being
discovered during open, so update it. This broke the gain to power
mapping by defaulting to a wrong device.

Change-Id: I1dda6023ca6f15bc063c3dfbc704db2410ff7c98
2023-11-09 15:12:20 +01:00
38 changed files with 179 additions and 1275 deletions

View File

@@ -1,5 +1,4 @@
--exclude osmocom-bb/.*
--exclude .*h
--exclude Transceiver52M/grgsm_vitac/.*
--exclude utils/va-test/.*
--ignore FUNCTION_WITHOUT_ARGS

2
.gitignore vendored
View File

@@ -38,7 +38,6 @@ Transceiver52M/device/ipc/ipc-driver-test
.deps
.libs
.dirstamp
.version
*~
Makefile
config.log
@@ -84,7 +83,6 @@ contrib/osmo-trx.spec
!contrib/osmo-trx.spec.in
utils/osmo-prbs-tool
utils/va-test/osmo-burst-gen
/.qtc_clangd/*
/.cache/*
/.vscode/*

View File

@@ -55,15 +55,12 @@ const BitVector GSM::gEdgeTrainingSequence[] = {
};
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
const BitVector GSM::gDummyBurstTSC("01110001011100010111000101");
/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
const BitVector GSM::gRACHSynchSequenceTS0("01001011011111111001100110101010001111000"); /* GSM, GMSK (default) */
const BitVector GSM::gRACHSynchSequenceTS1("01010100111110001000011000101111001001101"); /* EGPRS, 8-PSK */
const BitVector GSM::gRACHSynchSequenceTS2("11101111001001110101011000001101101110111"); /* EGPRS, GMSK */
const BitVector GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011");
// |-head-||---------midamble----------------------||--------------data----------------||t|
const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");

View File

@@ -52,16 +52,11 @@ extern const BitVector gEdgeTrainingSequence[];
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
extern const BitVector gDummyBurst;
extern const BitVector gDummyBurstTSC;
/** Random access burst synch. sequence */
extern const BitVector gRACHSynchSequenceTS0;
extern const BitVector gRACHSynchSequenceTS1;
extern const BitVector gRACHSynchSequenceTS2;
/** Synchronization burst sync sequence */
extern const BitVector gSCHSynchSequence;
/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
extern const BitVector gRACHBurst;

View File

@@ -43,20 +43,12 @@ SUBDIRS += \
doc \
$(NULL)
BUILT_SOURCES = $(top_srcdir)/.version
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version
EXTRA_DIST = \
.version \
LEGAL \
COPYING \
README.md \
contrib/osmo-trx.spec.in \
debian \
git-version-gen \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \

View File

@@ -88,7 +88,6 @@ TRXCON_LDADD = \
MS_LOWER_SRC = \
ms/sch.c \
ms/ms.cpp \
ms/threadsched.cpp \
ms/ms_rx_lower.cpp \
grgsm_vitac/grgsm_vitac.cpp \
grgsm_vitac/viterbi_detector.cc
@@ -102,7 +101,6 @@ MS_UPPER_SRC = \
noinst_HEADERS += \
ms/ms.h \
ms/threadsched.h \
ms/bladerf_specific.h \
ms/uhd_specific.h \
ms/ms_upper.h \

View File

@@ -32,7 +32,7 @@ extern "C" {
#define M_PI 3.14159265358979323846264338327f
#endif
#define MAX_OUTPUT_LEN 4096*4
#define MAX_OUTPUT_LEN 4096
using namespace std;

View File

@@ -959,18 +959,19 @@ int Transceiver::ctrl_sock_handle_rx(int chan)
sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss);
}
} else if (match_cmd(command, "SETMAXDLY", &params)) {
//set expected maximum time-of-arrival for Access Bursts
//set expected maximum time-of-arrival
int maxDelay;
sscanf(params, "%d", &maxDelay);
mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
} else if (match_cmd(command, "SETMAXDLYNB", &params)) {
//set expected maximum time-of-arrival for Normal Bursts
//set expected maximum time-of-arrival
int maxDelay;
sscanf(params, "%d", &maxDelay);
mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
} else if (match_cmd(command, "SETRXGAIN", &params)) {
//set expected maximum time-of-arrival
int newGain;
sscanf(params, "%d", &newGain);
newGain = mRadioInterface->setRxGain(newGain, chan);

View File

@@ -95,7 +95,7 @@ NO_UBSAN static void detect_burst_generic(const gr_complex *input, gr_complex *c
viterbi_detector(filtered_burst, burst_size, rhh, start_state, stop_states, 2, output);
for (unsigned int i = 0; i < burst_size; i++)
output_binary[i] = output[i] > 0 ? -127 : 127; // pre flip bits!
output_binary[i] = (char)(output[i] * -127); // pre flip bits!
}
NO_UBSAN void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary,

View File

@@ -254,7 +254,6 @@ struct blade_hw {
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
bladerf_set_usb_reset_on_open(true);
blade_check(bladerf_open, &dev, "");
if (!dev) {
std::cerr << "open failed, device missing?" << std::endl;
@@ -269,8 +268,7 @@ struct blade_hw {
bool is_locked;
blade_check(bladerf_set_pll_enable, dev, true);
uint64_t refclock = 10000000UL;
blade_check(bladerf_set_pll_refclk, dev, refclock);
blade_check(bladerf_set_pll_refclk, dev, 10000000UL);
for (int i = 0; i < 20; i++) {
usleep(50 * 1000);
bladerf_get_pll_lock_state(dev, &is_locked);
@@ -429,12 +427,10 @@ struct blade_hw {
auto get_rx_burst_handler_fn(bh_fn_t burst_handler)
{
using thist = decltype(this);
auto fn = [](void *args) -> void * {
thist t = reinterpret_cast<thist>(args);
auto fn = [this] {
int status = 0;
if (!stop_lower_threads_flag)
status = bladerf_stream(t->rx_stream, BLADERF_RX_X1);
status = bladerf_stream(rx_stream, BLADERF_RX_X1);
if (status < 0)
std::cerr << "rx stream error! " << bladerf_strerror(status) << std::endl;
@@ -444,12 +440,10 @@ struct blade_hw {
}
auto get_tx_burst_handler_fn(bh_fn_t burst_handler)
{
using thist = decltype(this);
auto fn = [](void *args) -> void * {
thist t = reinterpret_cast<thist>(args);
auto fn = [this] {
int status = 0;
if (!stop_lower_threads_flag)
status = bladerf_stream(t->tx_stream, BLADERF_TX_X1);
status = bladerf_stream(tx_stream, BLADERF_TX_X1);
if (status < 0)
std::cerr << "rx stream error! " << bladerf_strerror(status) << std::endl;

View File

@@ -35,8 +35,6 @@ extern "C" {
#include "sch.h"
}
#include "threadsched.h"
dummylog ms_trx::dummy_log;
#ifdef DBGXX
@@ -85,11 +83,13 @@ void ms_trx::start_lower_ms()
if (stop_lower_threads_flag)
return;
auto fn = get_rx_burst_handler_fn(rx_bh());
lower_rx_task = spawn_worker_thread(sched_params::thread_names::RXRUN, fn, this);
lower_rx_task = std::thread(fn);
set_name_aff_sched(lower_rx_task.native_handle(), sched_params::thread_names::RXRUN);
usleep(1000);
auto fn2 = get_tx_burst_handler_fn(tx_bh());
lower_tx_task = spawn_worker_thread(sched_params::thread_names::TXRUN, fn2, this);
lower_tx_task = std::thread(fn2);
set_name_aff_sched(lower_tx_task.native_handle(), sched_params::thread_names::TXRUN);
actually_enable_streams();
}
@@ -105,9 +105,9 @@ void ms_trx::stop_threads()
stop_lower_threads_flag = true;
close_device();
std::cerr << "dev closed..." << std::endl;
pthread_join(lower_rx_task, nullptr);
lower_rx_task.join();
std::cerr << "L rx dead..." << std::endl;
pthread_join(lower_tx_task, nullptr);
lower_tx_task.join();
std::cerr << "L tx dead..." << std::endl;
}
@@ -130,7 +130,7 @@ void ms_trx::submit_burst(blade_sample_type *buffer, int len, GSM::Time target)
tosend.decTN(-diff_tn);
// in theory fn equal and tn+3 equal is also a problem...
if (diff_fn < 0 || (diff_fn == 0 && (target_tn-now_time.TN() < 3))) {
if (diff_fn < 0 || (diff_fn == 0 && (now_time.TN() - target_tn < 1))) {
std::cerr << "## TX too late?! fn DIFF:" << diff_fn << " tn LOCAL: " << now_time.TN()
<< " tn OTHER: " << target_tn << std::endl;
return;

View File

@@ -26,7 +26,7 @@
#include <cstdint>
#include <mutex>
#include <iostream>
// #include <thread>
#include <thread>
#if defined(BUILDBLADE)
#include "bladerf_specific.h"
@@ -42,9 +42,9 @@
#include "GSMCommon.h"
#include "itrq.h"
#include "threadpool.h"
#include "threadsched.h"
const unsigned int ONE_TS_BURST_LEN = (3 + 58 + 26 + 58 + 3 + 8.25) * 4 /*sps*/;
const unsigned int NUM_RXQ_FRAMES = 1; // rx thread <-> upper rx queue
const unsigned int SCH_LEN_SPS = (ONE_TS_BURST_LEN * 8 /*ts*/ * 12 /*frames*/);
template <typename T>
@@ -133,7 +133,7 @@ struct one_burst {
};
};
using rx_queue_t = spsc_cond_timeout<4, one_burst, true, false>;
using rx_queue_t = spsc_cond_timeout<8 * NUM_RXQ_FRAMES, one_burst, true, false>;
enum class SCH_STATE { SEARCHING, FOUND };
@@ -217,23 +217,43 @@ class time_keeper {
}
};
using ts_hitter_q_t = spsc_cond<64, GSM::Time, true, false>;
// used to globally initialize the sched/hw information
struct sched_hw_info {
int hw_cpus;
sched_params::target hw_target;
sched_hw_info()
static struct sched_params {
enum thread_names { U_CTL = 0, U_RX, U_TX, SCH_SEARCH, MAIN, LEAKCHECK, RXRUN, TXRUN, _THRD_NAME_COUNT };
enum target { ODROID = 0, PI4 };
const char *name;
int core;
int schedtype;
int prio;
} schdp[][sched_params::_THRD_NAME_COUNT]{
{
hw_cpus = std::thread::hardware_concurrency();
hw_target = hw_cpus > 4 ? sched_params::target::ODROID : sched_params::target::PI4;
set_sched_target(hw_target);
std::cerr << "scheduling for: " << (hw_cpus > 4 ? "odroid" : "pi4") << std::endl;
}
{ "upper_ctrl", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) },
{ "upper_rx", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) - 5 },
{ "upper_tx", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) - 1 },
{ "sch_search", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "main", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "leakcheck", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 10 },
{ "rxrun", 4, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 2 },
{ "txrun", 5, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
},
{
{ "upper_ctrl", 1, SCHED_RR, sched_get_priority_max(SCHED_RR) },
{ "upper_rx", 1, SCHED_RR, sched_get_priority_max(SCHED_RR) - 5 },
{ "upper_tx", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
{ "sch_search", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "main", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "leakcheck", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 10 },
{ "rxrun", 2, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 2 },
{ "txrun", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
},
};
struct ms_trx : public BASET, public sched_hw_info {
using ts_hitter_q_t = spsc_cond<64, GSM::Time, true, false>;
struct ms_trx : public BASET {
using base = BASET;
static dummylog dummy_log;
unsigned int mTSC;
@@ -241,8 +261,8 @@ struct ms_trx : public BASET, public sched_hw_info {
int timing_advance;
bool do_auto_gain;
pthread_t lower_rx_task;
pthread_t lower_tx_task;
std::thread lower_rx_task;
std::thread lower_tx_task;
// provides bursts to upper rx thread
rx_queue_t rxqueue;
@@ -258,7 +278,9 @@ struct ms_trx : public BASET, public sched_hw_info {
int64_t first_sch_ts_start = -1;
time_keeper timekeeper;
single_thread_pool worker_thread; // uses base class sched target hw info
int hw_cpus;
sched_params::target hw_target;
single_thread_pool worker_thread;
void start_lower_ms();
std::atomic<bool> upper_is_ready;
@@ -280,8 +302,12 @@ struct ms_trx : public BASET, public sched_hw_info {
: mTSC(0), mBSIC(0), timing_advance(0), do_auto_gain(false), rxqueue(),
first_sch_buf(new blade_sample_type[SCH_LEN_SPS]),
burst_copy_buffer(new blade_sample_type[ONE_TS_BURST_LEN]), first_sch_buf_rcv_ts(0),
rcv_done{ false }, sch_thread_done{ false }, upper_is_ready(false)
rcv_done{ false }, sch_thread_done{ false }, hw_cpus(std::thread::hardware_concurrency()),
hw_target(hw_cpus > 4 ? sched_params::target::ODROID : sched_params::target::PI4),
upper_is_ready(false)
{
std::cerr << "scheduling for: " << (hw_cpus > 4 ? "odroid" : "pi4") << std::endl;
set_name_aff_sched(worker_thread.get_handle(), sched_params::thread_names::SCH_SEARCH);
}
virtual ~ms_trx()
@@ -298,4 +324,73 @@ struct ms_trx : public BASET, public sched_hw_info {
assert(val > -127 && val < 128);
timing_advance = val * 4;
}
void set_name_aff_sched(sched_params::thread_names name)
{
set_name_aff_sched(pthread_self(), name);
}
void set_name_aff_sched(std::thread::native_handle_type h, sched_params::thread_names name)
{
auto tgt = schdp[hw_target][name];
// std::cerr << "scheduling for: " << tgt.name << ":" << tgt.core << std::endl;
set_name_aff_sched(h, tgt.name, tgt.core, tgt.schedtype, tgt.prio);
}
using pt_sig = void *(*)(void *);
pthread_t spawn_worker_thread(sched_params::thread_names name, pt_sig fun, void *arg)
{
auto tgt = schdp[hw_target][name];
// std::cerr << "scheduling for: " << tgt.name << ":" << tgt.core << " prio:" << tgt.prio << std::endl;
return do_spawn_thr(tgt.name, tgt.core, tgt.schedtype, tgt.prio, fun, arg);
}
private:
void set_name_aff_sched(std::thread::native_handle_type h, const char *name, int cpunum, int schedtype,
int prio)
{
pthread_setname_np(h, name);
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpunum, &cpuset);
if (pthread_setaffinity_np(h, sizeof(cpuset), &cpuset) < 0) {
std::cerr << name << " affinity: errreur! " << std::strerror(errno);
return exit(0);
}
sched_param sch_params;
sch_params.sched_priority = prio;
if (pthread_setschedparam(h, schedtype, &sch_params) < 0) {
std::cerr << name << " sched: errreur! " << std::strerror(errno);
return exit(0);
}
}
pthread_t do_spawn_thr(const char *name, int cpunum, int schedtype, int prio, pt_sig fun, void *arg)
{
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
sched_param sch_params;
sch_params.sched_priority = prio;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpunum, &cpuset);
auto a = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
a |= pthread_attr_setschedpolicy(&attr, schedtype);
a |= pthread_attr_setschedparam(&attr, &sch_params);
a |= pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if(a)
std::cerr << "thread arg rc:" << a << std::endl;
pthread_create(&thread, &attr, fun, arg);
pthread_setname_np(thread, name);
pthread_attr_destroy(&attr);
return thread;
}
};

View File

@@ -19,8 +19,6 @@
*
*/
#include "sigProcLib.h"
#include "signalVector.h"
#include <atomic>
#include <cassert>
#include <complex>
@@ -157,12 +155,12 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
auto current_gsm_time = timekeeper.gsmtime();
const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
#if 1
const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
int start;
memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
if (is_first_sch_acq) {
float max_corr = 0;
@@ -175,22 +173,9 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
#if 0
auto burst = new signalVector(buf_len, 50);
const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
struct estim_burst_params ebp;
// scale like uhd, +-2k -> +-32k
convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
int howmuchdelay = ebp.toa * 4;
std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
std::cerr << "voffs: " << start << " " << sch_decode_success << std::endl;
#endif
if (sch_decode_success) {
const auto ts_offset_symb = 4;
const auto ts_offset_symb = 0;
if (is_first_sch_acq) {
// update ts to first sample in sch buffer, to allow delay calc for current ts
first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
@@ -205,97 +190,6 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
<< ":" << current_gsm_time.TN() << std::endl;
}
#else
const auto ts_offset_symb = 4;
auto burst = new signalVector(buf_len, 50);
const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
struct estim_burst_params ebp;
// scale like uhd, +-2k -> +-32k
convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
int howmuchdelay = ebp.toa * 4;
if (!rv) {
delete burst;
DBGLG() << "SCH : \x1B[31m detect fail \033[0m NOOOOOOOOOOOOOOOOOO toa:" << ebp.toa << " "
<< current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
return false;
}
SoftVector *bits;
if (is_first_sch_acq) {
// can't be legit with a buf size spanning _at least_ one SCH but delay that implies partial sch burst
if (howmuchdelay < 0 || (buf_len - howmuchdelay) < ONE_TS_BURST_LEN) {
delete burst;
return false;
}
struct estim_burst_params ebp2;
// auto sch_chunk = new signalVector(ONE_TS_BURST_LEN, 50);
// auto sch_chunk_start = sch_chunk->begin();
// memcpy(sch_chunk_start, sch_buf_f.data() + howmuchdelay, sizeof(std::complex<float>) * ONE_TS_BURST_LEN);
auto delay = delayVector(burst, NULL, -howmuchdelay);
scaleVector(*delay, (complex)1.0 / ebp.amp);
auto rv2 = detectSCHBurst(*delay, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp2);
DBGLG() << "FIRST SCH : " << (rv2 ? "yes " : " ") << "Timing offset " << ebp2.toa << " symbols"
<< std::endl;
bits = demodAnyBurst(*delay, SCH, 4, &ebp2);
delete delay;
} else {
bits = demodAnyBurst(*burst, SCH, 4, &ebp);
}
delete burst;
// clamp to +-1.5 because +-127 softbits scaled by 64 after -0.5 can be at most +-1.5
clamp_array(bits->begin(), 148, 1.5f);
float_to_sbit(&bits->begin()[0], (signed char *)&sch_demod_bits[0], 62, 148);
// float_to_sbit(&bits->begin()[106], &data[39], 62, 39);
if (decode_sch((char *)sch_demod_bits, is_first_sch_acq)) {
auto current_gsm_time_updated = timekeeper.gsmtime();
if (is_first_sch_acq) {
// update ts to first sample in sch buffer, to allow delay calc for current ts
first_sch_ts_start = first_sch_buf_rcv_ts + howmuchdelay - (ts_offset_symb * 4);
} else {
// continuous sch tracking, only update if off too much
auto diff = [](float x, float y) { return x > y ? x - y : y - x; };
auto d = diff(ebp.toa, ts_offset_symb);
if (abs(d) > 0.3) {
if (ebp.toa < ts_offset_symb)
ebp.toa = d;
else
ebp.toa = -d;
temp_ts_corr_offset += ebp.toa * 4;
DBGLG() << "offs: " << ebp.toa << " " << temp_ts_corr_offset << std::endl;
}
}
auto a = gsm_sch_check_fn(current_gsm_time_updated.FN() - 1);
auto b = gsm_sch_check_fn(current_gsm_time_updated.FN());
auto c = gsm_sch_check_fn(current_gsm_time_updated.FN() + 1);
DBGLG() << "L SCH : Timing offset " << rv << " " << ebp.toa << " " << a << b << c << "fn "
<< current_gsm_time_updated.FN() << ":" << current_gsm_time_updated.TN() << std::endl;
delete bits;
return true;
} else {
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << ebp.toa << " " << current_gsm_time.FN()
<< ":" << current_gsm_time.TN() << std::endl;
}
delete bits;
#endif
return false;
}

View File

@@ -50,7 +50,6 @@ void __lsan_do_recoverable_leak_check();
#include "ms_trxcon_if.h"
#include "ms_upper.h"
#include "threadsched.h"
extern bool trxc_l1ctl_init(void *tallctx);
struct trxcon_inst *g_trxcon;
@@ -199,7 +198,6 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
return true;
}
#if 1
convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
pow = energyDetect(sv, 20 * 4 /*sps*/);
@@ -233,42 +231,6 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
#endif
}
#else
// lower layer sch detection offset, easy to verify by just printing the detected value using both the va+sigproc code.
convert_and_scale(ss + 16, e.burst, ONE_TS_BURST_LEN * 2, 15);
pow = energyDetect(sv, 20 * 4 /*sps*/);
if (pow < -1) {
LOG(ALERT) << "Received empty burst";
return false;
}
avg = sqrt(pow);
/* Detect normal or RACH bursts */
CorrType type = CorrType::TSC;
struct estim_burst_params ebp;
auto rc = detectAnyBurst(sv, mTSC, 3, 4, type, 48, &ebp);
if (rc > 0) {
type = (CorrType)rc;
}
if (rc < 0) {
std::cerr << "UR : \x1B[31m rx fail \033[0m @ toa:" << ebp.toa << " " << e.gsmts.FN() << ":"
<< e.gsmts.TN() << std::endl;
return false;
}
SoftVector *bits = demodAnyBurst(sv, type, 4, &ebp);
SoftVector::const_iterator burstItr = bits->begin();
// invert and fix to +-127 sbits
for (int ii = 0; ii < 148; ii++) {
demodded_softbits[ii] = *burstItr++ > 0.0f ? -127 : 127;
}
delete bits;
#endif
RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
// FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
timingOffset = (int)round(0);
@@ -296,7 +258,6 @@ void upper_trx::driveReceiveFIFO()
trxcon_phyif_handle_burst_ind(g_trxcon, &bi);
}
burstTime.incTN(2);
struct trxcon_phyif_rts_ind rts {
static_cast<uint32_t>(burstTime.FN()), static_cast<uint8_t>(burstTime.TN())
};
@@ -495,7 +456,7 @@ int main(int argc, char *argv[])
std::cerr << "Error initializing hardware, quitting.." << std::endl;
return -1;
}
set_name_aff_sched(sched_params::thread_names::MAIN);
trx->set_name_aff_sched(sched_params::thread_names::MAIN);
if (!trxc_l1ctl_init(tall_trxcon_ctx)) {
std::cerr << "Error initializing l1ctl, quitting.." << std::endl;

View File

@@ -20,12 +20,13 @@
*
*/
#include <functional>
#include <thread>
#include <atomic>
#include <vector>
#include <future>
#include <mutex>
#include <queue>
#include "threadsched.h"
struct single_thread_pool {
std::mutex m;
@@ -33,7 +34,7 @@ struct single_thread_pool {
std::atomic<bool> stop_flag;
std::atomic<bool> is_ready;
std::deque<std::function<void()>> wq;
pthread_t worker_thread;
std::thread worker_thread;
template <class F>
void add_task(F &&f)
@@ -44,23 +45,19 @@ struct single_thread_pool {
return;
}
single_thread_pool() : stop_flag(false), is_ready(false)
single_thread_pool() : stop_flag(false), is_ready(false), worker_thread(std::thread([this] { thread_loop(); }))
{
worker_thread = spawn_worker_thread(
sched_params::thread_names::SCH_SEARCH,
[](void *args) -> void * {
using thist = decltype(this);
thist t = reinterpret_cast<thist>(args);
t->thread_loop();
return 0;
},
this);
}
~single_thread_pool()
{
stop();
}
std::thread::native_handle_type get_handle()
{
return worker_thread.native_handle();
}
private:
void stop()
{
@@ -70,7 +67,7 @@ struct single_thread_pool {
stop_flag = true;
cv.notify_one();
}
pthread_join(worker_thread, nullptr);
worker_thread.join();
}
void thread_loop()

View File

@@ -1,104 +0,0 @@
/*
* (C) 2023 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 <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
extern "C" {
#include <pthread.h>
}
#include "threadsched.h"
sched_params::target scheduling_target;
void set_sched_target(sched_params::target t)
{
scheduling_target = t;
}
void set_name_aff_sched(std::thread::native_handle_type h, const char *name, int cpunum, int schedtype, int prio)
{
pthread_setname_np(h, name);
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpunum, &cpuset);
if (pthread_setaffinity_np(h, sizeof(cpuset), &cpuset) < 0) {
std::cerr << name << " affinity: errreur! " << std::strerror(errno);
return exit(0);
}
sched_param sch_params;
sch_params.sched_priority = prio;
if (pthread_setschedparam(h, schedtype, &sch_params) < 0) {
std::cerr << name << " sched: errreur! " << std::strerror(errno);
return exit(0);
}
}
static pthread_t do_spawn_thr(const char *name, int cpunum, int schedtype, int prio, worker_func_sig fun, void *arg)
{
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
sched_param sch_params;
sch_params.sched_priority = prio;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpunum, &cpuset);
auto a = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
a |= pthread_attr_setschedpolicy(&attr, schedtype);
a |= pthread_attr_setschedparam(&attr, &sch_params);
a |= pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (a)
std::cerr << "thread arg rc:" << a << std::endl;
pthread_create(&thread, &attr, fun, arg);
pthread_setname_np(thread, name);
pthread_attr_destroy(&attr);
return thread;
}
void set_name_aff_sched(std::thread::native_handle_type h, sched_params::thread_names name)
{
auto tgt = schdp[scheduling_target][name];
// std::cerr << "scheduling for: " << tgt.name << ":" << tgt.core << std::endl;
set_name_aff_sched(h, tgt.name, tgt.core, tgt.schedtype, tgt.prio);
}
void set_name_aff_sched(sched_params::thread_names name)
{
set_name_aff_sched(pthread_self(), name);
}
pthread_t spawn_worker_thread(sched_params::thread_names name, worker_func_sig fun, void *arg)
{
auto tgt = schdp[scheduling_target][name];
// std::cerr << "scheduling for: " << tgt.name << ":" << tgt.core << " prio:" << tgt.prio << std::endl;
return do_spawn_thr(tgt.name, tgt.core, tgt.schedtype, tgt.prio, fun, arg);
}

View File

@@ -1,68 +0,0 @@
#pragma once
/*
* (C) 2023 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/>.
*
*/
extern "C" {
#include <pthread.h>
#include <sched.h>
}
static struct sched_params {
enum thread_names { U_CTL = 0, U_RX, U_TX, SCH_SEARCH, MAIN, LEAKCHECK, RXRUN, TXRUN, _THRD_NAME_COUNT };
enum target { ODROID = 0, PI4 };
const char *name;
int core;
int schedtype;
int prio;
} schdp[][sched_params::_THRD_NAME_COUNT]{
{
{ "upper_ctrl", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) },
{ "upper_rx", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) - 5 },
{ "upper_tx", 2, SCHED_RR, sched_get_priority_max(SCHED_RR) - 1 },
{ "sch_search", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "main", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "leakcheck", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 10 },
{ "rxrun", 4, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 2 },
{ "txrun", 5, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
},
{
{ "upper_ctrl", 1, SCHED_RR, sched_get_priority_max(SCHED_RR) },
{ "upper_rx", 1, SCHED_RR, sched_get_priority_max(SCHED_RR) - 5 },
{ "upper_tx", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
{ "sch_search", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "main", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 5 },
{ "leakcheck", 1, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 10 },
{ "rxrun", 2, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 2 },
{ "txrun", 3, SCHED_FIFO, sched_get_priority_max(SCHED_FIFO) - 1 },
},
};
void set_sched_target(sched_params::target t);
using worker_func_sig = void *(*)(void *);
void set_name_aff_sched(sched_params::thread_names name);
pthread_t spawn_worker_thread(sched_params::thread_names name, worker_func_sig fun, void *arg);

View File

@@ -231,29 +231,24 @@ struct uhd_hw {
auto get_rx_burst_handler_fn(bh_fn_t burst_handler)
{
// C cb -> ghetto closure capture, which is fine, the args never change.
static auto rx_burst_cap_this = this;
static auto rx_burst_cap_bh = burst_handler;
auto fn = [](void *args) -> void * {
auto fn = [this, burst_handler] {
pthread_setname_np(pthread_self(), "rxrun");
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
stream_cmd.stream_now = true;
stream_cmd.time_spec = uhd::time_spec_t();
rx_burst_cap_this->rx_stream->issue_stream_cmd(stream_cmd);
rx_stream->issue_stream_cmd(stream_cmd);
while (!rx_burst_cap_this->stop_lower_threads_flag) {
rx_burst_cap_this->rx_cb(rx_burst_cap_bh);
while (!stop_lower_threads_flag) {
rx_cb(burst_handler);
}
return 0;
};
return fn;
}
auto get_tx_burst_handler_fn(bh_fn_t burst_handler)
{
auto fn = [](void *args) -> void * {
auto fn = [] {
// dummy
return 0;
};
return fn;
}

View File

@@ -129,8 +129,6 @@ struct PulseSequence {
static CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
static CorrelationSequence *gEdgeMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
static CorrelationSequence *gRACHSequences[] = {NULL,NULL,NULL};
static CorrelationSequence *gSCHSequence = NULL;
static CorrelationSequence *gDummySequence = NULL;
static PulseSequence *GSMPulse1 = NULL;
static PulseSequence *GSMPulse4 = NULL;
@@ -153,12 +151,6 @@ void sigProcLibDestroy()
gRACHSequences[i] = NULL;
}
delete gSCHSequence;
gSCHSequence = NULL;
delete gDummySequence;
gDummySequence = NULL;
delete GMSKRotation1;
delete GMSKReverseRotation1;
delete GMSKRotation4;
@@ -323,7 +315,6 @@ static signalVector *convolve(const signalVector *x, const signalVector *h,
append = true;
break;
case CUSTOM:
// FIXME: x->getstart?
if (start < h->size() - 1) {
head = h->size() - start;
append = true;
@@ -1298,77 +1289,6 @@ release:
return status;
}
static bool generateDummyMidamble(int sps)
{
bool status = true;
float toa;
complex *data = NULL;
signalVector *autocorr = NULL, *midamble = NULL;
signalVector *midMidamble = NULL, *_midMidamble = NULL;
delete gDummySequence;
/* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
midMidamble = modulateBurst(gDummyBurstTSC.segment(5,16), 0, sps, true);
if (!midMidamble)
return false;
/* Simulated receive sequence is pulse shaped */
midamble = modulateBurst(gDummyBurstTSC, 0, sps, false);
if (!midamble) {
status = false;
goto release;
}
// NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
// the ideal TSC has an + 180 degree phase shift,
// due to the pi/2 frequency shift, that
// needs to be accounted for.
// 26-midamble is 61 symbols into burst, has +90 degree phase shift.
scaleVector(*midMidamble, complex(-1.0, 0.0));
scaleVector(*midamble, complex(0.0, 1.0));
conjugateVector(*midMidamble);
/* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
data = (complex *) convolve_h_alloc(midMidamble->size());
_midMidamble = new signalVector(data, 0, midMidamble->size(), convolve_h_alloc, free);
_midMidamble->setAligned(true);
midMidamble->copyTo(*_midMidamble);
autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
if (!autocorr) {
status = false;
goto release;
}
gDummySequence = new CorrelationSequence;
gDummySequence->sequence = _midMidamble;
gDummySequence->gain = peakDetect(*autocorr, &toa, NULL);
/* For 1 sps only
* (Half of correlation length - 1) + midpoint of pulse shape + remainder
* 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
*/
if (sps == 1)
gDummySequence->toa = toa - 13.5;
else
gDummySequence->toa = 0;
release:
delete autocorr;
delete midamble;
delete midMidamble;
if (!status) {
delete _midMidamble;
free(data);
gDummySequence = NULL;
}
return status;
}
static CorrelationSequence *generateEdgeMidamble(int tsc)
{
complex *data = NULL;
@@ -1464,69 +1384,6 @@ release:
return status;
}
bool generateSCHSequence(int sps)
{
bool status = true;
float toa;
complex *data = NULL;
signalVector *autocorr = NULL;
signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
delete gSCHSequence;
seq0 = modulateBurst(gSCHSynchSequence, 0, sps, false);
if (!seq0)
return false;
seq1 = modulateBurst(gSCHSynchSequence, 0, sps, true);
if (!seq1) {
status = false;
goto release;
}
conjugateVector(*seq1);
/* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
data = (complex *) convolve_h_alloc(seq1->size());
_seq1 = new signalVector(data, 0, seq1->size(), convolve_h_alloc, free);
_seq1->setAligned(true);
seq1->copyTo(*_seq1);
autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
if (!autocorr) {
status = false;
goto release;
}
gSCHSequence = new CorrelationSequence;
gSCHSequence->sequence = _seq1;
gSCHSequence->buffer = data;
gSCHSequence->gain = peakDetect(*autocorr, &toa, NULL);
/* For 1 sps only
* (Half of correlation length - 1) + midpoint of pulse shaping filer
* 20.5 = (64 / 2 - 1) + 1.5
*/
if (sps == 1)
gSCHSequence->toa = toa - 32.5;
else
gSCHSequence->toa = 0.0;
release:
delete autocorr;
delete seq0;
delete seq1;
if (!status) {
delete _seq1;
free(data);
gSCHSequence = NULL;
}
return status;
}
/*
* Peak-to-average computation +/- range from peak in symbols
*/
@@ -1584,15 +1441,14 @@ float energyDetect(const signalVector &rxBurst, unsigned windowLength)
return energy/windowLength;
}
static signalVector *downsampleBurst(const signalVector &burst, int in_len = DOWNSAMPLE_IN_LEN,
int out_len = DOWNSAMPLE_OUT_LEN)
static signalVector *downsampleBurst(const signalVector &burst)
{
signalVector in(in_len, dnsampler->len());
// gSCHSequence->sequence->size(), ensure next conv has no realloc
signalVector *out = new signalVector(out_len, 64);
burst.copyToSegment(in, 0, in_len);
signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
burst.copyToSegment(in, 0, DOWNSAMPLE_IN_LEN);
if (dnsampler->rotate((float *)in.begin(), in_len, (float *)out->begin(), out_len) < 0) {
if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
(float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
delete out;
out = NULL;
}
@@ -1613,12 +1469,6 @@ static float computeCI(const signalVector *burst, const CorrelationSequence *syn
/* Integer position where the sequence starts */
const int ps = start + 1 - N + (int)roundf(toa);
if(ps < 0) // might be -22 for toa 40 with N=64, if off by a lot during sch ms sync
return 0;
if (ps + N > (int)burst->size())
return 0;
/* Estimate Signal power */
S = 0.0f;
for (int i=0, j=ps; i<(int)N; i++,j++)
@@ -1802,80 +1652,6 @@ static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
return rc;
}
int detectSCHBurst(signalVector &burst,
float thresh,
int sps,
sch_detect_type state, struct estim_burst_params *ebp)
{
int rc, start, target, head, tail, len;
complex _amp;
CorrelationSequence *sync;
if ((sps != 1) && (sps != 4))
return -1;
target = 3 + 39 + 64;
switch (state) {
case sch_detect_type::SCH_DETECT_NARROW:
head = 4;
tail = 4;
break;
case sch_detect_type::SCH_DETECT_BUFFER:
target = 1;
head = 0;
tail = (12 * 8 * 625) / 4; // 12 frames, downsampled /4 to 1 sps
break;
case sch_detect_type::SCH_DETECT_FULL:
default:
head = target - 1;
tail = 39 + 3 + 9;
break;
}
start = (target - head) * 1 - 1;
len = (head + tail) * 1;
sync = gSCHSequence;
signalVector corr(len);
signalVector *dec = downsampleBurst(burst, len * 4, len);
rc = detectBurst(*dec, corr, sync, thresh, 1, start, len, ebp);
delete dec;
if (rc < 0) {
return -1;
} else if (!rc) {
ebp->amp = 0.0f;
ebp->toa = 0.0f;
return 0;
}
if (state == sch_detect_type::SCH_DETECT_BUFFER)
ebp->toa = ebp->toa - (3 + 39 + 64);
else {
/* Subtract forward search bits from delay */
ebp->toa = ebp->toa - head;
}
return rc;
}
static int detectDummyBurst(const signalVector &burst, float threshold,
int sps, unsigned max_toa, struct estim_burst_params *ebp)
{
int rc, target, head, tail;
CorrelationSequence *sync;
target = 3 + 58 + 16 + 5;
head = 10;
tail = 6 + max_toa;
sync = gDummySequence;
ebp->tsc = 0;
rc = detectGeneralBurst(burst, threshold, sps, target, head, tail, sync, ebp);
return rc;
}
/*
* Normal burst detection
*
@@ -1894,7 +1670,7 @@ static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float th
return -SIGERR_UNSUPPORTED;
target = 3 + 58 + 16 + 5;
head = 10;
head = 6;
tail = 6 + max_toa;
sync = gMidambles[tsc];
@@ -1943,9 +1719,6 @@ int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
case RACH:
rc = detectRACHBurst(burst, threshold, sps, max_toa, type == EXT_RACH, ebp);
break;
case IDLE:
rc = detectDummyBurst(burst, threshold, sps, max_toa, ebp);
break;
default:
LOG(ERR) << "Invalid correlation type";
}
@@ -2148,9 +1921,6 @@ bool sigProcLibSetup()
generateRACHSequence(&gRACHSequences[1], gRACHSynchSequenceTS1, 1);
generateRACHSequence(&gRACHSequences[2], gRACHSynchSequenceTS2, 1);
generateSCHSequence(1);
generateDummyMidamble(1);
for (int tsc = 0; tsc < 8; tsc++) {
generateMidamble(1, tsc);
gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);

View File

@@ -31,7 +31,6 @@ enum CorrType{
TSC, ///< timeslot should contain a normal burst
EXT_RACH, ///< timeslot should contain an extended access burst
RACH, ///< timeslot should contain an access burst
SCH,
EDGE, ///< timeslot should contain an EDGE burst
IDLE ///< timeslot is an idle (or dummy) burst
};
@@ -94,8 +93,6 @@ signalVector *generateDummyBurst(int sps, int tn);
void scaleVector(signalVector &x,
complex scale);
signalVector *delayVector(const signalVector *in, signalVector *out, float delay);
/**
Rough energy estimator.
@param rxBurst A GSM burst.
@@ -136,17 +133,6 @@ int detectAnyBurst(const signalVector &burst,
unsigned max_toa,
struct estim_burst_params *ebp);
enum class sch_detect_type {
SCH_DETECT_FULL,
SCH_DETECT_NARROW,
SCH_DETECT_BUFFER,
};
int detectSCHBurst(signalVector &rxBurst,
float detectThreshold,
int sps,
sch_detect_type state, struct estim_burst_params *ebp);
/** Demodulate burst basde on type and output soft bits */
SoftVector *demodAnyBurst(const signalVector &burst, CorrType type,
int sps, struct estim_burst_params *ebp);

View File

@@ -374,7 +374,6 @@ AC_CONFIG_FILES([\
tests/CommonLibs/Makefile \
tests/Transceiver52M/Makefile \
utils/Makefile \
utils/va-test/Makefile \
doc/Makefile \
doc/examples/Makefile \
contrib/Makefile \

View File

@@ -8,7 +8,6 @@ Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Environment=HOME=%h
ExecStart=/usr/bin/osmo-trx-uhd -C /etc/osmocom/osmo-trx-uhd.cfg
RestartSec=2
# CPU scheduling policy:

7
debian/changelog vendored
View File

@@ -1,3 +1,10 @@
osmo-trx (1.6.1) unstable; urgency=medium
[ Eric Wild ]
* devices: fix wrong gain to power mapping
-- Eric Wild <ewild@sysmocom.de> Thu, 09 Nov 2023 14:16:21 +0200
osmo-trx (1.6.0) unstable; urgency=medium
[ Vadim Yanitskiy ]

20
debian/control vendored
View File

@@ -14,7 +14,6 @@ Build-Depends: debhelper (>= 10),
libtalloc-dev,
libusrp-dev,
liblimesuite-dev,
libbladerf-dev,
libosmocore-dev (>= 1.9.0),
osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.6
@@ -111,25 +110,6 @@ Description: SDR transceiver that implements Layer 1 of a GSM BTS (generic IPC)
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-ms-blade
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: MS side transceiver (bladeRF)
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:
.
TS 05.01 "Physical layer on the radio path"
TS 05.02 "Multiplexing and Multiple Access on the Radio Path"
TS 05.04 "Modulation"
TS 05.10 "Radio subsystem synchronization"
.
In this context, BTS is "Base transceiver station". It's the stations that
connect mobile phones to the mobile network.
.
3GPP is the "3rd Generation Partnership Project" which is the collaboration
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-doc
Architecture: all
Section: doc

View File

@@ -1 +0,0 @@
/usr/bin/osmo-trx-ms-blade

11
debian/rules vendored
View File

@@ -9,16 +9,7 @@ override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
override_dh_auto_configure:
dh_auto_configure -- \
--enable-manuals \
--with-systemdsystemunitdir=/lib/systemd/system \
--with-bladerf \
--with-ipc \
--with-lms \
--with-mstrx \
--with-uhd \
--with-usrp1 \
$(NULL)
dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-ipc --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
override_dh_strip:
dh_strip --dbg-package=osmo-trx-dbg

View File

@@ -1,15 +1,3 @@
# all config examples must be listed here unconditionally, so that
# all of them end up in the release tarball (see OS#6349)
EXTRA_DIST = \
osmo-trx-uhd/osmo-trx-limesdr.cfg \
osmo-trx-uhd/osmo-trx-usrp_b200.cfg \
osmo-trx-uhd/osmo-trx-uhd.cfg \
osmo-trx-uhd/osmo-trx-umtrx.cfg \
osmo-trx-lms/osmo-trx-limesdr.cfg \
osmo-trx-lms/osmo-trx-lms.cfg \
osmo-trx-ipc/osmo-trx-ipc.cfg \
$(NULL)
OSMOCONF_FILES =
osmoconfdir = $(sysconfdir)/osmocom
@@ -31,6 +19,7 @@ OSMOCONF_FILES += osmo-trx-ipc/osmo-trx-ipc.cfg
endif
osmoconf_DATA = $(OSMOCONF_FILES)
EXTRA_DIST = $(OSMOCONF_FILES)
CFG_FILES = find $(srcdir) -type f -name '*.cfg*' | sed -e 's,^$(srcdir),,'

View File

@@ -1,11 +1,9 @@
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty

View File

@@ -1,11 +1,9 @@
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty

View File

@@ -1,11 +1,9 @@
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty

View File

@@ -1,11 +1,9 @@
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty

View File

@@ -1,11 +1,9 @@
log stderr
logging filter all 1
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
logging timestamp 1
logging print file basename
logging level set-all notice
!
line vty

View File

@@ -1,8 +1,6 @@
AM_CPPFLAGS = $(LIBOSMOCODING_CFLAGS)
AM_CFLAGS = -Wall
DIST_SUBDIRS = va-test
EXTRA_DIST = clockdump.sh matlab
noinst_PROGRAMS = osmo-prbs-tool

View File

@@ -1,17 +0,0 @@
include $(top_srcdir)/Makefile.common
noinst_PROGRAMS = osmo-burst-gen
osmo_burst_gen_SOURCES = burst-gen.cpp \
${top_srcdir}/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp \
${top_srcdir}/Transceiver52M/grgsm_vitac/viterbi_detector.cc
osmo_burst_gen_LDADD = \
${top_srcdir}/Transceiver52M/libtransceiver_common.la \
$(ARCH_LA) \
$(GSM_LA) \
$(COMMON_LA)
osmo_burst_gen_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) \
-I${top_srcdir}/Transceiver52M/arch/common \
-I${top_srcdir}/Transceiver52M/device/common \
-I${top_srcdir}/Transceiver52M

View File

@@ -1,531 +0,0 @@
/*
* (C) 2023 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/>.
*
*/
// this allows messing with the demod to check the detecton offset impact,
// not intended for actual automated tests.
#include "sigProcLib.h"
extern "C" {
#include "convert.h"
#include <convolve.h>
}
#define _CRT_SECURE_NO_WARNINGS
#include <algorithm>
#include <string.h>
#include <iomanip>
#include <numeric>
#include <memory>
#include <iostream>
#include <fstream>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <grgsm_vitac/grgsm_vitac.h>
#define DO_RACH
const int SAMPLE_SCALE_FACTOR = 1;
template <typename DST_T, typename SRC_T, typename ST>
void convert_and_scale(void *dst, void *src, unsigned int src_len, ST scale)
{
for (unsigned int i = 0; i < src_len; i++)
reinterpret_cast<DST_T *>(dst)[i] = static_cast<DST_T>((reinterpret_cast<SRC_T *>(src)[i]) * scale);
}
template <typename DST_T, typename SRC_T>
void convert_and_scale_default(void *dst, void *src, unsigned int src_len)
{
return convert_and_scale<DST_T, SRC_T>(dst, src, src_len, SAMPLE_SCALE_FACTOR);
}
static const unsigned int txFullScale = (float)(1 << 14) - 1;
// static const unsigned int rxFullScale = (float)(1 << 14) - 1;
static const BitVector
gRACHBurstx("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");
static const BitVector gTrainingSequencex[] = {
BitVector("00100101110000100010010111"), BitVector("00101101110111100010110111"),
BitVector("01000011101110100100001110"), BitVector("01000111101101000100011110"),
BitVector("00011010111001000001101011"), BitVector("01001110101100000100111010"),
BitVector("10100111110110001010011111"), BitVector("11101111000100101110111100"),
};
struct mrv {
std::vector<char> bits;
signalVector *rvbuf;
std::unique_ptr<std::vector<std::complex<float>>> convolved;
// mrv(): bits(), demod_bits() {}
CorrType ct;
};
static mrv genRandNormalBurstx(int tsc, int sps, int tn)
{
mrv retstruct;
int i = 0;
BitVector bits(148);
/* Tail bits */
for (; i < 3; i++)
bits[i] = 0;
/* Random bits */
for (int j = 0; i < 60; i++, j++)
bits[i] = rand() % 2;
/* Stealing bit */
bits[i++] = 0;
/* Training sequence */
for (int n = 0; i < 87; i++, n++)
bits[i] = gTrainingSequencex[tsc][n];
/* Stealing bit */
bits[i++] = 0;
/* Random bits */
for (; i < 145; i++)
bits[i] = rand() % 2;
/* Tail bits */
for (; i < 148; i++)
bits[i] = 0;
int guard = 8 + !(tn % 4);
auto r = modulateBurst(bits, guard, sps);
retstruct.rvbuf = r;
for (size_t i = 0; i < bits.size(); i++)
retstruct.bits.push_back(bits.bit(i) ? 1 : 0);
return retstruct;
}
static mrv genRandAccessBurstx(int delay, int sps, int tn)
{
mrv retstruct;
int i = 0;
BitVector bits(88 + delay);
/* delay */
for (; i < delay; i++)
bits[i] = 0;
/* head and synch bits */
for (int n = 0; i < 49 + delay; i++, n++)
bits[i] = gRACHBurstx[n];
/* Random bits */
for (int j = 0; i < 85 + delay; i++, j++)
bits[i] = rand() % 2;
for (; i < 88 + delay; i++)
bits[i] = 0;
int guard = 68 - delay + !(tn % 4);
auto r = modulateBurst(bits, guard, sps);
retstruct.rvbuf = r;
for (size_t i = 0; i < bits.size(); i++)
retstruct.bits.push_back(bits.bit(i) ? 1 : 0);
return retstruct;
}
extern gr_complex d_acc_training_seq[N_ACCESS_BITS]; ///<encoded training sequence of a SCH burst
extern gr_complex d_sch_training_seq[N_SYNC_BITS]; ///<encoded training sequence of a SCH burst
extern gr_complex d_norm_training_seq[TRAIN_SEQ_NUM]
[N_TRAIN_BITS]; ///<encoded training sequences of a normal and dummy burst
void sv_write_helper(signalVector *burst, std::string fname)
{
auto start = burst->begin();
auto n = burst->bytes();
char *data = reinterpret_cast<char *>(start);
const int len_in_real = burst->size() * 2;
auto cvrtbuf_tx_a = new int16_t[len_in_real];
convert_float_short(cvrtbuf_tx_a, (float *)burst->begin(), float(txFullScale), len_in_real);
std::ofstream fout;
fout.open(fname + ".cfile", std::ios::binary | std::ios::out);
fout.write(data, n);
fout.close();
fout.open(fname + ".cs16", std::ios::binary | std::ios::out);
fout.write((char *)cvrtbuf_tx_a, len_in_real * sizeof(uint16_t));
fout.close();
delete[] cvrtbuf_tx_a;
}
// borrowed from a real world burst..
static std::vector<std::complex<float>> chan_im_resp = {
{ 4.1588e-05 + -0.000361925 }, { 0.000112728 + -0.000289796 }, { 0.000162952 + -0.000169028 },
{ 0.000174185 + -2.54575e-05 }, { 0.000142947 + 0.000105992 }, { 8.65919e-05 + 0.000187041 },
{ 4.15799e-05 + 0.000184346 }, { 5.30207e-05 + 7.84921e-05 }, { 0.000158877 + -0.000128058 },
{ 0.000373956 + -0.000407954 }, { 0.000680606 + -0.000712065 }, { 0.00102929 + -0.000979604 },
{ 0.00135049 + -0.00115333 }, { 0.00157434 + -0.0011948 }, { 0.00165098 + -0.00109534 },
{ 0.00156519 + -0.000878794 }, { 0.0013399 + -0.000594285 }, { 0.00102788 + -0.00030189 },
{ 0.000694684 + -5.58912e-05 }, { 0.000399328 + 0.000109463 }
};
// as above, downsampled to 1sps + just magnitude
static std::vector<float> chan_im_resp_trunc = { 1., 0.20513351, 0.10020305, 0.11490235 };
template <typename A, typename B>
auto conv(const std::vector<A> &a, const std::vector<B> &b) -> std::unique_ptr<std::vector<A>>
{
int data_len = a.size();
int conv_len = b.size();
int conv_size = conv_len + data_len - 1;
auto retv = std::make_unique<std::vector<A>>(conv_size);
for (int i = 0; i < data_len; ++i) {
for (int j = 0; j < conv_len; ++j) {
(*retv)[i + j] += a[i] * b[j];
}
}
return retv;
}
template <typename A>
static auto conv(const A *a, int len, std::vector<float> &b)
{
std::vector<A> aa(len);
std::copy_n(a, len, aa.begin());
std::reverse(b.begin(), b.end());
return conv(aa, b);
}
template <typename A>
static auto conv(const A *a, int len, std::vector<A> &b)
{
std::vector<A> aa(len);
std::copy_n(a, len, aa.begin());
std::reverse(b.begin(), b.end());
return conv(aa, b);
}
// signalvector is owning despite claiming not to, but we can pretend, too..
static void dummy_free(void *wData){};
static void *dummy_alloc(size_t newSize)
{
return 0;
};
template <typename T>
size_t read_from_file(std::string path, std::vector<T> &outvec)
{
std::ifstream infile;
infile.open(path, std::ios::in | std::ios::binary);
if (infile.fail()) {
std::cout << " not found: " << path << std::endl;
exit(0);
}
infile.seekg(0, std::ios_base::end);
size_t fsize = infile.tellg();
auto fsize_in_T = fsize / sizeof(T);
infile.seekg(0, std::ios_base::beg);
outvec.resize(fsize_in_T);
infile.read(reinterpret_cast<char *>(&outvec[0]), fsize);
infile.close();
std::cout << "Read " << fsize << " from " << path << std::endl;
return fsize;
}
void demod_real_burst(int num = 0)
{
auto path = "./nb_chunk_tsc7.cfile";
auto bitfile = "./demodbits_tsc7.s8";
std::vector<std::complex<float>> burstdata;
std::vector<char> bitdata;
read_from_file(path, burstdata);
read_from_file(bitfile, bitdata);
// print "known good" burst bits
std::cerr << "known bits:" << std::endl;
std::cerr << std::setw(5) << 0 << " - ";
for (auto i : bitdata)
std::cout << (i > 0 ? "1" : "0");
std::cerr << std::endl;
std::cerr << "demod tests sigproclib:" << std::endl;
auto ct = CorrType::TSC;
auto delay = 0;
auto tsc = 7;
int offset = 0;
auto cplx = reinterpret_cast<complex *>(&burstdata[offset]);
auto stdcplx = reinterpret_cast<std::complex<float> *>(&burstdata[offset]);
signalVector sv(&cplx[0], 0, burstdata.size() - offset, dummy_alloc, dummy_free);
struct estim_burst_params ebp;
auto rc = detectAnyBurst(sv, tsc, BURST_THRESH, 4, ct, 40, &ebp);
auto rxBurst = std::unique_ptr<SoftVector>(demodAnyBurst(sv, (CorrType)rc, 4, &ebp));
// print osmotrx sigproclib demod result
std::cerr << std::setw(5) << int(ebp.toa) << " o ";
for (ssize_t i = 0 + delay; i < 148 + delay; i++)
std::cout << (rxBurst->bit(i) ? "1" : "0");
std::cerr << std::endl;
std::cerr << "demod test va:" << std::endl;
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
float ncmax;
char demodded_softbits[444];
// demod at known offset
{
auto inp = &stdcplx[29]; // known offset
auto normal_burst_startX = get_norm_chan_imp_resp(inp, &chan_imp_resp[0], &ncmax, tsc);
detect_burst_nb(inp, &chan_imp_resp[0], normal_burst_startX, demodded_softbits);
std::cerr << std::setw(5) << normal_burst_startX << " v ";
for (size_t i = 0; i < 148; i++)
std::cerr << (demodded_softbits[i] < 0 ? "1" : "0");
std::cerr << std::endl;
}
{
std::cerr << "-- va start offset loop --" << std::endl;
std::cerr << "offset/det offset/#errors/known^demod bits" << std::endl;
for (int i = 0; i < 34; i++) {
auto inp = &stdcplx[i];
auto conved_beg = inp;
auto me = get_norm_chan_imp_resp(conved_beg, &chan_imp_resp[0], &ncmax, tsc);
detect_burst_nb(conved_beg, &chan_imp_resp[0], me, demodded_softbits);
auto bitdiffarr = std::make_unique<char[]>(148);
for (size_t i = 0; i < 148; i++)
bitdiffarr.get()[i] = (demodded_softbits[i] < 0 ? 1 : 0) ^ (bitdata[i] > 0 ? 1 : 0);
auto ber = std::accumulate(bitdiffarr.get(), bitdiffarr.get() + 148, 0);
std::cerr << std::setw(3) << i << ": " << std::setw(3) << me << " v " << std::setw(3) << ber
<< " ";
for (size_t i = 0; i < 148; i++)
std::cerr << (bitdiffarr[i] ? "1" : "0");
std::cerr << std::endl;
// std::cerr << std::setw(4) << i << " (" << std::setw(4) << 29 - i << "):" << std::setw(4) << org
// << " " << std::setw(4) << me << " y " << std::endl;
}
}
}
auto gen_burst(CorrType t, int delay, int tsc)
{
mrv rs;
if (t == CorrType::RACH) {
rs = genRandAccessBurstx(delay, 4, tsc);
} else if (t == CorrType::TSC) {
rs = genRandNormalBurstx(tsc, 4, 0);
} else {
std::cerr << "wtf?" << std::endl;
exit(0);
}
rs.ct = t;
signalVector *burst = rs.rvbuf;
// sv_write_helper(burst, std::to_string(num));
// scaleVector(*burst, {1, 0});
const int len_in_real = burst->size() * 2;
auto cvrtbuf_tx_a = std::make_unique<short[]>(len_in_real);
auto cvrtbuf_rx_a = std::make_unique<float[]>(len_in_real);
auto rx_cfloat = reinterpret_cast<std::complex<float> *>(&cvrtbuf_rx_a[0]);
convert_float_short(cvrtbuf_tx_a.get(), (float *)burst->begin(), float(txFullScale), len_in_real);
convert_short_float(cvrtbuf_rx_a.get(), cvrtbuf_tx_a.get(), len_in_real);
for (int i = 0; i < len_in_real; i++) // scale properly!
cvrtbuf_rx_a[i] *= 1. / txFullScale;
auto conved = conv(rx_cfloat, burst->size(), chan_im_resp);
std::cerr << "-- generated " << (t == CorrType::RACH ? "RACH" : "TSC") << " burst --" << std::endl;
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << (rs.bits[i] ? "1" : "0");
std::cerr << std::endl;
delete burst;
rs.convolved = std::move(conved);
return rs;
}
void demod_generated_burst(CorrType t)
{
int tsc = 0;
int delay = 0;
auto rs = gen_burst(t, delay, tsc);
auto conved_beg = &(*rs.convolved)[0];
if (rs.ct == CorrType::RACH) {
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
float ncmax;
char demodded_softbits[444];
int normal_burst_start = 0;
normal_burst_start = get_access_imp_resp(conved_beg, &chan_imp_resp[0], &ncmax, 0);
normal_burst_start = std::max(normal_burst_start, 0);
for (int j = 0; j < 4; j++) {
for (int start_val = 0; start_val < 16; start_val++) {
auto bitdiffarr = std::make_unique<char[]>(rs.bits.size());
detect_burst_ab(conved_beg, &chan_imp_resp[0], normal_burst_start + j,
demodded_softbits, start_val);
for (size_t i = 0; i < rs.bits.size(); i++)
bitdiffarr.get()[i] = (demodded_softbits[i] < 0 ? 1 : 0) ^ rs.bits[i];
auto ber = std::accumulate(bitdiffarr.get(), bitdiffarr.get() + rs.bits.size(), 0);
std::cerr << "ber " << std::setw(4) << ber << " bo:" << std::setw(4) << j
<< " vas:" << std::setw(4) << start_val << " ";
// for (size_t i = 0; i < rs.num_bits; i++)
// std::cerr << (demodded_softbits[i] < 0 ? "1" : "0");
// std::cerr << std::endl;
// std::cerr << "d " << std::setw(4) << ber << " ";
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << (bitdiffarr.get()[i] ? "1" : "0");
std::cerr << std::endl;
// std::cerr << "v " << std::setw(4) << j << std::setw(4) << start_val << " ";
// for (size_t i = 0; i < rs.num_bits; i++)
// std::cerr << (demodded_softbits[i] < 0 ? "1" : "0");
// std::cerr << std::endl;
// std::cerr << "d " << std::setw(4) << ber << " ";
// for (size_t i = 0; i < rs.num_bits; i++)
// std::cerr << (ptr.get()[i] ? "1" : "0");
// std::cerr << std::endl;
}
}
} else {
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
float ncmax;
char demodded_softbits[444];
auto normal_burst_start = get_norm_chan_imp_resp(conved_beg, &chan_imp_resp[0], &ncmax, tsc);
detect_burst_nb(conved_beg, &chan_imp_resp[0], normal_burst_start + 0, demodded_softbits);
std::cerr << "toa " << std::setprecision(2) << normal_burst_start << std::endl;
std::cerr << "vita ";
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << (demodded_softbits[i] < 0 ? "1" : "0");
std::cerr << std::endl;
std::cerr << "diff ";
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << ((demodded_softbits[i] < 0 ? 1 : 0) ^ rs.bits[i] ? "1" : "0");
std::cerr << std::endl;
}
struct estim_burst_params ebp;
char demodded_softbits[444];
complex *rx_sigproc_cfloat = reinterpret_cast<complex *>(conved_beg);
signalVector sv(rx_sigproc_cfloat, 0, rs.convolved->size(), dummy_alloc, dummy_free);
auto rc = detectAnyBurst(sv, tsc, BURST_THRESH, 4, rs.ct, 40, &ebp);
auto rxBurst = std::unique_ptr<SoftVector>(demodAnyBurst(sv, (CorrType)rc, 4, &ebp));
std::cerr << "toa " << std::setprecision(2) << ebp.toa << std::endl;
for (ssize_t i = 0; i < delay; i++) // maybe pad rach op?
demodded_softbits[i] = 0;
for (size_t i = 0 + delay; i < rs.bits.size() + delay; i++)
demodded_softbits[i] = (rxBurst->bit(i) ? 1 : 0);
std::cerr << "sigp ";
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << (demodded_softbits[i] ? "1" : "0");
std::cerr << std::endl;
std::cerr << "diff ";
for (size_t i = 0; i < rs.bits.size(); i++)
std::cerr << (demodded_softbits[i] ^ rs.bits[i] ? "1" : "0");
std::cerr << std::endl;
}
void demod_test_offsets()
{
const int tsc = 0;
const int delaybuffer_realoffset = 100;
{
auto rs = gen_burst(CorrType::RACH, 0, tsc);
typeof(*rs.convolved) delay_buffer(rs.convolved->size() * 2); // plenty of space..
for (int delay = -10; delay < 60; delay++) {
std::fill(delay_buffer.begin(), delay_buffer.end(), 0);
std::copy(rs.convolved->begin(), rs.convolved->end(),
delay_buffer.begin() + delaybuffer_realoffset + delay);
auto conved_beg = &delay_buffer[delaybuffer_realoffset];
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
float ncmax;
auto va_burst_start = get_access_imp_resp(conved_beg, &chan_imp_resp[0], &ncmax, 60);
complex *rx_sigproc_cfloat = reinterpret_cast<complex *>(conved_beg);
struct estim_burst_params ebp;
signalVector sv(rx_sigproc_cfloat, 0, rs.convolved->size(), dummy_alloc, dummy_free);
detectAnyBurst(sv, tsc, BURST_THRESH, 4, rs.ct, 60, &ebp);
std::cerr << "delay:" << std::setw(3) << std::setprecision(2) << delay;
std::cerr << " va: " << std::setw(3) << std::setprecision(2) << va_burst_start;
std::cerr << " sg: " << std::setw(3) << std::setprecision(2) << ebp.toa;
std::cerr << " d: " << std::setw(3) << std::setprecision(2) << (ebp.toa * 4) - va_burst_start;
std::cerr << " ! " << float(va_burst_start + 13) / 4 << std::endl;
}
}
{
auto rs = gen_burst(CorrType::TSC, 0, tsc);
typeof(*rs.convolved) delay_buffer(rs.convolved->size() * 2); // plenty of space..
for (int delay = -10; delay < 10; delay++) {
std::fill(delay_buffer.begin(), delay_buffer.end(), 0);
std::copy(rs.convolved->begin(), rs.convolved->end(),
delay_buffer.begin() + delaybuffer_realoffset + delay);
auto conved_beg = &delay_buffer[delaybuffer_realoffset];
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
float ncmax;
auto va_burst_start = get_norm_chan_imp_resp(conved_beg, &chan_imp_resp[0], &ncmax, tsc);
complex *rx_sigproc_cfloat = reinterpret_cast<complex *>(conved_beg);
struct estim_burst_params ebp;
signalVector sv(rx_sigproc_cfloat, 0, rs.convolved->size(), dummy_alloc, dummy_free);
detectAnyBurst(sv, tsc, BURST_THRESH, 4, rs.ct, 60, &ebp);
std::cerr << "delay:" << std::setw(3) << std::setprecision(2) << delay;
std::cerr << " va: " << std::setw(3) << std::setprecision(2) << va_burst_start;
std::cerr << " sg: " << std::setw(3) << std::setprecision(2) << ebp.toa;
std::cerr << " d: " << std::setw(3) << std::setprecision(2) << (ebp.toa * 4) - va_burst_start;
std::cerr << " ! " << float(va_burst_start + 19) / 4 << std::endl;
}
}
}
int main()
{
convolve_init();
convert_init();
sigProcLibSetup();
initvita();
for (int i = 0; i < 1; i++) {
demod_real_burst(i);
demod_generated_burst(CorrType::RACH);
demod_generated_burst(CorrType::TSC);
demod_test_offsets();
}
}

Binary file not shown.

Binary file not shown.