ms: make app configurable
This adds proper config options. The ul/dl freq lines can be copied from the osmo-trx (network side) cfg. Change-Id: Ibd432f7abbd00065a59104d2c006b676d5db7b47
This commit is contained in:
parent
3d8598d460
commit
238891f161
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -239,7 +239,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 +276,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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -160,10 +160,11 @@ static void *static_alloc(size_t newSize)
|
|||
|
||||
bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
|
||||
{
|
||||
float pow, avg = 1.0;
|
||||
// float pow, avg = 1.0;
|
||||
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,16 +203,16 @@ 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*/);
|
||||
if (pow < -1) {
|
||||
LOG(ALERT) << "Received empty burst";
|
||||
return false;
|
||||
}
|
||||
// pow = energyDetect(sv, 20 * 4 /*sps*/);
|
||||
// if (pow < -1) {
|
||||
// LOG(ALERT) << "Received empty burst";
|
||||
// return false;
|
||||
// }
|
||||
|
||||
avg = sqrt(pow);
|
||||
// avg = sqrt(pow);
|
||||
{
|
||||
float ncmax;
|
||||
std::complex<float> chan_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
|
||||
|
@ -233,18 +237,17 @@ 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);
|
||||
|
||||
pow = energyDetect(sv, 20 * 4 /*sps*/);
|
||||
if (pow < -1) {
|
||||
LOG(ALERT) << "Received empty burst";
|
||||
return false;
|
||||
}
|
||||
// pow = energyDetect(sv, 20 * 4 /*sps*/);
|
||||
// if (pow < -1) {
|
||||
// LOG(ALERT) << "Received empty burst";
|
||||
// return false;
|
||||
// }
|
||||
|
||||
avg = sqrt(pow);
|
||||
// avg = sqrt(pow);
|
||||
|
||||
/* Detect normal or RACH bursts */
|
||||
CorrType type = CorrType::TSC;
|
||||
|
@ -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,22 @@ 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 parse config file: '%s'\n", config_file);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
g_trxcon = trxcon_inst_alloc(tall_trxcon_ctx, 0);
|
||||
g_trxcon->gsmtap = nullptr;
|
||||
g_trxcon->phyif = nullptr;
|
||||
|
@ -487,8 +511,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) {
|
||||
|
|
|
@ -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){};
|
||||
};
|
||||
|
|
|
@ -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, " 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, " 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,
|
||||
"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;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#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 {
|
||||
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;
|
|
@ -8,6 +8,7 @@ EXTRA_DIST = \
|
|||
osmo-trx-lms/osmo-trx-limesdr.cfg \
|
||||
osmo-trx-lms/osmo-trx-lms.cfg \
|
||||
osmo-trx-ipc/osmo-trx-ipc.cfg \
|
||||
osmo-trx-ms-blade/mssdr.cfg \
|
||||
$(NULL)
|
||||
|
||||
OSMOCONF_FILES =
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level set-all notice
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
# cpu-sched
|
||||
# policy rr 18
|
||||
mssdr
|
||||
ul-freq-override 881e6
|
||||
dl-freq-override 926e6
|
||||
ul-gain-override 30
|
||||
dl-gain-override 30
|
||||
viterbi-eq enable
|
||||
rx-agc enable
|
||||
|
Loading…
Reference in New Issue