Compare commits

..

3 Commits

Author SHA1 Message Date
Eric Wild
aa820c2ac1 ms: use queues with timeouts
Change-Id: I02e668a55dece96e421c82706b76bbb411ea6712
2024-03-18 20:31:06 +01:00
Eric Wild
db24660ac0 ms: prune ancient, unused code parts
Change-Id: I36dcb7ba9364b1eafbaa7267cde3574d82da5dd2
2024-03-18 20:30:56 +01:00
rpi5
47d0d93d9e cfg2
agc+rssi

XX

Change-Id: I01f68941964e2b7404f5c26bc7f7c60e5edc4ad2

vty xx

vty

cfg#

XX

Change-Id: I5c58561fc36a6f20b11c54dbbf024be0e993aabb

XX

Change-Id: Ia0abf8897f1488fe014670d8007269f50e1ddcae

XX

Change-Id: Ibea6c811e00e2d90428c7f5dfa3a9a00134aa389

XC

Change-Id: I13adf611eb7f56c3b17f645b4122bac154fc405c

xx

Change-Id: Id8f132a446e82982b6a1db8412e1b948945ee54a
2024-03-18 20:28:10 +01:00
32 changed files with 925 additions and 895 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
open_collective: osmocom

View File

@@ -28,7 +28,7 @@ std::vector<std::string> comma_delimited_to_vector(const char* opt)
{
std::string substr;
getline(ss, substr, ',');
result.push_back(std::move(substr));
result.push_back(substr);
}
return result;
}

View File

@@ -54,6 +54,7 @@ EXTRA_DIST = \
LEGAL \
COPYING \
README.md \
contrib/osmo-trx.spec.in \
debian \
git-version-gen \
$(NULL)

View File

