mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-04 14:13:29 +00:00
Compare commits
3 Commits
1.7.1
...
Hoernchen/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa820c2ac1 | ||
|
|
db24660ac0 | ||
|
|
47d0d93d9e |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
|||||||
open_collective: osmocom
|
|
||||||
@@ -28,7 +28,7 @@ std::vector<std::string> comma_delimited_to_vector(const char* opt)
|
|||||||
{
|
{
|
||||||
std::string substr;
|
std::string substr;
|
||||||
getline(ss, substr, ',');
|
getline(ss, substr, ',');
|
||||||
result.push_back(std::move(substr));
|
result.push_back(substr);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ EXTRA_DIST = \
|
|||||||
LEGAL \
|
LEGAL \
|
||||||
COPYING \
|
COPYING \
|
||||||
README.md \
|
README.md \
|
||||||
|
contrib/osmo-trx.spec.in \
|
||||||
debian \
|
debian \
|
||||||
git-version-gen \
|
git-version-gen \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -4,17 +4,17 @@ About OsmoTRX
|
|||||||
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
||||||
physical layer of a BTS comprising the following 3GPP specifications:
|
physical layer of a BTS comprising the following 3GPP specifications:
|
||||||
|
|
||||||
* TS 05.01 *Physical layer on the radio path*
|
* TS 05.01 "Physical layer on the radio path"
|
||||||
* TS 05.02 *Multiplexing and Multiple Access on the Radio Path*
|
* TS 05.02 "Multiplexing and Multiple Access on the Radio Path"
|
||||||
* TS 05.04 *Modulation*
|
* TS 05.04 "Modulation"
|
||||||
* TS 05.10 *Radio subsystem synchronization*
|
* TS 05.10 "Radio subsystem synchronization"
|
||||||
|
|
||||||
OsmoTRX is originally based on the transceiver code from the
|
OsmoTRX is originally based on the transceiver code from the
|
||||||
[OpenBTS](https://osmocom.org/projects/osmobts/wiki/OpenBTS) project, but setup
|
[OpenBTS](https://osmocom.org/projects/osmobts/wiki/OpenBTS) project, but setup
|
||||||
to operate independently with the purpose of using with non-OpenBTS software and
|
to operate independently with the purpose of using with non-OpenBTS software and
|
||||||
projects, specifically within the Osmocom stack. Used together with
|
projects, specifically within the Osmocom stack. Used together with
|
||||||
[OsmoBTS](https://osmocom.org/projects/osmobts/wiki) you can get a pretty
|
[OsmoBTS](https://osmocom.org/projects/osmobts/wiki) you can get a pretty
|
||||||
standard GSM/GPRS/EGPRS BTS with Abis interface as per the relevant 3GPP specifications.
|
standard GSM BTS with Abis interface as per the relevant 3GPP specifications.
|
||||||
|
|
||||||
Homepage
|
Homepage
|
||||||
--------
|
--------
|
||||||
@@ -27,7 +27,7 @@ GIT Repository
|
|||||||
|
|
||||||
You can clone from the official osmo-trx.git repository using
|
You can clone from the official osmo-trx.git repository using
|
||||||
|
|
||||||
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-trx`
|
||||||
|
|
||||||
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-trx>
|
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-trx>
|
||||||
|
|
||||||
@@ -39,13 +39,6 @@ also available online for each of the sub-libraries at User Manual for OsmoTRX
|
|||||||
can be generated during the build process, and is also available online at
|
can be generated during the build process, and is also available online at
|
||||||
<https://ftp.osmocom.org/docs/latest/osmotrx-usermanual.pdf>.
|
<https://ftp.osmocom.org/docs/latest/osmotrx-usermanual.pdf>.
|
||||||
|
|
||||||
Forum
|
|
||||||
-----
|
|
||||||
|
|
||||||
We welcome any osmo-trx related discussions in the
|
|
||||||
[Cellular Network Infrastructure -> 2 RAN (GERAN)](https://discourse.osmocom.org/c/cni/geran)
|
|
||||||
section of the osmocom discourse (web based Forum).
|
|
||||||
|
|
||||||
Mailing List
|
Mailing List
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@@ -57,20 +50,13 @@ Please observe the [Osmocom Mailing List
|
|||||||
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
|
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
|
||||||
when posting.
|
when posting.
|
||||||
|
|
||||||
Issue Tracker
|
|
||||||
-------------
|
|
||||||
|
|
||||||
We use the [issue tracker of the osmo-trx project on osmocom.org](https://osmocom.org/projects/osmotrx/issues) for
|
|
||||||
tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
|
|
||||||
us out by resolving existing issues.
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Our coding standards are described at
|
Our coding standards are described at
|
||||||
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
|
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
|
||||||
|
|
||||||
We use a Gerrit based patch submission/review process for managing contributions.
|
We us a gerrit based patch submission/review process for managing contributions.
|
||||||
Please see <https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit>
|
Please see <https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit>
|
||||||
for more details
|
for more details
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
|
||||||
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
|
|
||||||
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
|
||||||
# LIBVERSION=c:r:a
|
|
||||||
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
|
|
||||||
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
|
|
||||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
|
||||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
|
||||||
#library what description / commit summary line
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ MS_UPPER_SRC = \
|
|||||||
ms/ms_upper.cpp \
|
ms/ms_upper.cpp \
|
||||||
ms/l1ctl_server.c \
|
ms/l1ctl_server.c \
|
||||||
ms/logging.c \
|
ms/logging.c \
|
||||||
|
ms/mssdr_vty.c \
|
||||||
ms/l1ctl_server_cb.cpp \
|
ms/l1ctl_server_cb.cpp \
|
||||||
ms/ms_trxcon_if.cpp
|
ms/ms_trxcon_if.cpp
|
||||||
|
|
||||||
@@ -110,6 +111,7 @@ noinst_HEADERS += \
|
|||||||
ms/itrq.h \
|
ms/itrq.h \
|
||||||
ms/sch.h \
|
ms/sch.h \
|
||||||
ms/threadpool.h \
|
ms/threadpool.h \
|
||||||
|
ms/mssdr_vty.h \
|
||||||
grgsm_vitac/viterbi_detector.h \
|
grgsm_vitac/viterbi_detector.h \
|
||||||
grgsm_vitac/constants.h \
|
grgsm_vitac/constants.h \
|
||||||
grgsm_vitac/grgsm_vitac.h
|
grgsm_vitac/grgsm_vitac.h
|
||||||
@@ -127,16 +129,16 @@ osmo_trx_uhd_LDADD = \
|
|||||||
$(UHD_LIBS)
|
$(UHD_LIBS)
|
||||||
osmo_trx_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
|
osmo_trx_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
|
||||||
|
|
||||||
#if ENABLE_MS_TRX
|
if ENABLE_MS_TRX
|
||||||
#bin_PROGRAMS += osmo-trx-ms-uhd
|
bin_PROGRAMS += osmo-trx-ms-uhd
|
||||||
#osmo_trx_ms_uhd_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
|
osmo_trx_ms_uhd_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
|
||||||
#osmo_trx_ms_uhd_LDADD = \
|
osmo_trx_ms_uhd_LDADD = \
|
||||||
# $(builddir)/device/uhd/libdevice.la \
|
$(builddir)/device/uhd/libdevice.la \
|
||||||
# $(COMMON_LDADD) \
|
$(COMMON_LDADD) \
|
||||||
# $(UHD_LIBS) \
|
$(UHD_LIBS) \
|
||||||
# $(TRXCON_LDADD)
|
$(TRXCON_LDADD)
|
||||||
#osmo_trx_ms_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS) -DBUILDUHD
|
osmo_trx_ms_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS) -DBUILDUHD
|
||||||
#endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if DEVICE_USRP1
|
if DEVICE_USRP1
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
#include <libbladeRF.h>
|
#include <libbladeRF.h>
|
||||||
#include <Timeval.h>
|
#include <Timeval.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
extern "C" {
|
||||||
|
#include "mssdr_vty.h"
|
||||||
|
}
|
||||||
|
|
||||||
const size_t BLADE_BUFFER_SIZE = 1024 * 1;
|
const size_t BLADE_BUFFER_SIZE = 1024 * 1;
|
||||||
const size_t BLADE_NUM_BUFFERS = 32 * 1;
|
const size_t BLADE_NUM_BUFFERS = 32 * 1;
|
||||||
@@ -195,8 +198,8 @@ struct blade_hw {
|
|||||||
using tx_buf_q_type = spsc_cond_timeout<BLADE_NUM_BUFFERS, dev_buf_t *, true, false>;
|
using tx_buf_q_type = spsc_cond_timeout<BLADE_NUM_BUFFERS, dev_buf_t *, true, false>;
|
||||||
const unsigned int rxFullScale, txFullScale;
|
const unsigned int rxFullScale, txFullScale;
|
||||||
const int rxtxdelay;
|
const int rxtxdelay;
|
||||||
|
bool use_agc;
|
||||||
|
|
||||||
float rxgain, txgain;
|
|
||||||
static std::atomic<bool> stop_lower_threads_flag;
|
static std::atomic<bool> stop_lower_threads_flag;
|
||||||
double rxfreq_cache, txfreq_cache;
|
double rxfreq_cache, txfreq_cache;
|
||||||
|
|
||||||
@@ -205,9 +208,13 @@ struct blade_hw {
|
|||||||
int rx_freq;
|
int rx_freq;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int bandwidth;
|
int bandwidth;
|
||||||
|
float rxgain;
|
||||||
|
float txgain;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ms_trx_config() : tx_freq(881e6), rx_freq(926e6), sample_rate(((1625e3 / 6) * 4)), bandwidth(1e6)
|
ms_trx_config()
|
||||||
|
: tx_freq(881e6), rx_freq(926e6), sample_rate(((1625e3 / 6) * 4)), bandwidth(1e6), rxgain(30),
|
||||||
|
txgain(30)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
} cfg;
|
} cfg;
|
||||||
@@ -223,10 +230,14 @@ struct blade_hw {
|
|||||||
{
|
{
|
||||||
close_device();
|
close_device();
|
||||||
}
|
}
|
||||||
blade_hw()
|
blade_hw(struct mssdr_cfg *cfgdata)
|
||||||
: rxFullScale(2047), txFullScale(2047), rxtxdelay(-60), rxgain(30), txgain(30), rxfreq_cache(0),
|
: rxFullScale(2047), txFullScale(2047), rxtxdelay(-60), use_agc(cfgdata->use_agc), rxfreq_cache(0),
|
||||||
txfreq_cache(0)
|
txfreq_cache(0)
|
||||||
{
|
{
|
||||||
|
cfg.tx_freq = cfgdata->overrides.ul_freq;
|
||||||
|
cfg.rx_freq = cfgdata->overrides.dl_freq;
|
||||||
|
cfg.rxgain = cfgdata->overrides.dl_gain;
|
||||||
|
cfg.txgain = cfgdata->overrides.ul_gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_device()
|
void close_device()
|
||||||
@@ -251,6 +262,7 @@ struct blade_hw {
|
|||||||
int init_device(bh_fn_t rxh, bh_fn_t txh)
|
int init_device(bh_fn_t rxh, bh_fn_t txh)
|
||||||
{
|
{
|
||||||
struct bladerf_rational_rate rate = { 0, static_cast<uint64_t>((1625e3 * 4)) * 64, 6 * 64 }, actual;
|
struct bladerf_rational_rate rate = { 0, static_cast<uint64_t>((1625e3 * 4)) * 64, 6 * 64 }, actual;
|
||||||
|
std::cerr << "cfg: ul " << cfg.tx_freq << " dl " << cfg.rx_freq << std::endl;
|
||||||
|
|
||||||
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
|
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
|
||||||
bladerf_set_usb_reset_on_open(true);
|
bladerf_set_usb_reset_on_open(true);
|
||||||
@@ -294,9 +306,10 @@ struct blade_hw {
|
|||||||
blade_check(bladerf_set_bandwidth, dev, BLADERF_CHANNEL_TX(0), (bladerf_bandwidth)cfg.bandwidth,
|
blade_check(bladerf_set_bandwidth, dev, BLADERF_CHANNEL_TX(0), (bladerf_bandwidth)cfg.bandwidth,
|
||||||
(bladerf_bandwidth *)NULL);
|
(bladerf_bandwidth *)NULL);
|
||||||
|
|
||||||
blade_check(bladerf_set_gain_mode, dev, BLADERF_CHANNEL_RX(0), BLADERF_GAIN_MGC);
|
blade_check(bladerf_set_gain_mode, dev, BLADERF_CHANNEL_RX(0),
|
||||||
setRxGain(rxgain, 0);
|
use_agc ? BLADERF_GAIN_AUTOMATIC : BLADERF_GAIN_MGC);
|
||||||
setTxGain(txgain, 0);
|
setRxGain(cfg.rxgain, 0);
|
||||||
|
setTxGain(cfg.txgain, 0);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
bladerf_set_stream_timeout(dev, BLADERF_TX, 10);
|
bladerf_set_stream_timeout(dev, BLADERF_TX, 10);
|
||||||
@@ -350,7 +363,7 @@ struct blade_hw {
|
|||||||
|
|
||||||
double setRxGain(double dB, size_t chan = 0)
|
double setRxGain(double dB, size_t chan = 0)
|
||||||
{
|
{
|
||||||
rxgain = dB;
|
cfg.rxgain = dB;
|
||||||
msleep(15);
|
msleep(15);
|
||||||
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_RX(0), (bladerf_gain)dB);
|
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_RX(0), (bladerf_gain)dB);
|
||||||
msleep(15);
|
msleep(15);
|
||||||
@@ -358,7 +371,7 @@ struct blade_hw {
|
|||||||
};
|
};
|
||||||
double setTxGain(double dB, size_t chan = 0)
|
double setTxGain(double dB, size_t chan = 0)
|
||||||
{
|
{
|
||||||
txgain = dB;
|
cfg.txgain = dB;
|
||||||
msleep(15);
|
msleep(15);
|
||||||
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_TX(0), (bladerf_gain)dB);
|
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_TX(0), (bladerf_gain)dB);
|
||||||
msleep(15);
|
msleep(15);
|
||||||
|
|||||||
@@ -217,8 +217,6 @@ class time_keeper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using ts_hitter_q_t = spsc_cond<64, GSM::Time, true, false>;
|
|
||||||
|
|
||||||
// used to globally initialize the sched/hw information
|
// used to globally initialize the sched/hw information
|
||||||
struct sched_hw_info {
|
struct sched_hw_info {
|
||||||
int hw_cpus;
|
int hw_cpus;
|
||||||
@@ -239,7 +237,7 @@ struct ms_trx : public BASET, public sched_hw_info {
|
|||||||
unsigned int mTSC;
|
unsigned int mTSC;
|
||||||
unsigned int mBSIC;
|
unsigned int mBSIC;
|
||||||
int timing_advance;
|
int timing_advance;
|
||||||
bool do_auto_gain;
|
bool use_va;
|
||||||
|
|
||||||
pthread_t lower_rx_task;
|
pthread_t lower_rx_task;
|
||||||
pthread_t lower_tx_task;
|
pthread_t lower_tx_task;
|
||||||
@@ -276,8 +274,8 @@ struct ms_trx : public BASET, public sched_hw_info {
|
|||||||
void *tx_cb();
|
void *tx_cb();
|
||||||
void maybe_update_gain(one_burst &brst);
|
void maybe_update_gain(one_burst &brst);
|
||||||
|
|
||||||
ms_trx()
|
ms_trx(struct mssdr_cfg *cfgdata)
|
||||||
: mTSC(0), mBSIC(0), timing_advance(0), do_auto_gain(false), rxqueue(),
|
: BASET(cfgdata), mTSC(0), mBSIC(0), timing_advance(0), use_va(cfgdata->use_va), rxqueue(),
|
||||||
first_sch_buf(new blade_sample_type[SCH_LEN_SPS]),
|
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),
|
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 }, upper_is_ready(false)
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ void ms_trx::maybe_update_gain(one_burst &brst)
|
|||||||
runmean = gain_check ? (runmean * (gain_check + 2) - 1 + sum) / (gain_check + 2) : sum;
|
runmean = gain_check ? (runmean * (gain_check + 2) - 1 + sum) / (gain_check + 2) : sum;
|
||||||
|
|
||||||
if (gain_check == avgburst_num - 1) {
|
if (gain_check == avgburst_num - 1) {
|
||||||
DBGLG2() << "\x1B[32m #RXG \033[0m" << rxgain << " " << runmean << " " << sum << std::endl;
|
DBGLG2() << "\x1B[32m #RXG \033[0m" << cfg.rxgain << " " << runmean << " " << sum << std::endl;
|
||||||
auto gainoffset = runmean < (rxFullScale / 4 ? 4 : 2);
|
auto gainoffset = runmean < (rxFullScale / 4 ? 4 : 2);
|
||||||
gainoffset = runmean < (rxFullScale / 2 ? 2 : 1);
|
gainoffset = runmean < (rxFullScale / 2 ? 2 : 1);
|
||||||
float newgain = runmean < rx_max_cutoff ? rxgain + gainoffset : rxgain - gainoffset;
|
float newgain = runmean < rx_max_cutoff ? cfg.rxgain + gainoffset : cfg.rxgain - gainoffset;
|
||||||
// FIXME: gian cutoff
|
// FIXME: gian cutoff
|
||||||
if (newgain != rxgain && newgain <= 60) {
|
if (newgain != cfg.rxgain && newgain <= 60) {
|
||||||
auto gain_fun = [this, newgain] { setRxGain(newgain); };
|
auto gain_fun = [this, newgain] { setRxGain(newgain); };
|
||||||
worker_thread.add_task(gain_fun);
|
worker_thread.add_task(gain_fun);
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ bool ms_trx::handle_sch_or_nb()
|
|||||||
while (upper_is_ready && !rxqueue.spsc_push(&brst))
|
while (upper_is_ready && !rxqueue.spsc_push(&brst))
|
||||||
;
|
;
|
||||||
|
|
||||||
if (do_auto_gain)
|
if (!use_agc)
|
||||||
maybe_update_gain(brst);
|
maybe_update_gain(brst);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -158,24 +158,24 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
|
|||||||
const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
|
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;
|
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));
|
memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
|
||||||
#if 1
|
if (use_va) {
|
||||||
const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
|
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);
|
const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
|
||||||
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
||||||
int start;
|
int start;
|
||||||
convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
|
convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
|
||||||
if (is_first_sch_acq) {
|
if (is_first_sch_acq) {
|
||||||
float max_corr = 0;
|
float max_corr = 0;
|
||||||
start = get_sch_buffer_chan_imp_resp(ss, &channel_imp_resp[0], buf_len, &max_corr);
|
start = get_sch_buffer_chan_imp_resp(ss, &channel_imp_resp[0], buf_len, &max_corr);
|
||||||
} else {
|
} else {
|
||||||
start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
|
start = get_sch_chan_imp_resp(ss, &channel_imp_resp[0]);
|
||||||
start = start < 39 ? start : 39;
|
start = start < 39 ? start : 39;
|
||||||
start = start > -39 ? start : -39;
|
start = start > -39 ? start : -39;
|
||||||
}
|
}
|
||||||
detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
|
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);
|
auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
|
||||||
#if 0
|
#if 0 // useful to debug offset shifts
|
||||||
auto burst = new signalVector(buf_len, 50);
|
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;
|
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;
|
struct estim_burst_params ebp;
|
||||||
@@ -189,113 +189,114 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
|
|||||||
std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
|
std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
|
||||||
std::cerr << "voffs: " << start << " " << sch_decode_success << std::endl;
|
std::cerr << "voffs: " << start << " " << sch_decode_success << std::endl;
|
||||||
#endif
|
#endif
|
||||||
if (sch_decode_success) {
|
if (sch_decode_success) {
|
||||||
const auto ts_offset_symb = 4;
|
const auto ts_offset_symb = 4;
|
||||||
if (is_first_sch_acq) {
|
if (is_first_sch_acq) {
|
||||||
// update ts to first sample in sch buffer, to allow delay calc for current ts
|
// 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;
|
first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
|
||||||
} else if (abs(start) > 1) {
|
} else if (abs(start) > 1) {
|
||||||
// continuous sch tracking, only update if off too much
|
// continuous sch tracking, only update if off too much
|
||||||
temp_ts_corr_offset += -start;
|
temp_ts_corr_offset += -start;
|
||||||
std::cerr << "offs: " << start << " " << temp_ts_corr_offset << std::endl;
|
std::cerr << "offs: " << start << " " << temp_ts_corr_offset << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " "
|
||||||
|
<< current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
|
const auto ts_offset_symb = 4;
|
||||||
<< ":" << current_gsm_time.TN() << std::endl;
|
auto burst = new signalVector(buf_len, 50);
|
||||||
}
|
const auto corr_type =
|
||||||
#else
|
is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
|
||||||
const auto ts_offset_symb = 4;
|
struct estim_burst_params ebp;
|
||||||
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
|
// scale like uhd, +-2k -> +-32k
|
||||||
convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
|
convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
|
||||||
|
|
||||||
auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
|
auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
|
||||||
|
|
||||||
int howmuchdelay = ebp.toa * 4;
|
int howmuchdelay = ebp.toa * 4;
|
||||||
|
|
||||||
if (!rv) {
|
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;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct estim_burst_params ebp2;
|
SoftVector *bits;
|
||||||
// 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) {
|
if (is_first_sch_acq) {
|
||||||
// update ts to first sample in sch buffer, to allow delay calc for current ts
|
// can't be legit with a buf size spanning _at least_ one SCH but delay that implies partial sch burst
|
||||||
first_sch_ts_start = first_sch_buf_rcv_ts + howmuchdelay - (ts_offset_symb * 4);
|
if (howmuchdelay < 0 || (buf_len - howmuchdelay) < ONE_TS_BURST_LEN) {
|
||||||
} else {
|
delete burst;
|
||||||
// continuous sch tracking, only update if off too much
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto a = gsm_sch_check_fn(current_gsm_time_updated.FN() - 1);
|
delete burst;
|
||||||
auto b = gsm_sch_check_fn(current_gsm_time_updated.FN());
|
|
||||||
auto c = gsm_sch_check_fn(current_gsm_time_updated.FN() + 1);
|
// clamp to +-1.5 because +-127 softbits scaled by 64 after -0.5 can be at most +-1.5
|
||||||
DBGLG() << "L SCH : Timing offset " << rv << " " << ebp.toa << " " << a << b << c << "fn "
|
clamp_array(bits->begin(), 148, 1.5f);
|
||||||
<< current_gsm_time_updated.FN() << ":" << current_gsm_time_updated.TN() << std::endl;
|
|
||||||
|
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;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,12 +334,12 @@ SCH_STATE ms_trx::search_for_sch(dev_buf_t *rcd)
|
|||||||
float sum = normed_abs_sum(first_sch_buf, SCH_LEN_SPS);
|
float sum = normed_abs_sum(first_sch_buf, SCH_LEN_SPS);
|
||||||
|
|
||||||
//FIXME: arbitrary value, gain cutoff
|
//FIXME: arbitrary value, gain cutoff
|
||||||
if (sum > target_val || rxgain >= 60) // enough ?
|
if (sum > target_val || cfg.rxgain >= 60) // enough ?
|
||||||
sch_thread_done = this->handle_sch(true);
|
sch_thread_done = this->handle_sch(true);
|
||||||
else {
|
else {
|
||||||
std::cerr << "\x1B[32m #RXG \033[0m gain " << rxgain << " -> " << rxgain + 4
|
std::cerr << "\x1B[32m #RXG \033[0m gain " << cfg.rxgain << " -> " << cfg.rxgain + 4
|
||||||
<< " sample avg:" << sum << " target: >=" << target_val << std::endl;
|
<< " sample avg:" << sum << " target: >=" << target_val << std::endl;
|
||||||
setRxGain(rxgain + 4);
|
setRxGain(cfg.rxgain + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sch_thread_done)
|
if (!sch_thread_done)
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ struct internal_q_tx_buf {
|
|||||||
memcpy(buf, (void *)br->burst, br->burst_len);
|
memcpy(buf, (void *)br->burst, br->burst_len);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
using tx_queue_t = spsc_cond<8 * 1, internal_q_tx_buf, true, false>;
|
using tx_queue_t = spsc_cond_timeout<8 * 1, internal_q_tx_buf, true, false>;
|
||||||
using cmd_queue_t = spsc_cond_timeout<8 * 1, trxcon_phyif_cmd, true, false>;
|
using cmd_queue_t = spsc_cond_timeout<8 * 1, trxcon_phyif_cmd, true, false>;
|
||||||
using cmdr_queue_t = spsc_cond<8 * 1, trxcon_phyif_rsp, false, false>;
|
using cmdr_queue_t = spsc_cond_timeout<8 * 1, trxcon_phyif_rsp, false, false>;
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
|
|||||||
const auto zero_pad_len = 40; // give the VA some runway for misaligned bursts
|
const auto zero_pad_len = 40; // give the VA some runway for misaligned bursts
|
||||||
const auto workbuf_size = zero_pad_len + ONE_TS_BURST_LEN + zero_pad_len;
|
const auto workbuf_size = zero_pad_len + ONE_TS_BURST_LEN + zero_pad_len;
|
||||||
static complex workbuf[workbuf_size];
|
static complex workbuf[workbuf_size];
|
||||||
|
static int32_t meas_p, meas_rssi;
|
||||||
|
|
||||||
static signalVector sv(workbuf, zero_pad_len, ONE_TS_BURST_LEN, static_alloc, static_free);
|
static signalVector sv(workbuf, zero_pad_len, ONE_TS_BURST_LEN, static_alloc, static_free);
|
||||||
one_burst e;
|
one_burst e;
|
||||||
@@ -183,8 +184,11 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
|
|||||||
trxcon_phyif_rtr_ind i = { static_cast<uint32_t>(wTime.FN()), static_cast<uint8_t>(wTime.TN()) };
|
trxcon_phyif_rtr_ind i = { static_cast<uint32_t>(wTime.FN()), static_cast<uint8_t>(wTime.TN()) };
|
||||||
trxcon_phyif_rtr_rsp r = {};
|
trxcon_phyif_rtr_rsp r = {};
|
||||||
trxcon_phyif_handle_rtr_ind(g_trxcon, &i, &r);
|
trxcon_phyif_handle_rtr_ind(g_trxcon, &i, &r);
|
||||||
if (!(r.flags & TRXCON_PHYIF_RTR_F_ACTIVE))
|
if (!(r.flags & TRXCON_PHYIF_RTR_F_ACTIVE)) {
|
||||||
|
bladerf_get_rfic_rssi(dev, 0, &meas_p, &meas_rssi);
|
||||||
|
// std::cerr << "G : \x1B[31m rx fail \033[0m @:" << meas_rssi << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_fcch) {
|
if (is_fcch) {
|
||||||
// return trash
|
// return trash
|
||||||
@@ -199,77 +203,75 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
if (use_va) {
|
||||||
convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
|
convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
|
||||||
|
|
||||||
pow = energyDetect(sv, 20 * 4 /*sps*/);
|
pow = energyDetect(sv, 20 * 4 /*sps*/);
|
||||||
if (pow < -1) {
|
if (pow < -1) {
|
||||||
LOG(ALERT) << "Received empty burst";
|
LOG(ALERT) << "Received empty burst";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
avg = sqrt(pow);
|
avg = sqrt(pow);
|
||||||
{
|
{
|
||||||
float ncmax;
|
float ncmax;
|
||||||
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
||||||
auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, mTSC);
|
auto normal_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp[0], &ncmax, mTSC);
|
||||||
#ifdef DBGXX
|
#ifdef DBGXX
|
||||||
float dcmax;
|
float dcmax;
|
||||||
std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
|
std::complex<float> chan_imp_resp2[CHAN_IMP_RESP_LENGTH * d_OSR];
|
||||||
auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
|
auto dummy_burst_start = get_norm_chan_imp_resp(ss, &chan_imp_resp2[0], &dcmax, TS_DUMMY);
|
||||||
auto is_nb = ncmax > dcmax;
|
auto is_nb = ncmax > dcmax;
|
||||||
// DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start
|
// DBGLG() << " U " << (is_nb ? "NB" : "DB") << "@ o nb: " << normal_burst_start
|
||||||
// << " o db: " << dummy_burst_start << std::endl;
|
// << " o db: " << dummy_burst_start << std::endl;
|
||||||
#endif
|
#endif
|
||||||
normal_burst_start = normal_burst_start < 39 ? normal_burst_start : 39;
|
normal_burst_start = normal_burst_start < 39 ? normal_burst_start : 39;
|
||||||
normal_burst_start = normal_burst_start > -39 ? normal_burst_start : -39;
|
normal_burst_start = normal_burst_start > -39 ? normal_burst_start : -39;
|
||||||
#ifdef DBGXX
|
#ifdef DBGXX
|
||||||
// fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
|
// fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
|
||||||
// if (is_nb)
|
// if (is_nb)
|
||||||
#endif
|
#endif
|
||||||
detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
|
detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
|
||||||
#ifdef DBGXX
|
#ifdef DBGXX
|
||||||
// else
|
// else
|
||||||
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
|
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
|
||||||
#endif
|
#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;
|
||||||
}
|
}
|
||||||
#else
|
RSSI = meas_rssi; // (int)floor(20.0 * log10(rxFullScale / avg));
|
||||||
|
|
||||||
// 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...
|
// FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
|
||||||
timingOffset = (int)round(0);
|
timingOffset = (int)round(0);
|
||||||
|
|
||||||
@@ -419,13 +421,13 @@ bool upper_trx::driveControl()
|
|||||||
r.param.measure.band_arfcn = cmd.param.measure.band_arfcn;
|
r.param.measure.band_arfcn = cmd.param.measure.band_arfcn;
|
||||||
// FIXME: do we want to measure anything, considering the transceiver just syncs by.. syncing?
|
// FIXME: do we want to measure anything, considering the transceiver just syncs by.. syncing?
|
||||||
r.param.measure.dbm = -80;
|
r.param.measure.dbm = -80;
|
||||||
tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
|
// tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
|
||||||
tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
|
// tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
|
||||||
cmdq_from_phy.spsc_push(&r);
|
cmdq_from_phy.spsc_push(&r);
|
||||||
break;
|
break;
|
||||||
case TRXCON_PHYIF_CMDT_SETFREQ_H0:
|
case TRXCON_PHYIF_CMDT_SETFREQ_H0:
|
||||||
tuneRx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 0) * 1000 * 100);
|
// tuneRx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 0) * 1000 * 100);
|
||||||
tuneTx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 1) * 1000 * 100);
|
// tuneTx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 1) * 1000 * 100);
|
||||||
break;
|
break;
|
||||||
case TRXCON_PHYIF_CMDT_SETFREQ_H1:
|
case TRXCON_PHYIF_CMDT_SETFREQ_H1:
|
||||||
break;
|
break;
|
||||||
@@ -456,6 +458,12 @@ void sighandler(int sigset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/vty/command.h>
|
||||||
|
#include <osmocom/vty/logging.h>
|
||||||
|
#include "mssdr_vty.h"
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
auto tall_trxcon_ctx = talloc_init("trxcon context");
|
auto tall_trxcon_ctx = talloc_init("trxcon context");
|
||||||
@@ -476,6 +484,41 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
osmo_fsm_log_timeouts(true);
|
osmo_fsm_log_timeouts(true);
|
||||||
|
|
||||||
|
auto g_mssdr_ctx = vty_mssdr_ctx_alloc(tall_trxcon_ctx);
|
||||||
|
vty_init(&g_mssdr_vty_info);
|
||||||
|
logging_vty_add_cmds();
|
||||||
|
mssdr_vty_init(g_mssdr_ctx);
|
||||||
|
|
||||||
|
const char *home_dir = getenv("HOME");
|
||||||
|
if (!home_dir)
|
||||||
|
home_dir = "~";
|
||||||
|
auto config_file = talloc_asprintf(tall_trxcon_ctx, "%s/%s", home_dir, ".osmocom/bb/mssdr.cfg");
|
||||||
|
|
||||||
|
int rc = vty_read_config_file(config_file, NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
// OSMO_ASSERT(l23_app_info.vty_info != NULL);
|
||||||
|
// l23_app_info.vty_info->tall_ctx = l23_ctx;
|
||||||
|
|
||||||
|
// vty_init(l23_app_info.vty_info);
|
||||||
|
// logging_vty_add_cmds();
|
||||||
|
|
||||||
|
// if (l23_app_info.vty_init != NULL)
|
||||||
|
// l23_app_info.vty_init();
|
||||||
|
// if (config_file) {
|
||||||
|
// LOGP(DLGLOBAL, LOGL_INFO, "Using configuration from '%s'\n", config_file);
|
||||||
|
// l23_vty_reading = true;
|
||||||
|
// rc = vty_read_config_file(config_file, NULL);
|
||||||
|
// l23_vty_reading = false;
|
||||||
|
// if (rc < 0) {
|
||||||
|
// LOGP(DLGLOBAL, LOGL_FATAL,
|
||||||
|
// "Failed to parse the configuration file '%s'\n", config_file);
|
||||||
|
// return rc;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
g_trxcon = trxcon_inst_alloc(tall_trxcon_ctx, 0);
|
g_trxcon = trxcon_inst_alloc(tall_trxcon_ctx, 0);
|
||||||
g_trxcon->gsmtap = nullptr;
|
g_trxcon->gsmtap = nullptr;
|
||||||
g_trxcon->phyif = nullptr;
|
g_trxcon->phyif = nullptr;
|
||||||
@@ -487,8 +530,7 @@ int main(int argc, char *argv[])
|
|||||||
initvita();
|
initvita();
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
auto trx = new upper_trx();
|
auto trx = new upper_trx(&g_mssdr_ctx->cfg);
|
||||||
trx->do_auto_gain = true;
|
|
||||||
|
|
||||||
status = trx->init_dev_and_streams();
|
status = trx->init_dev_and_streams();
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
|||||||
@@ -44,5 +44,6 @@ class upper_trx : public ms_trx {
|
|||||||
void driveReceiveFIFO();
|
void driveReceiveFIFO();
|
||||||
void driveTx();
|
void driveTx();
|
||||||
|
|
||||||
upper_trx() : mOn(false){};
|
upper_trx() = delete;
|
||||||
|
explicit upper_trx(struct mssdr_cfg *cfgdata) : ms_trx(cfgdata), mOn(false){};
|
||||||
};
|
};
|
||||||
|
|||||||
264
Transceiver52M/ms/mssdr_vty.c
Normal file
264
Transceiver52M/ms/mssdr_vty.c
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* (C) 2024 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 <osmocom/vty/command.h>
|
||||||
|
#include <osmocom/vty/logging.h>
|
||||||
|
#include "../config.h"
|
||||||
|
#include "mssdr_vty.h"
|
||||||
|
|
||||||
|
static struct mssdr_ctx *g_mssdr_ctx;
|
||||||
|
|
||||||
|
enum mssdr_vty_node {
|
||||||
|
MSSDR_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char mssdr_copyright[] =
|
||||||
|
"Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
|
||||||
|
"Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
|
||||||
|
"Copyright (C) 2013-2019 Fairwaves, Inc.\r\n"
|
||||||
|
"Copyright (C) 2015 Ettus Research LLC\r\n"
|
||||||
|
"Copyright (C) 2017-2024 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
|
||||||
|
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||||
|
"This is free software: you are free to change and redistribute it.\r\n"
|
||||||
|
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||||
|
|
||||||
|
static int mssdr_vty_go_parent(struct vty *vty)
|
||||||
|
{
|
||||||
|
switch (vty->node) {
|
||||||
|
case MSSDR_NODE:
|
||||||
|
vty->node = CONFIG_NODE;
|
||||||
|
vty->index = NULL;
|
||||||
|
vty->index_sub = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vty->node = CONFIG_NODE;
|
||||||
|
vty->index = NULL;
|
||||||
|
vty->index_sub = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vty->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mssdr_ctx *mssdr_from_vty(struct vty *v)
|
||||||
|
{
|
||||||
|
OSMO_ASSERT(g_mssdr_ctx);
|
||||||
|
return g_mssdr_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vty_app_info g_mssdr_vty_info = {
|
||||||
|
.name = "OsmoMSSDR",
|
||||||
|
.version = PACKAGE_VERSION,
|
||||||
|
.copyright = mssdr_copyright,
|
||||||
|
.go_parent_cb = mssdr_vty_go_parent,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mssdr_ctx *vty_mssdr_ctx_alloc(void *talloc_ctx)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = talloc_zero(talloc_ctx, struct mssdr_ctx);
|
||||||
|
trx->cfg.use_va = true;
|
||||||
|
trx->cfg.use_agc = true;
|
||||||
|
return trx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mssdr_dump_vty(struct vty *vty, struct mssdr_ctx *trx)
|
||||||
|
{
|
||||||
|
// vty_out(vty, "TRX Config:%s", VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
|
||||||
|
// vty_out(vty, " Filler Burst Type: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
|
||||||
|
vty_out(vty, "trx%s", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_freq_override)
|
||||||
|
vty_out(vty, " dl-freq-override %f%s", trx->cfg.overrides.dl_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_freq_override)
|
||||||
|
vty_out(vty, " ul-freq-override %f%s", trx->cfg.overrides.ul_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_gain_override)
|
||||||
|
vty_out(vty, " dl-gain-override %f%s", trx->cfg.overrides.dl_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_gain_override)
|
||||||
|
vty_out(vty, " ul-gain-override %f%s", trx->cfg.overrides.ul_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.use_va)
|
||||||
|
vty_out(vty, " viterbi-eq %s%s", trx->cfg.use_va ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.use_agc)
|
||||||
|
vty_out(vty, " enable-rx-agc %s%s", trx->cfg.use_agc ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_write_mssdr(struct vty *vty)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
vty_out(vty, "trx%s", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_freq_override)
|
||||||
|
vty_out(vty, " dl-freq-override %f%s", trx->cfg.overrides.dl_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_freq_override)
|
||||||
|
vty_out(vty, " ul-freq-override %f%s", trx->cfg.overrides.ul_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_gain_override)
|
||||||
|
vty_out(vty, " dl-gain-override %f%s", trx->cfg.overrides.dl_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_gain_override)
|
||||||
|
vty_out(vty, " ul-gain-override %f%s", trx->cfg.overrides.ul_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.use_va)
|
||||||
|
vty_out(vty, " viterbi-eq %s%s", trx->cfg.use_va ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.use_agc)
|
||||||
|
vty_out(vty, " enable-rx-agc %s%s", trx->cfg.use_agc ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(show_mssdr, show_mssdr_cmd,
|
||||||
|
"show mssdr",
|
||||||
|
SHOW_STR "Display information on the TRX\n")
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
mssdr_dump_vty(vty, trx);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_mssdr, cfg_mssdr_cmd,
|
||||||
|
"mssdr",
|
||||||
|
"Configure the mssdr\n")
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
if (!trx)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
vty->node = MSSDR_NODE;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ul_freq_override, cfg_ul_freq_override_cmd,
|
||||||
|
"ul-freq-override FLOAT",
|
||||||
|
"Overrides Tx carrier frequency\n"
|
||||||
|
"Frequency in Hz (e.g. 145300000)\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.ul_freq_override = true;
|
||||||
|
trx->cfg.overrides.ul_freq = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
DEFUN_ATTR(cfg_dl_freq_override, cfg_dl_freq_override_cmd,
|
||||||
|
"dl-freq-override FLOAT",
|
||||||
|
"Overrides Rx carrier frequency\n"
|
||||||
|
"Frequency in Hz (e.g. 145300000)\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.dl_freq_override = true;
|
||||||
|
trx->cfg.overrides.dl_freq = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ul_gain_override, cfg_ul_gain_override_cmd,
|
||||||
|
"ul-gain-override FLOAT",
|
||||||
|
"Overrides Tx gain\n"
|
||||||
|
"gain in dB\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.ul_gain_override = true;
|
||||||
|
trx->cfg.overrides.ul_gain = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
DEFUN_ATTR(cfg_dl_gain_override, cfg_dl_gain_override_cmd,
|
||||||
|
"dl-gain-override FLOAT",
|
||||||
|
"Overrides Rx gain\n"
|
||||||
|
"gain in dB\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.dl_gain_override = true;
|
||||||
|
trx->cfg.overrides.dl_gain = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_use_viterbi, cfg_use_viterbi_cmd,
|
||||||
|
"viterbi-eq (disable|enable)",
|
||||||
|
"Use viterbi equalizer for gmsk (default=enable)\n"
|
||||||
|
"Disable VA\n"
|
||||||
|
"Enable VA\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_va = false;
|
||||||
|
else if (strcmp("enable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_va = true;
|
||||||
|
else
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_use_agc, cfg_use_agc_cmd,
|
||||||
|
"enable-rx-agc (disable|enable)",
|
||||||
|
"Use the transceiver rx agc (default=enable)\n"
|
||||||
|
"Disable agc\n"
|
||||||
|
"Enable agc\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct mssdr_ctx *trx = mssdr_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_agc = false;
|
||||||
|
else if (strcmp("enable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_agc = true;
|
||||||
|
else
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cmd_node mssdr_node = {
|
||||||
|
MSSDR_NODE,
|
||||||
|
"%s(config-mssdr)# ",
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
int mssdr_vty_init(struct mssdr_ctx *trx)
|
||||||
|
{
|
||||||
|
g_mssdr_ctx = trx;
|
||||||
|
install_element_ve(&show_mssdr_cmd);
|
||||||
|
install_element(CONFIG_NODE, &cfg_mssdr_cmd);
|
||||||
|
|
||||||
|
install_node(&mssdr_node, config_write_mssdr);
|
||||||
|
install_element(MSSDR_NODE, &cfg_ul_freq_override_cmd);
|
||||||
|
install_element(MSSDR_NODE, &cfg_dl_freq_override_cmd);
|
||||||
|
install_element(MSSDR_NODE, &cfg_ul_gain_override_cmd);
|
||||||
|
install_element(MSSDR_NODE, &cfg_dl_gain_override_cmd);
|
||||||
|
install_element(MSSDR_NODE, &cfg_use_viterbi_cmd);
|
||||||
|
install_element(MSSDR_NODE, &cfg_use_agc_cmd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
67
Transceiver52M/ms/mssdr_vty.h
Normal file
67
Transceiver52M/ms/mssdr_vty.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* (C) 2024 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct mssdr_cfg {
|
||||||
|
// char *bind_addr;
|
||||||
|
// char *remote_addr;
|
||||||
|
// char *dev_args;
|
||||||
|
// unsigned int base_port;
|
||||||
|
// unsigned int tx_sps;
|
||||||
|
// unsigned int rx_sps;
|
||||||
|
// unsigned int rtsc;
|
||||||
|
// unsigned int rach_delay;
|
||||||
|
// enum ReferenceType clock_ref;
|
||||||
|
// enum FillerType filler;
|
||||||
|
// bool multi_arfcn;
|
||||||
|
// double offset;
|
||||||
|
// double freq_offset_khz;
|
||||||
|
// double rssi_offset;
|
||||||
|
// int ul_fn_offset;
|
||||||
|
// bool force_rssi_offset; /* Force value set in VTY? */
|
||||||
|
// bool swap_channels;
|
||||||
|
// bool ext_rach;
|
||||||
|
// bool egprs;
|
||||||
|
// unsigned int sched_rr;
|
||||||
|
// unsigned int stack_size;
|
||||||
|
// unsigned int num_chans;
|
||||||
|
// struct trx_chan chans[TRX_CHAN_MAX];
|
||||||
|
struct {
|
||||||
|
bool ul_freq_override;
|
||||||
|
bool dl_freq_override;
|
||||||
|
bool ul_gain_override;
|
||||||
|
bool dl_gain_override;
|
||||||
|
double ul_freq;
|
||||||
|
double dl_freq;
|
||||||
|
double ul_gain;
|
||||||
|
double dl_gain;
|
||||||
|
} overrides;
|
||||||
|
bool use_va;
|
||||||
|
bool use_agc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mssdr_ctx {
|
||||||
|
struct mssdr_cfg cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mssdr_ctx *vty_mssdr_ctx_alloc(void *talloc_ctx);
|
||||||
|
int mssdr_vty_init(struct mssdr_ctx *trx);
|
||||||
|
extern struct vty_app_info g_mssdr_vty_info;
|
||||||
@@ -645,7 +645,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
osmo_init_logging2(tall_trx_ctx, &log_info);
|
osmo_init_logging2(tall_trx_ctx, &log_info);
|
||||||
log_enable_multithread();
|
log_enable_multithread();
|
||||||
log_cache_enable();
|
|
||||||
osmo_stats_init(tall_trx_ctx);
|
osmo_stats_init(tall_trx_ctx);
|
||||||
vty_init(&g_vty_info);
|
vty_init(&g_vty_info);
|
||||||
logging_vty_add_cmds();
|
logging_vty_add_cmds();
|
||||||
|
|||||||
10
configure.ac
10
configure.ac
@@ -82,10 +82,10 @@ AC_TYPE_SIZE_T
|
|||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
AC_C_BIGENDIAN
|
AC_C_BIGENDIAN
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0)
|
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
|
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
|
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.10.0)
|
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.9.0)
|
||||||
|
|
||||||
AC_ARG_ENABLE(sanitize,
|
AC_ARG_ENABLE(sanitize,
|
||||||
[AS_HELP_STRING(
|
[AS_HELP_STRING(
|
||||||
@@ -240,6 +240,7 @@ AS_IF([test "x$with_sse" != "xno"], [
|
|||||||
AM_CONDITIONAL(HAVE_SSE4_1, false)
|
AM_CONDITIONAL(HAVE_SSE4_1, false)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl Check if the compiler supports specified GCC's built-in function
|
||||||
AC_DEFUN([CHECK_BUILTIN_SUPPORT], [
|
AC_DEFUN([CHECK_BUILTIN_SUPPORT], [
|
||||||
AC_CACHE_CHECK(
|
AC_CACHE_CHECK(
|
||||||
[whether ${CC} has $1 built-in],
|
[whether ${CC} has $1 built-in],
|
||||||
@@ -379,5 +380,6 @@ AC_CONFIG_FILES([\
|
|||||||
contrib/Makefile \
|
contrib/Makefile \
|
||||||
contrib/systemd/Makefile \
|
contrib/systemd/Makefile \
|
||||||
doc/manuals/Makefile \
|
doc/manuals/Makefile \
|
||||||
|
contrib/osmo-trx.spec \
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -9,19 +9,60 @@
|
|||||||
#
|
#
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
case "$INSTR" in
|
substr() { [ -z "${2##*$1*}" ]; }
|
||||||
"--with-neon"*)
|
|
||||||
case "$(arch)" in
|
#apt-get install qemu qemu-user-static qemu-system-arm debootstrap fakeroot proot
|
||||||
arm*)
|
mychroot_nocwd() {
|
||||||
;;
|
# LC_ALL + LANGUAGE set to avoid lots of print errors due to locale not being set inside container
|
||||||
*)
|
# PATH is needed to be able to reach binaries like ldconfig without logging in to root, which adds the paths to PATH.
|
||||||
set +x
|
# PROOT_NO_SECCOMP is required due to proot bug #106
|
||||||
echo "ERROR: trying to build with INSTR=$INSTR but not running on a 32-bit arm machine! (arch=$(arch))"
|
LC_ALL=C LANGUAGE=C PATH="$PATH:/usr/sbin:/sbin" PROOT_NO_SECCOMP=1 proot -r "$ROOTFS" -w / -b /proc --root-id -q qemu-arm-static "$@"
|
||||||
exit 1
|
}
|
||||||
;;
|
|
||||||
esac
|
mychroot() {
|
||||||
;;
|
mychroot_nocwd -w / "$@"
|
||||||
esac
|
}
|
||||||
|
|
||||||
|
if [ -z "${INSIDE_CHROOT}" ]; then
|
||||||
|
|
||||||
|
# Only use ARM chroot if host is not ARM and the target is ARM:
|
||||||
|
if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then
|
||||||
|
|
||||||
|
OSMOTRX_DIR="$PWD" # we assume we are called as contrib/jenkins.sh
|
||||||
|
ROOTFS_PREFIX="${ROOTFS_PREFIX:-$HOME}"
|
||||||
|
ROOTFS="${ROOTFS_PREFIX}/qemu-img"
|
||||||
|
mkdir -p "${ROOTFS_PREFIX}"
|
||||||
|
|
||||||
|
# Prepare chroot:
|
||||||
|
if [ ! -d "$ROOTFS" ]; then
|
||||||
|
mkdir -p "$ROOTFS"
|
||||||
|
if [ "x${USE_DEBOOTSTRAP}" = "x1" ]; then
|
||||||
|
fakeroot qemu-debootstrap --foreign --include="linux-image-armmp-lpae" --arch=armhf stretch "$ROOTFS" http://ftp.de.debian.org/debian/
|
||||||
|
# Hack to avoid debootstrap trying to mount /proc, as it will fail with "no permissions" and anyway proot takes care of it:
|
||||||
|
sed -i "s/setup_proc//g" "$ROOTFS/debootstrap/suite-script"
|
||||||
|
mychroot /debootstrap/debootstrap --second-stage --verbose http://ftp.de.debian.org/debian/
|
||||||
|
else
|
||||||
|
YESTERDAY=$(python -c 'import datetime ; print((datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d"))')
|
||||||
|
wget -nc -q "https://uk.images.linuxcontainers.org/images/debian/stretch/armhf/default/${YESTERDAY}_22:42/rootfs.tar.xz"
|
||||||
|
tar -xf rootfs.tar.xz -C "$ROOTFS/" || true
|
||||||
|
echo "nameserver 8.8.8.8" > "$ROOTFS/etc/resolv.conf"
|
||||||
|
fi
|
||||||
|
mychroot -b /dev apt-get update
|
||||||
|
mychroot apt-get -y install build-essential dh-autoreconf pkg-config libuhd-dev libusb-1.0-0-dev libusb-dev git libtalloc-dev libgnutls28-dev stow
|
||||||
|
fi
|
||||||
|
# Run jenkins.sh inside the chroot:
|
||||||
|
INSIDE_CHROOT=1 mychroot_nocwd \
|
||||||
|
-w /osmo-trx \
|
||||||
|
-b "$OSMOTRX_DIR:/osmo-trx" \
|
||||||
|
-b "$(which osmo-clean-workspace.sh):/usr/bin/osmo-clean-workspace.sh" \
|
||||||
|
-b "$(which osmo-build-dep.sh):/usr/bin/osmo-build-dep.sh" \
|
||||||
|
-b "$(which osmo-deps.sh):/usr/bin/osmo-deps.sh" \
|
||||||
|
./contrib/jenkins.sh
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
|
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
|
||||||
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
|
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
|
||||||
|
|||||||
254
contrib/osmo-trx.spec.in
Normal file
254
contrib/osmo-trx.spec.in
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
#
|
||||||
|
# spec file for package osmo-trx
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
|
||||||
|
#
|
||||||
|
# All modifications and additions to the file contributed by third parties
|
||||||
|
# remain the property of their copyright owners, unless otherwise agreed
|
||||||
|
# upon. The license for this file, and modifications and additions to the
|
||||||
|
# file, is the same license as for the pristine package itself (unless the
|
||||||
|
# license for the pristine package is not an Open Source License, in which
|
||||||
|
# case the license is the MIT License). An "Open Source License" is a
|
||||||
|
# license that conforms to the Open Source Definition (Version 1.9)
|
||||||
|
# published by the Open Source Initiative.
|
||||||
|
|
||||||
|
Name: osmo-trx
|
||||||
|
Version: @VERSION@
|
||||||
|
Release: 0
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS
|
||||||
|
License: AGPL-3.0-or-later
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
URL: https://osmocom.org/projects/osmotrx
|
||||||
|
Source: %{name}-%{version}.tar.xz
|
||||||
|
BuildRequires: autoconf
|
||||||
|
BuildRequires: automake
|
||||||
|
BuildRequires: fdupes
|
||||||
|
BuildRequires: gcc-c++
|
||||||
|
BuildRequires: libtool
|
||||||
|
BuildRequires: pkgconfig >= 0.20
|
||||||
|
%if 0%{?suse_version}
|
||||||
|
BuildRequires: systemd-rpm-macros
|
||||||
|
%endif
|
||||||
|
%if ! 0%{?centos_ver}
|
||||||
|
BuildRequires: pkgconfig(LimeSuite)
|
||||||
|
BuildRequires: pkgconfig(usrp) >= 3.3
|
||||||
|
%endif
|
||||||
|
BuildRequires: pkgconfig(fftw3f)
|
||||||
|
BuildRequires: pkgconfig(libosmocoding) >= 1.9.0
|
||||||
|
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
|
||||||
|
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
|
||||||
|
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
|
||||||
|
BuildRequires: pkgconfig(libusb-1.0)
|
||||||
|
BuildRequires: pkgconfig(uhd)
|
||||||
|
%{?systemd_requires}
|
||||||
|
%if 0%{?suse_version} > 1325
|
||||||
|
BuildRequires: libboost_program_options-devel
|
||||||
|
BuildRequires: libboost_system-devel
|
||||||
|
BuildRequires: libboost_test-devel
|
||||||
|
BuildRequires: libboost_thread-devel
|
||||||
|
%else
|
||||||
|
BuildRequires: boost-devel
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%description
|
||||||
|
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 uhd
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (UHD)
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
Requires: uhd-firmware
|
||||||
|
|
||||||
|
%description uhd
|
||||||
|
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)
|
||||||
|
|
||||||
|
%if ! 0%{?centos_ver}
|
||||||
|
%package usrp1
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (USRP1)
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
|
||||||
|
%description usrp1
|
||||||
|
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 lms
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (LimeSuite)
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
|
||||||
|
%description lms
|
||||||
|
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)
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%package ipc
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (IPC)
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
|
||||||
|
%description ipc
|
||||||
|
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 ipc-test
|
||||||
|
Summary: SDR transceiver that implements Layer 1 of a GSM BTS (IPC) driver test utility
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
|
||||||
|
%description ipc-test
|
||||||
|
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
||||||
|
physical layer of a BTS comprising the following 3GPP specifications:
|
||||||
|
|
||||||
|
This package include the test tools for osmo-trx-ipc
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
echo "%{version}" >.tarball-version
|
||||||
|
autoreconf -fi
|
||||||
|
|
||||||
|
%if 0%{?centos_ver}
|
||||||
|
%configure \
|
||||||
|
--docdir=%{_docdir}/%{name} \
|
||||||
|
--with-systemdsystemunitdir=%{_unitdir} \
|
||||||
|
--without-lms \
|
||||||
|
--with-uhd \
|
||||||
|
--without-usrp1 \
|
||||||
|
--with-ipc
|
||||||
|
%else
|
||||||
|
%configure \
|
||||||
|
--docdir=%{_docdir}/%{name} \
|
||||||
|
--with-systemdsystemunitdir=%{_unitdir} \
|
||||||
|
--with-lms \
|
||||||
|
--with-uhd \
|
||||||
|
--with-usrp1 \
|
||||||
|
--with-ipc
|
||||||
|
%endif
|
||||||
|
|
||||||
|
make %{?_smp_mflags} V=1
|
||||||
|
|
||||||
|
%check
|
||||||
|
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install
|
||||||
|
%fdupes -s %{buildroot}/%{_datadir}
|
||||||
|
|
||||||
|
%if 0%{?suse_version}
|
||||||
|
%pre lms %service_add_pre osmo-trx-lms.service
|
||||||
|
%post lms %service_add_post osmo-trx-lms.service
|
||||||
|
%preun lms %service_del_preun osmo-trx-lms.service
|
||||||
|
%postun lms %service_del_postun osmo-trx-lms.service
|
||||||
|
%pre uhd %service_add_pre osmo-trx-uhd.service
|
||||||
|
%post uhd %service_add_post osmo-trx-uhd.service
|
||||||
|
%preun uhd %service_del_preun osmo-trx-uhd.service
|
||||||
|
%postun uhd %service_del_postun osmo-trx-uhd.service
|
||||||
|
%pre usrp1 %service_add_pre osmo-trx-usrp1.service
|
||||||
|
%post usrp1 %service_add_post osmo-trx-usrp1.service
|
||||||
|
%preun usrp1 %service_del_preun osmo-trx-usrp1.service
|
||||||
|
%postun usrp1 %service_del_postun osmo-trx-usrp1.service
|
||||||
|
%pre ipc %service_add_pre osmo-trx-ipc.service
|
||||||
|
%post ipc %service_add_post osmo-trx-ipc.service
|
||||||
|
%preun ipc %service_del_preun osmo-trx-ipc.service
|
||||||
|
%postun ipc %service_del_postun osmo-trx-ipc.service
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license COPYING
|
||||||
|
%doc README.md
|
||||||
|
%doc %{_docdir}/%{name}/examples
|
||||||
|
|
||||||
|
%if ! 0%{?centos_ver}
|
||||||
|
%files lms
|
||||||
|
%{_bindir}/osmo-trx-lms
|
||||||
|
%dir %{_sysconfdir}/osmocom
|
||||||
|
%config(noreplace) %{_sysconfdir}/osmocom/osmo-trx-lms.cfg
|
||||||
|
%{_unitdir}/osmo-trx-lms.service
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%files uhd
|
||||||
|
%{_bindir}/osmo-trx-uhd
|
||||||
|
%dir %{_sysconfdir}/osmocom
|
||||||
|
%config(noreplace) %{_sysconfdir}/osmocom/osmo-trx-uhd.cfg
|
||||||
|
%{_unitdir}/osmo-trx-uhd.service
|
||||||
|
|
||||||
|
%if ! 0%{?centos_ver}
|
||||||
|
%files usrp1
|
||||||
|
%{_bindir}/osmo-trx-usrp1
|
||||||
|
%dir %{_datadir}/usrp
|
||||||
|
%dir %{_datadir}/usrp/rev2
|
||||||
|
%dir %{_datadir}/usrp/rev4
|
||||||
|
%{_datadir}/usrp/rev2/std_inband.rbf
|
||||||
|
%{_datadir}/usrp/rev4/std_inband.rbf
|
||||||
|
%{_unitdir}/osmo-trx-usrp1.service
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%files ipc
|
||||||
|
%{_bindir}/osmo-trx-ipc
|
||||||
|
%dir %{_sysconfdir}/osmocom
|
||||||
|
%config(noreplace) %{_sysconfdir}/osmocom/osmo-trx-ipc.cfg
|
||||||
|
%{_unitdir}/osmo-trx-ipc.service
|
||||||
|
|
||||||
|
%files ipc-test
|
||||||
|
%{_bindir}/ipc-driver-test
|
||||||
|
|
||||||
|
%changelog
|
||||||
@@ -8,11 +8,8 @@ Type=simple
|
|||||||
Restart=always
|
Restart=always
|
||||||
StateDirectory=osmocom
|
StateDirectory=osmocom
|
||||||
WorkingDirectory=%S/osmocom
|
WorkingDirectory=%S/osmocom
|
||||||
User=osmocom
|
|
||||||
Group=osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-trx-ipc -C /etc/osmocom/osmo-trx-ipc.cfg
|
ExecStart=/usr/bin/osmo-trx-ipc -C /etc/osmocom/osmo-trx-ipc.cfg
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
AmbientCapabilities=CAP_SYS_NICE
|
|
||||||
# CPU scheduling policy:
|
# CPU scheduling policy:
|
||||||
CPUSchedulingPolicy=rr
|
CPUSchedulingPolicy=rr
|
||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ Type=simple
|
|||||||
Restart=always
|
Restart=always
|
||||||
StateDirectory=osmocom
|
StateDirectory=osmocom
|
||||||
WorkingDirectory=%S/osmocom
|
WorkingDirectory=%S/osmocom
|
||||||
User=osmocom
|
|
||||||
Group=osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-trx-lms -C /etc/osmocom/osmo-trx-lms.cfg
|
ExecStart=/usr/bin/osmo-trx-lms -C /etc/osmocom/osmo-trx-lms.cfg
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
AmbientCapabilities=CAP_SYS_NICE
|
|
||||||
# CPU scheduling policy:
|
# CPU scheduling policy:
|
||||||
CPUSchedulingPolicy=rr
|
CPUSchedulingPolicy=rr
|
||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ Type=simple
|
|||||||
Restart=always
|
Restart=always
|
||||||
StateDirectory=osmocom
|
StateDirectory=osmocom
|
||||||
WorkingDirectory=%S/osmocom
|
WorkingDirectory=%S/osmocom
|
||||||
Environment=HOME=%S/osmocom
|
Environment=HOME=%h
|
||||||
User=osmocom
|
|
||||||
Group=osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-trx-uhd -C /etc/osmocom/osmo-trx-uhd.cfg
|
ExecStart=/usr/bin/osmo-trx-uhd -C /etc/osmocom/osmo-trx-uhd.cfg
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
AmbientCapabilities=CAP_SYS_NICE
|
|
||||||
# CPU scheduling policy:
|
# CPU scheduling policy:
|
||||||
CPUSchedulingPolicy=rr
|
CPUSchedulingPolicy=rr
|
||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ Type=simple
|
|||||||
Restart=always
|
Restart=always
|
||||||
StateDirectory=osmocom
|
StateDirectory=osmocom
|
||||||
WorkingDirectory=%S/osmocom
|
WorkingDirectory=%S/osmocom
|
||||||
User=osmocom
|
|
||||||
Group=osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-trx-usrp1 -C /etc/osmocom/osmo-trx-usrp1.cfg
|
ExecStart=/usr/bin/osmo-trx-usrp1 -C /etc/osmocom/osmo-trx-usrp1.cfg
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
AmbientCapabilities=CAP_SYS_NICE
|
|
||||||
# CPU scheduling policy:
|
# CPU scheduling policy:
|
||||||
CPUSchedulingPolicy=rr
|
CPUSchedulingPolicy=rr
|
||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||||
|
|||||||
62
debian/changelog
vendored
62
debian/changelog
vendored
@@ -1,65 +1,3 @@
|
|||||||
osmo-trx (1.7.1) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* contrib/jenkins: remove broken chroot + qemu code
|
|
||||||
|
|
||||||
[ Neels Hofmeyr ]
|
|
||||||
* comma_delimited_to_vector() optimization CID#465430
|
|
||||||
|
|
||||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 12 Feb 2025 12:43:24 +0100
|
|
||||||
|
|
||||||
osmo-trx (1.7.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Eric ]
|
|
||||||
* ms: adjust ts advance
|
|
||||||
* ms: reduce rx burst queue size
|
|
||||||
* ms: init blade with fpga control
|
|
||||||
* devices: fix wrong gain to power mapping
|
|
||||||
* ms: get rid of std::thread
|
|
||||||
* ms: add demod test tool and data
|
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
|
||||||
* osmo-trx-ms: bump osmocom-bb submodule commit
|
|
||||||
* Transceiver::ctrl_sock_handle_rx(): fix copy-pasted comments
|
|
||||||
* build: include version files into the release tarball
|
|
||||||
* doc/examples: fix missing config files in release tarballs
|
|
||||||
* README.md: cosmetic: fix a typo
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* osmo-trx-uhd: Make sure HOME environment variable is set
|
|
||||||
* README.md: Improve markdown formatting
|
|
||||||
* README.md: Add Forum and Issue Tracker links
|
|
||||||
* Add funding link to github mirror
|
|
||||||
* README.md: Remove stray apostrophe
|
|
||||||
|
|
||||||
[ Andreas Eversberg ]
|
|
||||||
* Use uniform log format for default config files
|
|
||||||
|
|
||||||
[ Eric Wild ]
|
|
||||||
* ms: do not set the blade tuning mode
|
|
||||||
* ms: hard preswapped VA gsm bits
|
|
||||||
* ms: add sigproclib demod
|
|
||||||
* ms: fix up template deduction failure
|
|
||||||
* ms: update osmocom-bb submodule
|
|
||||||
* ms: disabe uhd ms build
|
|
||||||
* transceiver: use log level cache
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* gitignore: add .version
|
|
||||||
* debian/rules: make configure args diff friendly
|
|
||||||
* debian: add osmo-trx-ms-blade
|
|
||||||
* contrib/jenkins: make configure args diff friendly
|
|
||||||
* contrib/jenkins: add --with-bladerf
|
|
||||||
* contrib: remove rpm spec file
|
|
||||||
* contrib/systemd: run as osmocom user
|
|
||||||
* contrib/systemd/osmo-trx-uhd: fix HOME=
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* code-architecture.adoc: Fix missing alignment in digraph
|
|
||||||
* doc: Introduce documentation for osmo-trx-ipc and its IPC interface
|
|
||||||
|
|
||||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 24 Jul 2024 15:57:14 +0200
|
|
||||||
|
|
||||||
osmo-trx (1.6.0) unstable; urgency=medium
|
osmo-trx (1.6.0) unstable; urgency=medium
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
[ Vadim Yanitskiy ]
|
||||||
|
|||||||
4
debian/control
vendored
4
debian/control
vendored
@@ -15,8 +15,8 @@ Build-Depends: debhelper (>= 10),
|
|||||||
libusrp-dev,
|
libusrp-dev,
|
||||||
liblimesuite-dev,
|
liblimesuite-dev,
|
||||||
libbladerf-dev,
|
libbladerf-dev,
|
||||||
libosmocore-dev (>= 1.10.0),
|
libosmocore-dev (>= 1.9.0),
|
||||||
osmo-gsm-manuals-dev (>= 1.6.0)
|
osmo-gsm-manuals-dev (>= 1.5.0)
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
||||||
|
|||||||
38
debian/osmo-trx-ipc.postinst
vendored
38
debian/osmo-trx-ipc.postinst
vendored
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
case "$1" in
|
|
||||||
configure)
|
|
||||||
# Create the osmocom group and user (if it doesn't exist yet)
|
|
||||||
if ! getent group osmocom >/dev/null; then
|
|
||||||
groupadd --system osmocom
|
|
||||||
fi
|
|
||||||
if ! getent passwd osmocom >/dev/null; then
|
|
||||||
useradd \
|
|
||||||
--system \
|
|
||||||
--gid osmocom \
|
|
||||||
--home-dir /var/lib/osmocom \
|
|
||||||
--shell /sbin/nologin \
|
|
||||||
--comment "Open Source Mobile Communications" \
|
|
||||||
osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
|
||||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
|
||||||
if [ -e /etc/osmocom/osmo-trx-ipc.cfg ]; then
|
|
||||||
chown -v osmocom:osmocom /etc/osmocom/osmo-trx-ipc.cfg
|
|
||||||
chmod -v 0660 /etc/osmocom/osmo-trx-ipc.cfg
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d /etc/osmocom ]; then
|
|
||||||
chown -v root:osmocom /etc/osmocom
|
|
||||||
chmod -v 2775 /etc/osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/lib/osmocom
|
|
||||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb(1) will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
#DEBHELPER#
|
|
||||||
38
debian/osmo-trx-lms.postinst
vendored
38
debian/osmo-trx-lms.postinst
vendored
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
case "$1" in
|
|
||||||
configure)
|
|
||||||
# Create the osmocom group and user (if it doesn't exist yet)
|
|
||||||
if ! getent group osmocom >/dev/null; then
|
|
||||||
groupadd --system osmocom
|
|
||||||
fi
|
|
||||||
if ! getent passwd osmocom >/dev/null; then
|
|
||||||
useradd \
|
|
||||||
--system \
|
|
||||||
--gid osmocom \
|
|
||||||
--home-dir /var/lib/osmocom \
|
|
||||||
--shell /sbin/nologin \
|
|
||||||
--comment "Open Source Mobile Communications" \
|
|
||||||
osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
|
||||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
|
||||||
if [ -e /etc/osmocom/osmo-trx-lms.cfg ]; then
|
|
||||||
chown -v osmocom:osmocom /etc/osmocom/osmo-trx-lms.cfg
|
|
||||||
chmod -v 0660 /etc/osmocom/osmo-trx-lms.cfg
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d /etc/osmocom ]; then
|
|
||||||
chown -v root:osmocom /etc/osmocom
|
|
||||||
chmod -v 2775 /etc/osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/lib/osmocom
|
|
||||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb(1) will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
#DEBHELPER#
|
|
||||||
38
debian/osmo-trx-uhd.postinst
vendored
38
debian/osmo-trx-uhd.postinst
vendored
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
case "$1" in
|
|
||||||
configure)
|
|
||||||
# Create the osmocom group and user (if it doesn't exist yet)
|
|
||||||
if ! getent group osmocom >/dev/null; then
|
|
||||||
groupadd --system osmocom
|
|
||||||
fi
|
|
||||||
if ! getent passwd osmocom >/dev/null; then
|
|
||||||
useradd \
|
|
||||||
--system \
|
|
||||||
--gid osmocom \
|
|
||||||
--home-dir /var/lib/osmocom \
|
|
||||||
--shell /sbin/nologin \
|
|
||||||
--comment "Open Source Mobile Communications" \
|
|
||||||
osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
|
||||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
|
||||||
if [ -e /etc/osmocom/osmo-trx-uhd.cfg ]; then
|
|
||||||
chown -v osmocom:osmocom /etc/osmocom/osmo-trx-uhd.cfg
|
|
||||||
chmod -v 0660 /etc/osmocom/osmo-trx-uhd.cfg
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d /etc/osmocom ]; then
|
|
||||||
chown -v root:osmocom /etc/osmocom
|
|
||||||
chmod -v 2775 /etc/osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/lib/osmocom
|
|
||||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb(1) will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
#DEBHELPER#
|
|
||||||
38
debian/osmo-trx-usrp1.postinst
vendored
38
debian/osmo-trx-usrp1.postinst
vendored
@@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
case "$1" in
|
|
||||||
configure)
|
|
||||||
# Create the osmocom group and user (if it doesn't exist yet)
|
|
||||||
if ! getent group osmocom >/dev/null; then
|
|
||||||
groupadd --system osmocom
|
|
||||||
fi
|
|
||||||
if ! getent passwd osmocom >/dev/null; then
|
|
||||||
useradd \
|
|
||||||
--system \
|
|
||||||
--gid osmocom \
|
|
||||||
--home-dir /var/lib/osmocom \
|
|
||||||
--shell /sbin/nologin \
|
|
||||||
--comment "Open Source Mobile Communications" \
|
|
||||||
osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
|
||||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
|
||||||
if [ -e /etc/osmocom/osmo-trx-usrp1.cfg ]; then
|
|
||||||
chown -v osmocom:osmocom /etc/osmocom/osmo-trx-usrp1.cfg
|
|
||||||
chmod -v 0660 /etc/osmocom/osmo-trx-usrp1.cfg
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d /etc/osmocom ]; then
|
|
||||||
chown -v root:osmocom /etc/osmocom
|
|
||||||
chmod -v 2775 /etc/osmocom
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/lib/osmocom
|
|
||||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb(1) will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
#DEBHELPER#
|
|
||||||
@@ -9,7 +9,7 @@ digraph hierarchy {
|
|||||||
node[shape=record,style=filled,fillcolor=gray95]
|
node[shape=record,style=filled,fillcolor=gray95]
|
||||||
edge[dir=back, arrowtail=empty]
|
edge[dir=back, arrowtail=empty]
|
||||||
|
|
||||||
2[label = "{Transceiver|+ constructor()\l+ destructor()\l+ init()\l+ numChans()\l+ receiveFIFO()\l+ setSignalHandler()\l}"]
|
2[label = "{Transceiver|+ constructor()\l+ destructor()\l+ init()\l+ numChans()\l+ receiveFIFO()\l+ setSignalHandler()}"]
|
||||||
3[label = "{RadioInterface|...}"]
|
3[label = "{RadioInterface|...}"]
|
||||||
4[label = "{RadioInterfaceResamp|...}"]
|
4[label = "{RadioInterfaceResamp|...}"]
|
||||||
5[label = "{RadioInterfaceMulti|...}"]
|
5[label = "{RadioInterfaceMulti|...}"]
|
||||||
@@ -17,7 +17,6 @@ edge[dir=back, arrowtail=empty]
|
|||||||
7[label = "{UHDDevice|...}"]
|
7[label = "{UHDDevice|...}"]
|
||||||
8[label = "{LMSDevice|...}"]
|
8[label = "{LMSDevice|...}"]
|
||||||
9[label = "{USRPDevice|...}"]
|
9[label = "{USRPDevice|...}"]
|
||||||
10[label = "{IPCDevice|...}"]
|
|
||||||
|
|
||||||
2->3[arrowtail=odiamond]
|
2->3[arrowtail=odiamond]
|
||||||
3->4[constraint=false]
|
3->4[constraint=false]
|
||||||
@@ -26,7 +25,6 @@ edge[dir=back, arrowtail=empty]
|
|||||||
6->7
|
6->7
|
||||||
6->8
|
6->8
|
||||||
6->9
|
6->9
|
||||||
6->10
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|||||||
@@ -1,301 +0,0 @@
|
|||||||
[[ipc_if]]
|
|
||||||
== osmo-trx-ipc IPC Interface
|
|
||||||
|
|
||||||
This interface is the one used by _osmo_trx_ipc_ backend to communicate to a
|
|
||||||
third party process in charge of driving the lowest layer device-specific bits
|
|
||||||
(from now on the Driver).
|
|
||||||
|
|
||||||
It consists of a set of Unix Domain (UD) sockets for the control plane, plus a
|
|
||||||
shared memory region for the data plane.
|
|
||||||
|
|
||||||
Related code can be found in the
|
|
||||||
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc[Transceiver52M/device/ipc/]
|
|
||||||
directory in _osmo-trx.git_.
|
|
||||||
|
|
||||||
If you are a potential driver implementator, the
|
|
||||||
various primitives and data structures are publicly available in header file
|
|
||||||
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/shm.h[Transceiver52M/device/ipc/shm.h].
|
|
||||||
|
|
||||||
=== Control plane
|
|
||||||
|
|
||||||
Control plane protocol is transmitted over Unix Domain (UD) sockets using
|
|
||||||
message based primitives. Each primitive has a type identified by an integer,
|
|
||||||
and each type of primitive has a number of extra attributes attached to it. The
|
|
||||||
IPC interface consists of 2 types of UD sockets:
|
|
||||||
|
|
||||||
* _Master_ UD socket: One per osmo-trx-ipc process.
|
|
||||||
|
|
||||||
* _Channel_ UD socket: One for each channel managed by osmo-trx-ipc process.
|
|
||||||
|
|
||||||
The _Driver_ is in all cases expected to take the server role when creating UD
|
|
||||||
sockets, while _osmo-trx-ipc_ takes the client role and connects to sockets
|
|
||||||
provided by the driver.
|
|
||||||
|
|
||||||
=== Master UD socket
|
|
||||||
|
|
||||||
During startup, _osmo-trx-ipc_ will try connecting to the _Driver_ Master UD
|
|
||||||
socket located in the path provided by its own (VTY) configuration. As a result,
|
|
||||||
it means the _Driver_ process must be running and listening on the Master UD
|
|
||||||
socket before _osmo-trx-ipc_ is started, otherwise _osmo-trx-ipc_ will fail and
|
|
||||||
exit.
|
|
||||||
|
|
||||||
Once connected, _osmo-trx-ipc_ will submit a `GREETING_REQ` message primitive
|
|
||||||
announcing the maximum supported protocol version (first version ever is `1`,
|
|
||||||
increasing over time).
|
|
||||||
|
|
||||||
The _Driver_ shall then answer in `GREETING_CNF` message primitive with its own
|
|
||||||
maximum supported version (`<=` version received), providing 0 if none is
|
|
||||||
supported.
|
|
||||||
|
|
||||||
If _osmo-trx-ipc_ receives back the requested version, then both sides agreed
|
|
||||||
on the protocol version to use.
|
|
||||||
If _osmo-trx-ipc_ receives back a lower version, it shall decide to continue
|
|
||||||
with version negotiation using a lower version, until a supported version or 0
|
|
||||||
is received. If finally 0 is received, _osmo-trx-ipc_ will disconnect and exit
|
|
||||||
with failure.
|
|
||||||
|
|
||||||
Once the version is negotiated (`v1` as of current date), _osmo-trx-ipc_ will
|
|
||||||
ask for device information and available characeristics to the _Driver_ using
|
|
||||||
the `INFO_REQ` message primitive.
|
|
||||||
|
|
||||||
The _Driver_ shall then answer with a `INFO_CNF` message
|
|
||||||
containing information, such as:
|
|
||||||
|
|
||||||
* String containing device description
|
|
||||||
|
|
||||||
* Available reference clocks,
|
|
||||||
|
|
||||||
* {rx,tx} I/Q scaling factors
|
|
||||||
|
|
||||||
* Maximum number of channels supported
|
|
||||||
|
|
||||||
* for each channel:
|
|
||||||
|
|
||||||
** List of available {rx,tx} paths/antennas.
|
|
||||||
|
|
||||||
** {min,max}{rx,tx} gains
|
|
||||||
|
|
||||||
** Nominal transmit power
|
|
||||||
|
|
||||||
All the information received from the _Driver_ during `INFO_CNF` will be used by
|
|
||||||
_osmo-trx-ipc_ to decide whether it can fullfil the requested configuration from
|
|
||||||
the user, and proceed to open the device, or exit with a failure (for instance
|
|
||||||
number of channels, referece clock or tx/rx antenna selected by the user cannot
|
|
||||||
be fullfilled).
|
|
||||||
|
|
||||||
_osmo-trx-ipc_ will then proceed to open the device and do an initial
|
|
||||||
configuration using an `OPEN_REQ` message, where it will provide the _Driver_
|
|
||||||
with the desired selected configuration (such as number of channels, rx/tx
|
|
||||||
paths, clock reference, bandwidth filters, etc.).
|
|
||||||
|
|
||||||
The _Driver_ shall then configure the device and send back a `OPEN_CNF` with:
|
|
||||||
|
|
||||||
* `return_code` integer attribute set to `0` on success or `!0` on error.
|
|
||||||
|
|
||||||
* Name of the Posix Shared Memory region where data plane is going to be
|
|
||||||
transmitted.
|
|
||||||
|
|
||||||
* One path for each channel, containing the just-created UD socket to manage
|
|
||||||
that channel (for instance by taking Master UD socket path and appending
|
|
||||||
`_$chan_idx`).
|
|
||||||
|
|
||||||
* Path Delay: this is the loopback path delay in samples (= used as a timestamp
|
|
||||||
offset internally by _osmo-trx-ipc_), this value contains the analog delay as
|
|
||||||
well as the delay introduced by the digital filters in the fpga in the sdr
|
|
||||||
devices, and is therefore device type and bandwidth/sample rate dependant. This
|
|
||||||
can not be omitted, wrong values will lead to a _osmo-trx-ipc_ that just doesn't
|
|
||||||
detect any bursts.
|
|
||||||
|
|
||||||
Finally, _osmo-trx-ipc_ will connect to each channel's UD socket (see next
|
|
||||||
section).
|
|
||||||
|
|
||||||
Upon _osmo-trx-ipc_ closing the UD master socket connection, the _Driver_ shall
|
|
||||||
go into _closed_ state: stop all processing and instruct the device to power
|
|
||||||
off.
|
|
||||||
|
|
||||||
TIP: See
|
|
||||||
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/shm.h[Transceiver52M/device/ipc/shm.h]
|
|
||||||
for the detailed definition of all the related message primitives and data
|
|
||||||
types for this socket.
|
|
||||||
|
|
||||||
=== Channel UD Socket
|
|
||||||
|
|
||||||
This socket can be used by _osmo-trx-ipc_ to start/stop data plane processing or
|
|
||||||
change channel's parameters such as Rx/Tx Frequency, Rx/Tx gains, etc.
|
|
||||||
|
|
||||||
A channel can be either in _started_ or _stopped_ state. When a channel is
|
|
||||||
created (during `OPEN_REQ` in the Master UD Socket), it's by default in
|
|
||||||
_stopped_ state. `START_REQ` and `STOP_REQ` messages control this state, and
|
|
||||||
eventual failures can be reported through `START_CNF` and `STOP_CNF` by the
|
|
||||||
_Driver_.
|
|
||||||
|
|
||||||
The message `START_REQ` instructs the _Driver_ to start processing data in the
|
|
||||||
data plane. Similary, `STOP_REQ` instructs the _Driver_ to stop processing data
|
|
||||||
in the data plane.
|
|
||||||
|
|
||||||
Some parameters are usually changed only when the channel is in stopped mode,
|
|
||||||
for instance Rx/Tx Frequency.
|
|
||||||
|
|
||||||
TIP: See
|
|
||||||
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/shm.h[Transceiver52M/device/ipc/shm.h]
|
|
||||||
for the detailed definition of all the related message primitives and data
|
|
||||||
types for this socket.
|
|
||||||
|
|
||||||
=== Data Plane
|
|
||||||
|
|
||||||
Data plane protocol is implemented by means of a ring buffer structure on top of
|
|
||||||
Posix Shared Memory (see `man 7 shm_overview`) between _osmo-trx-ipc_ process
|
|
||||||
and the _Driver_.
|
|
||||||
|
|
||||||
The Posix Shared Memory region is created and its memory structure prepared by
|
|
||||||
the _Driver_ and its name shared with _osmo-trx-ipc_ during _OPEN_CNF_ message
|
|
||||||
in the Master UD Socket from the Control Plane. Resource allocation for the
|
|
||||||
shared memory area and cleanup is up to the ipc server, as is mutex
|
|
||||||
initialization for the buffers.
|
|
||||||
|
|
||||||
==== Posix Shared Memory structure
|
|
||||||
|
|
||||||
[[fig-shm-structure]]
|
|
||||||
.General overview of Posix Shared Memory structure
|
|
||||||
[graphviz]
|
|
||||||
----
|
|
||||||
digraph hierarchy {
|
|
||||||
node[shape=record,style=filled,fillcolor=gray95]
|
|
||||||
edge[dir=back, arrowtail=empty]
|
|
||||||
|
|
||||||
SHM[label = "{Posix Shared Memory region|+ num_chans\l+ Channels[]\l}"]
|
|
||||||
CHAN0[label = "{Channel 0|...}"]
|
|
||||||
CHAN1[label = "{Channel 1|...}"]
|
|
||||||
CHANN[label = "{Channel ...|}"]
|
|
||||||
STREAM0_UL[label = "{UL Stream|+ semaphore\l+ read_next\l+ write_next\l+ buffer_size /* In samples */\l+ num_buffers\l+ sample_buffers[]\l}"]
|
|
||||||
STREAM0_DL[label = "{DL Stream|+ semaphore\l+ read_next\l+ write_next\l+ buffer_size /* In samples */\l+ num_buffers\l+ sample_buffers[]\l}"]
|
|
||||||
STREAM1_UL[label = "{UL Stream|...}"]
|
|
||||||
STREAM1_DL[label = "{DL Stream|...}"]
|
|
||||||
STREAMN_UL[label = "{UL Stream|...}"]
|
|
||||||
STREAMN_DL[label = "{DL Stream|...}"]
|
|
||||||
BUF_0DL0[label = "{DL Sample Buffer 0|+ timestamp\l+ buffer_size /* In samples */\l+ samples[] = [16bit I + 16bit Q,...]\l}"]
|
|
||||||
BUF_0DLN[label = "{DL Sample Buffer ....|...}"]
|
|
||||||
BUF_0UL0[label = "{UL Sample Buffer 0|+ timestamp\l+ buffer_size /* In samples */\l+ samples[] = [16bit I + 16bit Q,...]\l}"]
|
|
||||||
BUF_0ULN[label = "{UL Sample Buffer ...|...}"]
|
|
||||||
|
|
||||||
SHM->CHAN0
|
|
||||||
SHM->CHAN1
|
|
||||||
SHM->CHANN
|
|
||||||
|
|
||||||
CHAN0->STREAM0_DL
|
|
||||||
CHAN0->STREAM0_UL
|
|
||||||
STREAM0_DL->BUF_0DL0
|
|
||||||
STREAM0_DL->BUF_0DLN
|
|
||||||
STREAM0_UL->BUF_0UL0
|
|
||||||
STREAM0_UL->BUF_0ULN
|
|
||||||
|
|
||||||
CHAN1->STREAM1_UL
|
|
||||||
CHAN1->STREAM1_DL
|
|
||||||
|
|
||||||
CHANN->STREAMN_UL
|
|
||||||
CHANN->STREAMN_DL
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
The Posix Shared Memory region contains an array of _Channels_.
|
|
||||||
|
|
||||||
Each _Channel_ contains 2 Streams:
|
|
||||||
|
|
||||||
* Downlink _Stream_
|
|
||||||
|
|
||||||
* Uplink _Stream_
|
|
||||||
|
|
||||||
Each _Stream_ handles a ring buffer, which is implemented as:
|
|
||||||
|
|
||||||
* An array of pointers to _Sample Buffer_ structures.
|
|
||||||
|
|
||||||
* Variables containing the number of buffers in the array, as well as the
|
|
||||||
maximum size in samples for each Sample Buffer.
|
|
||||||
|
|
||||||
* Variables containing `next_read` and `next_write` _Sample Buffer_ (its index
|
|
||||||
in the array of pointers).
|
|
||||||
|
|
||||||
* Unnamed Posix semaphores to do the required locking while using the ring
|
|
||||||
buffer.
|
|
||||||
|
|
||||||
Each _Sample Buffer_ contains:
|
|
||||||
|
|
||||||
* A `timestamp` variable, containing the position in the stream of the first
|
|
||||||
sample in the buffer
|
|
||||||
|
|
||||||
* A `data_len` variable, containing the amount of samples available to process
|
|
||||||
in the buffer
|
|
||||||
|
|
||||||
* An array of samples of size specified by the stream struct it is part of.
|
|
||||||
|
|
||||||
==== Posix Shared Memory format
|
|
||||||
|
|
||||||
The Posix Shared memory region shall be formatted applying the following
|
|
||||||
considerations:
|
|
||||||
|
|
||||||
* All pointers in the memory region are encoded as offsets from the start
|
|
||||||
address of the region itself, to allow different processes with different
|
|
||||||
address spaces to decode them.
|
|
||||||
|
|
||||||
* All structs must be force-aligned to 8 bytes
|
|
||||||
|
|
||||||
* Number of buffers must be power of 2 (2,4,8,16,...) - 4 appears to be plenty
|
|
||||||
|
|
||||||
* IQ samples format: One (complex) sample consists of 16bit i + 16bit q, so the
|
|
||||||
buffer size is number of IQ pairs.
|
|
||||||
|
|
||||||
* A reasonable per-buffer size (in samples) is 2500, since this happens to be
|
|
||||||
the ususal TX (downlink) buffer size used by _osmo-trx-ipc_ with the b210 (rx
|
|
||||||
over-the-wire packet size for the b210 is 2040 samples, so the larger value of
|
|
||||||
both is convenient).
|
|
||||||
|
|
||||||
TIP: See
|
|
||||||
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/shm.h[Transceiver52M/device/ipc/shm.h]
|
|
||||||
for the detailed definition of all the objects being part of the Posix Shared
|
|
||||||
memory region structure
|
|
||||||
|
|
||||||
==== Posix Shared Memory procedures
|
|
||||||
|
|
||||||
The queue in the shared memory area is not supposed to be used for actual
|
|
||||||
buffering of data, only for exchange, so the general expectation is that it is
|
|
||||||
mostly empty. The only exception to that might be minor processing delays, and
|
|
||||||
during startup.
|
|
||||||
|
|
||||||
Care must be taken to ensure that only timed waits for the mutex protecting it
|
|
||||||
and the condition variables are used, in order to ensure that no deadlock occurs
|
|
||||||
should the other side die/quit.
|
|
||||||
|
|
||||||
Thread cancellation should be disabled during reads/writes from/to the queue. In
|
|
||||||
general a timeout can be considered a non recoverable error during regular
|
|
||||||
processing after startup, at least with the current timeout value of one second.
|
|
||||||
|
|
||||||
Should over- or underflows occur a corresponding message should be sent towards
|
|
||||||
_osmo-trx-ipc_.
|
|
||||||
|
|
||||||
Upon **read** of `N` samples, the reader does something like:
|
|
||||||
|
|
||||||
. Acquire the semaphore in the channel's stream object.
|
|
||||||
|
|
||||||
. Read `stream->next_read`, if `next_read==next_write`, become blocked in
|
|
||||||
another sempahore (unlocking the previous one) until writer signals us, then
|
|
||||||
`buff = stream->buffers[next_read]`
|
|
||||||
|
|
||||||
. Read `buff->data_len` samples, reset the buffer data (`data_len=0`),
|
|
||||||
increment `next_read` and if read samples is `<N`, continue with next buffer
|
|
||||||
until `next_read==next_write`, then block again or if timeout elapsed, then we
|
|
||||||
reach conditon buffer underflow and `return len < N`.
|
|
||||||
|
|
||||||
. Release the semaphore
|
|
||||||
|
|
||||||
Upon **write** of `N` samples, the writer does something like:
|
|
||||||
|
|
||||||
. Acquire the semapore in the channel's stream object.
|
|
||||||
|
|
||||||
. Write samples to `buff = stream->buffers[next_write]`. If `data_len!=0`,
|
|
||||||
signal `buffer_overflow` (increase field in stream object) and probably
|
|
||||||
increase next_read`.
|
|
||||||
|
|
||||||
. Increase `next_write`.
|
|
||||||
|
|
||||||
. If `next_write` was `== next_read`, signal the reader through the other
|
|
||||||
semaphore that it can continue reading.
|
|
||||||
@@ -71,103 +71,3 @@ with a memory buffer. In this mode, data written to the USRP is actually stored
|
|||||||
in a buffer, and read commands to the USRP simply pull data from this buffer.
|
in a buffer, and read commands to the USRP simply pull data from this buffer.
|
||||||
This was very useful in early testing, and still may be useful in testing basic
|
This was very useful in early testing, and still may be useful in testing basic
|
||||||
Transceiver and radioInterface functionality.
|
Transceiver and radioInterface functionality.
|
||||||
|
|
||||||
|
|
||||||
[[backend_ipc]]
|
|
||||||
=== `osmo-trx-ipc` Inter Process Communication backend
|
|
||||||
|
|
||||||
This OsmoTRX model provides its own Inter Process Communication (IPC) interface
|
|
||||||
to drive the radio device driver (from now on the Driver), allowing for third
|
|
||||||
party processes to implement the lowest layer device-specific bits without being
|
|
||||||
affected by copyleft licenses of OsmoTRX.
|
|
||||||
|
|
||||||
For more information on such interface, see section <<ipc_if>>.
|
|
||||||
|
|
||||||
[[fig-backend-ipc]]
|
|
||||||
.Architecture with _osmo-trx-ipc_ and its IPC _Driver_
|
|
||||||
[graphviz]
|
|
||||||
----
|
|
||||||
digraph G {
|
|
||||||
rankdir=LR;
|
|
||||||
MS0 [label="MS"];
|
|
||||||
MS1 [label="MS"];
|
|
||||||
OsmoTRX [label="osmo-trx-ipc", color=red];
|
|
||||||
BTS;
|
|
||||||
|
|
||||||
subgraph cluster_ipc_driver {
|
|
||||||
label = "IPC Driver";
|
|
||||||
color=red;
|
|
||||||
RE [label = "Radio Equipment"];
|
|
||||||
REC [label="Radio Equipment Controller"];
|
|
||||||
RE->REC;
|
|
||||||
}
|
|
||||||
|
|
||||||
REC->OsmoTRX [label="IPC Interface", color=red];
|
|
||||||
|
|
||||||
MS0->RE [label="Um"];
|
|
||||||
MS1->RE [label="Um"];
|
|
||||||
OsmoTRX->BTS [label="bursts over UDP"];
|
|
||||||
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
A sample config file for this OsmoTRX model can be found in _osmo-trx.git_ https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg[doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg]
|
|
||||||
|
|
||||||
In the config file, the following VTY command can be used to set up the IPC UD Master Socket _osmo-trx-ipc_ will connect to at startup:
|
|
||||||
|
|
||||||
.Example: _osmo-trx-ipc_ will connect to UD Master Socket /tmp/ipc_sock0 upon startup
|
|
||||||
----
|
|
||||||
dev-args ipc_msock=/tmp/ipc_sock0
|
|
||||||
----
|
|
||||||
|
|
||||||
==== ipc-device-test
|
|
||||||
|
|
||||||
When built with `--with-ipc --with-uhd` configure options, _osmo-trx.git_ will
|
|
||||||
build the test program called _ipc-driver-test_. This program implements the
|
|
||||||
_Driver_ side of the osmo-trx-ipc interface (see <<ipc_if>> for more
|
|
||||||
information) on one side, and also interacts internally with UHD (eg B210 as
|
|
||||||
when using osmo-trx-uhd).
|
|
||||||
|
|
||||||
You can use this small program as a reference to:
|
|
||||||
|
|
||||||
* Test and experiment with _osmo-trx-ipc_.
|
|
||||||
|
|
||||||
* Write your own IPC _Driver_ connecting to osmo-trx-ipc.
|
|
||||||
|
|
||||||
[[fig-backend-ipc-device-test]]
|
|
||||||
.Architecture with _osmo-trx-ipc_ and ipc-device-test as IPC _Driver_
|
|
||||||
[graphviz]
|
|
||||||
----
|
|
||||||
digraph G {
|
|
||||||
rankdir=LR;
|
|
||||||
MS0 [label="MS"];
|
|
||||||
MS1 [label="MS"];
|
|
||||||
SDR;
|
|
||||||
ipc_device_test[label = "ipc-device-test", color=red];
|
|
||||||
OsmoTRX [label="osmo-trx-ipc", color=red];
|
|
||||||
BTS;
|
|
||||||
|
|
||||||
MS0->SDR [label="Um"];
|
|
||||||
MS1->SDR [label="Um"];
|
|
||||||
SDR->ipc_device_test [label="UHD"];
|
|
||||||
ipc_device_test->OsmoTRX [label="IPC Interface", color=red];
|
|
||||||
OsmoTRX->BTS [label="bursts over UDP"];
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
The code for this app is found here:
|
|
||||||
|
|
||||||
* https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/ipc-driver-test.h[Transceiver52M/device/ipc/ipc-driver-test.h]
|
|
||||||
|
|
||||||
* https://gitea.osmocom.org/cellular-infrastructure/osmo-trx/src/branch/master/Transceiver52M/device/ipc/ipc-driver-test.c[Transceiver52M/device/ipc/ipc-driver-test.c]
|
|
||||||
|
|
||||||
Those files use the server-side (_Driver_ side) code to operate the Posix Shared
|
|
||||||
Memory region implemented in files `shm.c`, `shm.h`, `ipc_shm.c` and `ipc_shm.h`
|
|
||||||
in the same directory.
|
|
||||||
|
|
||||||
Most of the code in that same directory is deliverately released under a BSD
|
|
||||||
license (unlike most of _osmo-trx.git_), allowing third parties to reuse/recycle
|
|
||||||
the code on their implemented _Driver_ program no matter it being proprietary or
|
|
||||||
under an open license. However, care must be taken with external dependencies,
|
|
||||||
as for instance shm.c uses the talloc memory allocator, which is GPL licensed
|
|
||||||
and hence cannot be used in a proprietary driver.
|
|
||||||
@@ -35,8 +35,6 @@ include::./common/chapters/vty_cpu_sched.adoc[]
|
|||||||
|
|
||||||
include::./common/chapters/trx_if.adoc[]
|
include::./common/chapters/trx_if.adoc[]
|
||||||
|
|
||||||
include::{srcdir}/chapters/ipc_if.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/port_numbers.adoc[]
|
include::./common/chapters/port_numbers.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/bibliography.adoc[]
|
include::./common/chapters/bibliography.adoc[]
|
||||||
|
|||||||
Reference in New Issue
Block a user