@@ -4,17 +4,17 @@ About OsmoTRX
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*
* 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"
OsmoTRX is originally based on the transceiver code from the
[OpenBTS](https://osmocom.org/projects/osmobts/wiki/OpenBTS) project, but setup
to operate independently with the purpose of using with non-OpenBTS software and
projects, specifically within the Osmocom stack. Used together with
[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
--------
@@ -27,7 +27,7 @@ GIT Repository
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>
@@ -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
<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
------------
@@ -57,20 +50,13 @@ Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
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
------------
Our coding standards are described at
<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>
for more details

View File

@@ -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

View File

@@ -97,6 +97,7 @@ MS_UPPER_SRC = \
ms/ms_upper.cpp \
ms/l1ctl_server.c \
ms/logging.c \
ms/mssdr_vty.c \
ms/l1ctl_server_cb.cpp \
ms/ms_trxcon_if.cpp
@@ -110,6 +111,7 @@ noinst_HEADERS += \
ms/itrq.h \
ms/sch.h \
ms/threadpool.h \
ms/mssdr_vty.h \
grgsm_vitac/viterbi_detector.h \
grgsm_vitac/constants.h \
grgsm_vitac/grgsm_vitac.h
@@ -127,16 +129,16 @@ osmo_trx_uhd_LDADD = \
$(UHD_LIBS)
osmo_trx_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
#if ENABLE_MS_TRX
#bin_PROGRAMS += osmo-trx-ms-uhd
#osmo_trx_ms_uhd_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
#osmo_trx_ms_uhd_LDADD = \
# $(builddir)/device/uhd/libdevice.la \
# $(COMMON_LDADD) \
# $(UHD_LIBS) \
# $(TRXCON_LDADD)
#osmo_trx_ms_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS) -DBUILDUHD
#endif
if ENABLE_MS_TRX
bin_PROGRAMS += osmo-trx-ms-uhd
osmo_trx_ms_uhd_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
osmo_trx_ms_uhd_LDADD = \
$(builddir)/device/uhd/libdevice.la \
$(COMMON_LDADD) \
$(UHD_LIBS) \
$(TRXCON_LDADD)
osmo_trx_ms_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS) -DBUILDUHD
endif
endif
if DEVICE_USRP1

View File

@@ -32,6 +32,9 @@
#include <libbladeRF.h>
#include <Timeval.h>
#include <unistd.h>
extern "C" {
#include "mssdr_vty.h"
}
const size_t BLADE_BUFFER_SIZE = 1024 * 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>;
const unsigned int rxFullScale, txFullScale;
const int rxtxdelay;
bool use_agc;
float rxgain, txgain;
static std::atomic<bool> stop_lower_threads_flag;
double rxfreq_cache, txfreq_cache;
@@ -205,9 +208,13 @@ struct blade_hw {
int rx_freq;
int sample_rate;
int bandwidth;
float rxgain;
float txgain;
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;
@@ -223,10 +230,14 @@ struct blade_hw {
{
close_device();
}
blade_hw()
: rxFullScale(2047), txFullScale(2047), rxtxdelay(-60), rxgain(30), txgain(30), rxfreq_cache(0),
blade_hw(struct mssdr_cfg *cfgdata)
: rxFullScale(2047), txFullScale(2047), rxtxdelay(-60), use_agc(cfgdata->use_agc), rxfreq_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()
@@ -251,6 +262,7 @@ struct blade_hw {
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;
std::cerr << "cfg: ul " << cfg.tx_freq << " dl " << cfg.rx_freq << std::endl;
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
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,
(bladerf_bandwidth *)NULL);
blade_check(bladerf_set_gain_mode, dev, BLADERF_CHANNEL_RX(0), BLADERF_GAIN_MGC);
setRxGain(rxgain, 0);
setTxGain(txgain, 0);
blade_check(bladerf_set_gain_mode, dev, BLADERF_CHANNEL_RX(0),
use_agc ? BLADERF_GAIN_AUTOMATIC : BLADERF_GAIN_MGC);
setRxGain(cfg.rxgain, 0);
setTxGain(cfg.txgain, 0);
usleep(1000);
bladerf_set_stream_timeout(dev, BLADERF_TX, 10);
@@ -350,7 +363,7 @@ struct blade_hw {
double setRxGain(double dB, size_t chan = 0)
{
rxgain = dB;
cfg.rxgain = dB;
msleep(15);
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_RX(0), (bladerf_gain)dB);
msleep(15);
@@ -358,7 +371,7 @@ struct blade_hw {
};
double setTxGain(double dB, size_t chan = 0)
{
txgain = dB;
cfg.txgain = dB;
msleep(15);
blade_check(bladerf_set_gain, dev, BLADERF_CHANNEL_TX(0), (bladerf_gain)dB);
msleep(15);

View File

@@ -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
struct sched_hw_info {
int hw_cpus;
@@ -239,7 +237,7 @@ struct ms_trx : public BASET, public sched_hw_info {
unsigned int mTSC;
unsigned int mBSIC;
int timing_advance;
bool do_auto_gain;
bool use_va;
pthread_t lower_rx_task;
pthread_t lower_tx_task;
@@ -276,8 +274,8 @@ struct ms_trx : public BASET, public sched_hw_info {
void *tx_cb();
void maybe_update_gain(one_burst &brst);
ms_trx()
: mTSC(0), mBSIC(0), timing_advance(0), do_auto_gain(false), rxqueue(),
ms_trx(struct mssdr_cfg *cfgdata)
: 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]),
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)

View File

@@ -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;
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);
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
if (newgain != rxgain && newgain <= 60) {
if (newgain != cfg.rxgain && newgain <= 60) {
auto gain_fun = [this, newgain] { setRxGain(newgain); };
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))
;
if (do_auto_gain)
if (!use_agc)
maybe_update_gain(brst);
return false;
@@ -158,7 +158,7 @@ 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 which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
#if 1
if (use_va) {
const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
@@ -175,7 +175,7 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
#if 0
#if 0 // useful to debug offset shifts
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;
@@ -202,13 +202,14 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
return true;
} else {
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
<< ":" << current_gsm_time.TN() << std::endl;
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " "
<< current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
}
#else
} else {
const auto ts_offset_symb = 4;
auto burst = new signalVector(buf_len, 50);
const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
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
@@ -243,8 +244,8 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
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;
DBGLG() << "FIRST SCH : " << (rv2 ? "yes " : " ") << "Timing offset " << ebp2.toa
<< " symbols" << std::endl;
bits = demodAnyBurst(*delay, SCH, 4, &ebp2);
delete delay;
@@ -290,12 +291,12 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
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;
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;
}
@@ -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);
//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);
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;
setRxGain(rxgain + 4);
setRxGain(cfg.rxgain + 4);
}
if (!sch_thread_done)

View File

@@ -37,6 +37,6 @@ struct internal_q_tx_buf {
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 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>;

View File

@@ -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 workbuf_size = zero_pad_len + ONE_TS_BURST_LEN + zero_pad_len;
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);
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_rsp 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;
}
if (is_fcch) {
// return trash
@@ -199,7 +203,7 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
return true;
}
#if 1
if (use_va) {
convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
pow = energyDetect(sv, 20 * 4 /*sps*/);
@@ -233,8 +237,7 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
#endif
}
#else
} 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);
@@ -267,9 +270,8 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
demodded_softbits[ii] = *burstItr++ > 0.0f ? -127 : 127;
}
delete bits;
#endif
RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
}
RSSI = meas_rssi; // (int)floor(20.0 * log10(rxFullScale / avg));
// FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
timingOffset = (int)round(0);
@@ -419,13 +421,13 @@ bool upper_trx::driveControl()
r.param.measure.band_arfcn = cmd.param.measure.band_arfcn;
// FIXME: do we want to measure anything, considering the transceiver just syncs by.. syncing?
r.param.measure.dbm = -80;
tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
// tuneRx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 0) * 1000 * 100);
// tuneTx(gsm_arfcn2freq10(cmd.param.measure.band_arfcn, 1) * 1000 * 100);
cmdq_from_phy.spsc_push(&r);
break;
case TRXCON_PHYIF_CMDT_SETFREQ_H0:
tuneRx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 0) * 1000 * 100);
tuneTx(gsm_arfcn2freq10(cmd.param.setfreq_h0.band_arfcn, 1) * 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);
break;
case TRXCON_PHYIF_CMDT_SETFREQ_H1:
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[])
{
auto tall_trxcon_ctx = talloc_init("trxcon context");
@@ -476,6 +484,41 @@ int main(int argc, char *argv[])
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->gsmtap = nullptr;
g_trxcon->phyif = nullptr;
@@ -487,8 +530,7 @@ int main(int argc, char *argv[])
initvita();
int status = 0;
auto trx = new upper_trx();
trx->do_auto_gain = true;
auto trx = new upper_trx(&g_mssdr_ctx->cfg);
status = trx->init_dev_and_streams();
if (status < 0) {

View File

@@ -44,5 +44,6 @@ class upper_trx : public ms_trx {
void driveReceiveFIFO();
void driveTx();
upper_trx() : mOn(false){};
upper_trx() = delete;
explicit upper_trx(struct mssdr_cfg *cfgdata) : ms_trx(cfgdata), mOn(false){};
};

View 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;
}

View 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;

View File

@@ -645,7 +645,6 @@ int main(int argc, char *argv[])
osmo_init_logging2(tall_trx_ctx, &log_info);
log_enable_multithread();
log_cache_enable();
osmo_stats_init(tall_trx_ctx);
vty_init(&g_vty_info);
logging_vty_add_cmds();

View File

@@ -82,10 +82,10 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.9.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
@@ -240,6 +240,7 @@ AS_IF([test "x$with_sse" != "xno"], [
AM_CONDITIONAL(HAVE_SSE4_1, false)
])
dnl Check if the compiler supports specified GCC's built-in function
AC_DEFUN([CHECK_BUILTIN_SUPPORT], [
AC_CACHE_CHECK(
[whether ${CC} has $1 built-in],
@@ -379,5 +380,6 @@ AC_CONFIG_FILES([\
contrib/Makefile \
contrib/systemd/Makefile \
doc/manuals/Makefile \
contrib/osmo-trx.spec \
])
AC_OUTPUT

View File

@@ -9,19 +9,60 @@
#
set -ex
case "$INSTR" in
"--with-neon"*)
case "$(arch)" in
arm*)
;;
*)
set +x
echo "ERROR: trying to build with INSTR=$INSTR but not running on a 32-bit arm machine! (arch=$(arch))"
exit 1
;;
esac
;;
esac
substr() { [ -z "${2##*$1*}" ]; }
#apt-get install qemu qemu-user-static qemu-system-arm debootstrap fakeroot proot
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.
# PROOT_NO_SECCOMP is required due to proot bug #106
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 "$@"
}
mychroot() {
mychroot_nocwd -w / "$@"
}
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
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
View 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

View File

@@ -8,11 +8,8 @@ Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-trx-ipc -C /etc/osmocom/osmo-trx-ipc.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

View File

@@ -8,11 +8,8 @@ Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-trx-lms -C /etc/osmocom/osmo-trx-lms.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

View File

@@ -8,12 +8,9 @@ Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Environment=HOME=%S/osmocom
User=osmocom
Group=osmocom
Environment=HOME=%h
ExecStart=/usr/bin/osmo-trx-uhd -C /etc/osmocom/osmo-trx-uhd.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

View File

@@ -8,11 +8,8 @@ Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-trx-usrp1 -C /etc/osmocom/osmo-trx-usrp1.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

62
debian/changelog vendored
View File

@@ -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
[ Vadim Yanitskiy ]

4
debian/control vendored
View File

@@ -15,8 +15,8 @@ Build-Depends: debhelper (>= 10),
libusrp-dev,
liblimesuite-dev,
libbladerf-dev,
libosmocore-dev (>= 1.10.0),
osmo-gsm-manuals-dev (>= 1.6.0)
libosmocore-dev (>= 1.9.0),
osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.6
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-trx

View File

@@ -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#

View File

@@ -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#

View File

@@ -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#

View File

@@ -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#

View File

@@ -9,7 +9,7 @@ digraph hierarchy {
node[shape=record,style=filled,fillcolor=gray95]
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|...}"]
4[label = "{RadioInterfaceResamp|...}"]
5[label = "{RadioInterfaceMulti|...}"]
@@ -17,7 +17,6 @@ edge[dir=back, arrowtail=empty]
7[label = "{UHDDevice|...}"]
8[label = "{LMSDevice|...}"]
9[label = "{USRPDevice|...}"]
10[label = "{IPCDevice|...}"]
2->3[arrowtail=odiamond]
3->4[constraint=false]
@@ -26,7 +25,6 @@ edge[dir=back, arrowtail=empty]
6->7
6->8
6->9
6->10
}
----

View File

@@ -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.

View File

@@ -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.
This was very useful in early testing, and still may be useful in testing basic
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.

View File

@@ -35,8 +35,6 @@ include::./common/chapters/vty_cpu_sched.adoc[]
include::./common/chapters/trx_if.adoc[]
include::{srcdir}/chapters/ipc_if.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]