fixeria has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-trx/+/43115?usp=email )
Change subject: Transceiver52M: migrate to libosmo-trx
......................................................................
Transceiver52M: migrate to libosmo-trx
Replace the local TRXC/TRXD implementation with libosmo-trx's shared
osmo_trxc_msg/osmo_trxd_burst_{ind,req} API, including SETSLOT parsing
via osmo_trxc_setslot_parse()/_build(). Take a chance to fix SETSLOT
to always send a response, distinguishing bogus input from unsupported
VAMOS channel combinations.
Only the TRXC/TRXD build/parse API is used here, not the osmo_trx_ep
endpoint API: osmo-trx runs its socket I/O on dedicated threads that
don't drive osmo_select_main(), which osmo_trx_ep depends on.
Change-Id: I458ec85c56e2101d073c8c35f11c147191c4ea0c
Related: OS#5283
---
M Transceiver52M/Makefile.am
M Transceiver52M/Transceiver.cpp
M Transceiver52M/Transceiver.h
D Transceiver52M/proto_trxd.c
D Transceiver52M/proto_trxd.h
5 files changed, 292 insertions(+), 480 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/15/43115/1
diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am
index 74152b3..794f8b4 100644
--- a/Transceiver52M/Makefile.am
+++ b/Transceiver52M/Makefile.am
@@ -23,9 +23,28 @@
SUBDIRS = arch device
-AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/arch/common
-I${srcdir}/device/common
-AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
$(LIBOSMOVTY_CFLAGS)
-AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
$(LIBOSMOVTY_CFLAGS)
+AM_CPPFLAGS = \
+ -Wall \
+ $(STD_DEFINES_AND_INCLUDES) \
+ -I${srcdir}/arch/common \
+ -I${srcdir}/device/common \
+ -I$(top_srcdir)/libosmo-trx/include \
+ -I$(top_builddir)/libosmo-trx/include \
+ $(NULL)
+
+AM_CXXFLAGS = \
+ -lpthread \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(NULL)
+
+AM_CFLAGS = \
+ -lpthread \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(NULL)
noinst_LTLIBRARIES = libtransceiver_common.la
@@ -37,7 +56,6 @@
sigProcLib.cpp \
signalVector.cpp \
Transceiver.cpp \
- proto_trxd.c \
grgsm_vitac/grgsm_vitac.cpp \
grgsm_vitac/viterbi_detector.cc
@@ -67,8 +85,7 @@
sigProcLib.h \
signalVector.h \
Transceiver.h \
- Resampler.h \
- proto_trxd.h
+ Resampler.h
if ENABLE_MULTI_ARFCN
noinst_HEADERS += \
@@ -80,6 +97,7 @@
COMMON_LDADD = \
libtransceiver_common.la \
+ $(top_builddir)/libosmo-trx/src/libosmotrx.la \
$(ARCH_LA) \
$(GSM_LA) \
$(COMMON_LA) \
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
index 46d06db..20a568a 100644
--- a/Transceiver52M/Transceiver.cpp
+++ b/Transceiver52M/Transceiver.cpp
@@ -33,12 +33,14 @@
extern "C" {
#include "osmo_signal.h"
-#include "proto_trxd.h"
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
#include <osmocom/vty/cpu_sched_vty.h>
+#include <osmocom/trx/trxc.h>
+#include <osmocom/trx/trxd.h>
}
#ifdef HAVE_CONFIG_H
@@ -655,6 +657,21 @@
};
#endif
+/* Convert a soft bit normalized to 0..1 (1.0 = confident '1') into the
+ * sbit_t domain (-127..127) used by osmo_trxd_burst_ind, matching the wire
+ * encoding of osmo_trxd_burst_ind_build()/soft_bits_build() (byte = 127 -
+ * sbit): a value of 1.0 rounds to a raw byte of 255, which the TRXD wire
+ * format reserves as -127 (see soft_bits_parse()), so clamp accordingly. */
+static inline sbit_t float_soft_bit_to_sbit(float x)
+{
+ int v = 127 - (int) lround(x * 255.0);
+ if (v > 127)
+ v = 127;
+ if (v < -127)
+ v = -127;
+ return (sbit_t) v;
+}
+
/*
* Pull bursts from the FIFO and handle according to the slot
* and burst correlation type. Equalzation is currently disabled.
@@ -662,7 +679,7 @@
* -ENOENT: timeslot is off (fn and tn in bi are filled),
* -EIO: read error
*/
-int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
+int Transceiver::pullRadioVector(size_t chan, struct osmo_trxd_burst_ind *bi)
{
int rc;
struct estim_burst_params ebp;
@@ -675,6 +692,7 @@
TransceiverState *state = &mStates[chan];
bool ctr_changed = false;
double rssi_offset;
+ float soft_bits[OSMO_TRXD_BURST_LEN_MAX];
static complex burst_shift_buffer[625];
static signalVector shift_vec(burst_shift_buffer, 0, 625, dummy_alloc,
dummy_free);
signalVector *shvec_ptr = &shift_vec;
@@ -691,17 +709,12 @@
CorrType type = expectedCorrType(burstTime, chan);
/* Initialize struct bi */
- bi->nbits = 0;
+ memset(bi, 0, sizeof(*bi));
+ bi->flags = OSMO_TRXD_F_MOD_TYPE | OSMO_TRXD_F_TS_INFO | OSMO_TRXD_F_CI_CB;
bi->fn = burstTime.FN();
bi->tn = burstTime.TN();
- bi->rssi = 0.0;
- bi->toa = 0.0;
- bi->noise = 0.0;
- bi->idle = false;
- bi->modulation = MODULATION_GMSK;
- bi->tss = 0; /* TODO: we only support tss 0 right now */
- bi->tsc = 0;
- bi->ci = 0.0;
+ bi->mod = OSMO_TRXD_MOD_T_GMSK;
+ bi->tsc_set = 0; /* TODO: we only support tsc_set 0 right now */
/* Debug: dump bursts to disk */
/* bits 0-7 - chan 0 timeslots
@@ -748,8 +761,7 @@
}
rssi_offset = rssiOffset(chan);
- bi->rssi = 20.0 * log10(rxFullScale / avg) + rssi_offset;
- bi->noise = 20.0 * log10(rxFullScale / state->mNoiseLev) + rssi_offset;
+ bi->rssi = (int8_t) lround(-(20.0 * log10(rxFullScale / avg) + rssi_offset));
if (type == IDLE)
goto ret_idle;
@@ -786,21 +798,23 @@
rxBurst = demodAnyBurst(*shvec_ptr, (CorrType)rc, cfg->rx_sps, &ebp);
}
- bi->toa = ebp.toa;
+ bi->toa256 = (int16_t) lround(ebp.toa * 256.0);
bi->tsc = ebp.tsc;
- bi->ci = ebp.ci;
+ bi->ci_cb = (int16_t) ((ebp.ci * 10) + 0.5);
/* EDGE demodulator returns 444 (gSlotLen * 3) bits */
if (rxBurst->size() == EDGE_BURST_NBITS) {
- bi->modulation = MODULATION_8PSK;
- bi->nbits = EDGE_BURST_NBITS;
+ bi->mod = OSMO_TRXD_MOD_T_8PSK;
+ bi->burst_len = EDGE_BURST_NBITS;
} else { /* size() here is actually gSlotLen + 8, due to guard periods */
- bi->modulation = MODULATION_GMSK;
- bi->nbits = gSlotLen;
+ bi->mod = OSMO_TRXD_MOD_T_GMSK;
+ bi->burst_len = gSlotLen;
}
- // Convert -1..+1 soft bits to 0..1 soft bits
- vectorSlicer(bi->rx_burst, rxBurst->begin(), bi->nbits);
+ // Convert -1..+1 soft bits to 0..1 soft bits, then to the sbit_t wire domain
+ vectorSlicer(soft_bits, rxBurst->begin(), bi->burst_len);
+ for (size_t i = 0; i < bi->burst_len; i++)
+ bi->burst[i] = float_soft_bit_to_sbit(soft_bits[i]);
delete rxBurst;
delete radio_burst;
@@ -809,7 +823,8 @@
ret_idle:
if (ctr_changed)
dispatch_trx_rate_ctr_change(state, chan);
- bi->idle = true;
+ bi->flags |= OSMO_TRXD_F_NOPE_IND;
+ bi->burst_len = 0;
delete radio_burst;
return 0;
}
@@ -820,36 +835,6 @@
mTxPriorityQueues[i].clear();
}
-
-/**
- * Matches a buffer with a command.
- * @param buf a buffer to look command in
- * @param cmd a command to look in buffer
- * @param params pointer to arguments, or NULL
- * @return true if command matches, otherwise false
- */
-static bool match_cmd(const char *buf,
- const char *cmd, const char **params)
-{
- size_t cmd_len = strlen(cmd);
-
- /* Check a command itself */
- if (strncmp(buf, cmd, cmd_len))
- return false;
-
- /* A command has arguments */
- if (params != NULL) {
- /* Make sure there is a space */
- if (buf[cmd_len] != ' ')
- return false;
-
- /* Update external pointer */
- *params = buf + cmd_len + 1;
- }
-
- return true;
-}
-
void Transceiver::ctrl_sock_send(ctrl_msg& m, int chan)
{
ctrl_sock_state& s = mCtrlSockets[chan];
@@ -896,17 +881,15 @@
int Transceiver::ctrl_sock_handle_rx(int chan)
{
+ struct osmo_trxc_msg cmd, rsp;
ctrl_msg cmd_received;
ctrl_msg cmd_to_send;
- char *buffer = cmd_received.data;
- char *response = cmd_to_send.data;
- const size_t response_size = sizeof(cmd_to_send.data);
- const char *command, *params;
int msgLen;
+ int rc;
ctrl_sock_state& s = mCtrlSockets[chan];
/* Attempt to read from control socket */
- msgLen = read(s.conn_bfd.fd, buffer, sizeof(cmd_received.data)-1);
+ msgLen = read(s.conn_bfd.fd, cmd_received.data, sizeof(cmd_received.data) -
1);
if (msgLen < 0 && errno == EAGAIN)
return 0; /* Try again later */
if (msgLen <= 0) {
@@ -914,184 +897,196 @@
return -EIO;
}
-
- /* Zero-terminate received string */
- buffer[msgLen] = '\0';
-
- /* Verify a command signature */
- if (strncmp(buffer, "CMD ", 4)) {
+ rc = osmo_trxc_msg_parse(&cmd, cmd_received.data, msgLen);
+ if (rc < 0 || cmd.type != OSMO_TRXC_MT_CMD) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
return -EIO;
}
- /* Set command pointer */
- command = buffer + 4;
- LOGCHAN(chan, DTRXCTRL, INFO) << "command is '" << command << "'";
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.type = OSMO_TRXC_MT_RSP;
+ rsp.status = 1; /* default: NACK, cleared to 0 on the success path of each
verb below */
+ snprintf(rsp.cmd, sizeof(rsp.cmd), "%s", cmd.cmd);
- if (match_cmd(command, "POWEROFF", NULL)) {
+ LOGCHAN(chan, DTRXCTRL, INFO) << "command is '" << osmo_trxc_msg_name(&cmd)
<< "'";
+
+ if (!strcmp(cmd.cmd, "POWEROFF")) {
stop();
- snprintf(response, response_size, "RSP POWEROFF 0");
- } else if (match_cmd(command, "POWERON", NULL)) {
- if (!start()) {
- snprintf(response, response_size, "RSP POWERON 1");
- } else {
- snprintf(response, response_size, "RSP POWERON 0");
+ rsp.status = 0;
+ } else if (!strcmp(cmd.cmd, "POWERON")) {
+ if (start()) {
+ rsp.status = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++)
mHandover[i][j] = false;
}
}
- } else if (match_cmd(command, "HANDOVER", ¶ms)) {
+ } else if (!strcmp(cmd.cmd, "HANDOVER")) {
unsigned ts = 0, ss = 0;
- sscanf(params, "%u %u", &ts, &ss);
- if (ts > 7 || ss > 7) {
- snprintf(response, response_size, "RSP HANDOVER 1 %u %u", ts, ss);
- } else {
+ if (osmo_trxc_msg_params_scan(&cmd, "%u %u", &ts, &ss) == 2 && ts <= 7 &&
ss <= 7) {
mHandover[ts][ss] = true;
- snprintf(response, response_size, "RSP HANDOVER 0 %u %u", ts, ss);
+ rsp.status = 0;
}
- } else if (match_cmd(command, "NOHANDOVER", ¶ms)) {
+ snprintf(rsp.params, sizeof(rsp.params), "%u %u", ts, ss);
+ } else if (!strcmp(cmd.cmd, "NOHANDOVER")) {
unsigned ts = 0, ss = 0;
- sscanf(params, "%u %u", &ts, &ss);
- if (ts > 7 || ss > 7) {
- snprintf(response, response_size, "RSP NOHANDOVER 1 %u %u", ts, ss);
- } else {
+ if (osmo_trxc_msg_params_scan(&cmd, "%u %u", &ts, &ss) == 2 && ts <= 7 &&
ss <= 7) {
mHandover[ts][ss] = false;
- snprintf(response, response_size, "RSP NOHANDOVER 0 %u %u", ts, ss);
+ rsp.status = 0;
}
- } else if (match_cmd(command, "SETMAXDLY", ¶ms)) {
+ snprintf(rsp.params, sizeof(rsp.params), "%u %u", ts, ss);
+ } else if (!strcmp(cmd.cmd, "SETMAXDLY")) {
//set expected maximum time-of-arrival for Access Bursts
- int maxDelay;
- sscanf(params, "%d", &maxDelay);
- mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
- snprintf(response, response_size, "RSP SETMAXDLY 0 %d", maxDelay);
- } else if (match_cmd(command, "SETMAXDLYNB", ¶ms)) {
+ int maxDelay = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &maxDelay) == 1) {
+ mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", maxDelay);
+ } else if (!strcmp(cmd.cmd, "SETMAXDLYNB")) {
//set expected maximum time-of-arrival for Normal Bursts
- int maxDelay;
- sscanf(params, "%d", &maxDelay);
- mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
- snprintf(response, response_size, "RSP SETMAXDLYNB 0 %d", maxDelay);
- } else if (match_cmd(command, "SETRXGAIN", ¶ms)) {
- int newGain;
- sscanf(params, "%d", &newGain);
- newGain = mRadioInterface->setRxGain(newGain, chan);
- snprintf(response, response_size, "RSP SETRXGAIN 0 %d", newGain);
- } else if (match_cmd(command, "NOISELEV", NULL)) {
+ int maxDelay = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &maxDelay) == 1) {
+ mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", maxDelay);
+ } else if (!strcmp(cmd.cmd, "SETRXGAIN")) {
+ int newGain = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &newGain) == 1) {
+ newGain = mRadioInterface->setRxGain(newGain, chan);
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", newGain);
+ } else if (!strcmp(cmd.cmd, "NOISELEV")) {
if (mOn) {
float lev = mStates[chan].mNoiseLev;
- snprintf(response, response_size, "RSP NOISELEV 0 %d",
+ rsp.status = 0;
+ snprintf(rsp.params, sizeof(rsp.params), "%d",
(int) round(20.0 * log10(rxFullScale / lev)));
- }
- else {
- snprintf(response, response_size, "RSP NOISELEV 1 0");
- }
- } else if (match_cmd(command, "SETPOWER", ¶ms)) {
- int power;
- sscanf(params, "%d", &power);
- power = mRadioInterface->setPowerAttenuation(power, chan);
- mStates[chan].mPower = power;
- snprintf(response, response_size, "RSP SETPOWER 0 %d", power);
- } else if (match_cmd(command, "ADJPOWER", ¶ms)) {
- int power, step;
- sscanf(params, "%d", &step);
- power = mStates[chan].mPower + step;
- power = mRadioInterface->setPowerAttenuation(power, chan);
- mStates[chan].mPower = power;
- snprintf(response, response_size, "RSP ADJPOWER 0 %d", power);
- } else if (match_cmd(command, "NOMTXPOWER", NULL)) {
- int power = mRadioInterface->getNominalTxPower(chan);
- snprintf(response, response_size, "RSP NOMTXPOWER 0 %d", power);
- } else if (match_cmd(command, "RXTUNE", ¶ms)) {
- // tune receiver
- int freqKhz;
- sscanf(params, "%d", &freqKhz);
- mRxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
- if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
- LOGCHAN(chan, DTRXCTRL, FATAL) << "RX failed to tune";
- snprintf(response, response_size, "RSP RXTUNE 1 %d", freqKhz);
- }
- else
- snprintf(response, response_size, "RSP RXTUNE 0 %d", freqKhz);
- } else if (match_cmd(command, "TXTUNE", ¶ms)) {
- // tune txmtr
- int freqKhz;
- sscanf(params, "%d", &freqKhz);
- mTxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
- if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
- LOGCHAN(chan, DTRXCTRL, FATAL) << "TX failed to tune";
- snprintf(response, response_size, "RSP TXTUNE 1 %d", freqKhz);
- }
- else
- snprintf(response, response_size, "RSP TXTUNE 0 %d", freqKhz);
- } else if (match_cmd(command, "SETTSC", ¶ms)) {
- // set TSC
- unsigned TSC;
- sscanf(params, "%u", &TSC);
- if (TSC > 7) {
- snprintf(response, response_size, "RSP SETTSC 1 %d", TSC);
} else {
+ snprintf(rsp.params, sizeof(rsp.params), "0");
+ }
+ } else if (!strcmp(cmd.cmd, "SETPOWER")) {
+ int power = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &power) == 1) {
+ power = mRadioInterface->setPowerAttenuation(power, chan);
+ mStates[chan].mPower = power;
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", power);
+ } else if (!strcmp(cmd.cmd, "ADJPOWER")) {
+ int power = mStates[chan].mPower, step;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &step) == 1) {
+ power = mStates[chan].mPower + step;
+ power = mRadioInterface->setPowerAttenuation(power, chan);
+ mStates[chan].mPower = power;
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", power);
+ } else if (!strcmp(cmd.cmd, "NOMTXPOWER")) {
+ int power = mRadioInterface->getNominalTxPower(chan);
+ rsp.status = 0;
+ snprintf(rsp.params, sizeof(rsp.params), "%d", power);
+ } else if (!strcmp(cmd.cmd, "RXTUNE")) {
+ // tune receiver
+ int freqKhz = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &freqKhz) == 1) {
+ mRxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
+ if (!mRadioInterface->tuneRx(mRxFreq, chan))
+ LOGCHAN(chan, DTRXCTRL, FATAL) << "RX failed to tune";
+ else
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", freqKhz);
+ } else if (!strcmp(cmd.cmd, "TXTUNE")) {
+ // tune txmtr
+ int freqKhz = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &freqKhz) == 1) {
+ mTxFreq = (freqKhz + cfg->freq_offset_khz) * 1e3;
+ if (!mRadioInterface->tuneTx(mTxFreq, chan))
+ LOGCHAN(chan, DTRXCTRL, FATAL) << "TX failed to tune";
+ else
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", freqKhz);
+ } else if (!strcmp(cmd.cmd, "SETTSC")) {
+ // set TSC
+ unsigned TSC = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%u", &TSC) == 1 && TSC <= 7) {
LOGC(DTRXCTRL, NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
mTSC = TSC;
- snprintf(response, response_size, "RSP SETTSC 0 %d", TSC);
+ rsp.status = 0;
}
- } else if (match_cmd(command, "SETSLOT", ¶ms)) {
+ snprintf(rsp.params, sizeof(rsp.params), "%u", TSC);
+ } else if (!strcmp(cmd.cmd, "SETSLOT")) {
// set slot type
- int corrCode;
- int timeslot;
- sscanf(params, "%d %d", ×lot, &corrCode);
- if ((timeslot < 0) || (timeslot > 7)) {
+ struct osmo_trxc_setslot ss;
+ if (osmo_trxc_setslot_parse(&ss, &cmd) < 0) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
- snprintf(response, response_size, "RSP SETSLOT 1 %d %d", timeslot,
corrCode);
- return 0;
+ } else if (ss.vamos) {
+ LOGCHAN(chan, DTRXCTRL, NOTICE) << "VAMOS channel combinations are not
supported";
+ } else {
+ mStates[chan].chanType[ss.tn] = (ChannelCombination) ss.chan_comb;
+ setModulus(ss.tn, chan);
+ rsp.status = 0;
}
- mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
- setModulus(timeslot, chan);
- snprintf(response, response_size, "RSP SETSLOT 0 %d %d", timeslot,
corrCode);
- } else if (match_cmd(command, "SETFORMAT", ¶ms)) {
+ snprintf(rsp.params, sizeof(rsp.params), "%s", cmd.params);
+ } else if (!strcmp(cmd.cmd, "SETFORMAT")) {
// set TRXD protocol version
- unsigned version_recv;
- sscanf(params, "%u", &version_recv);
+ unsigned version_recv = 0;
+ osmo_trxc_msg_params_scan(&cmd, "%u", &version_recv);
LOGCHAN(chan, DTRXCTRL, INFO) << "BTS requests TRXD version switch: " <<
version_recv;
if (version_recv > TRX_DATA_FORMAT_VER) {
LOGCHAN(chan, DTRXCTRL, INFO) << "rejecting TRXD version " <<
version_recv
<< " in favor of " << TRX_DATA_FORMAT_VER;
- snprintf(response, response_size, "RSP SETFORMAT %u %u",
TRX_DATA_FORMAT_VER, version_recv);
+ rsp.status = TRX_DATA_FORMAT_VER;
} else {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "switching to TRXD version " <<
version_recv;
mVersionTRXD[chan] = version_recv;
- snprintf(response, response_size, "RSP SETFORMAT %u %u", version_recv,
version_recv);
+ rsp.status = version_recv;
}
- } else if (match_cmd(command, "RFMUTE", ¶ms)) {
+ snprintf(rsp.params, sizeof(rsp.params), "%u", version_recv);
+ } else if (!strcmp(cmd.cmd, "RFMUTE")) {
// (Un)mute RF TX and RX
- unsigned mute;
- sscanf(params, "%u", &mute);
- mStates[chan].mMuted = mute ? true : false;
- snprintf(response, response_size, "RSP RFMUTE 0 %u", mute);
- } else if (match_cmd(command, "_SETBURSTTODISKMASK", ¶ms)) {
+ unsigned mute = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%u", &mute) == 1) {
+ mStates[chan].mMuted = mute ? true : false;
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%u", mute);
+ } else if (!strcmp(cmd.cmd, "_SETBURSTTODISKMASK")) {
// debug command! may change or disappear without notice
// set a mask which bursts to dump to disk
- int mask;
- sscanf(params, "%d", &mask);
- mWriteBurstToDiskMask = mask;
- snprintf(response, response_size, "RSP _SETBURSTTODISKMASK 0 %d", mask);
+ int mask = 0;
+ if (osmo_trxc_msg_params_scan(&cmd, "%d", &mask) == 1) {
+ mWriteBurstToDiskMask = mask;
+ rsp.status = 0;
+ }
+ snprintf(rsp.params, sizeof(rsp.params), "%d", mask);
} else {
- LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus command " << command << " on
control interface.";
- snprintf(response, response_size, "RSP ERR 1");
+ LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus command " << cmd.cmd << " on
control interface.";
+ snprintf(rsp.cmd, sizeof(rsp.cmd), "%s", OSMO_TRXC_CMD_ERR);
}
- LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
- transceiver->ctrl_sock_send(cmd_to_send, chan);
+ LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << osmo_trxc_msg_name(&rsp)
<< "'";
+
+ rc = osmo_trxc_msg_build(cmd_to_send.data, sizeof(cmd_to_send.data), &rsp);
+ if (rc < 0) {
+ LOGCHAN(chan, DTRXCTRL, ERROR) << "failed to build response (rc=" << rc <<
")";
+ return -EIO;
+ }
+ ctrl_sock_send(cmd_to_send, chan);
return 0;
}
bool Transceiver::driveTxPriorityQueue(size_t chan)
{
+ char buffer[OSMO_TRXD_MSG_BUF_SIZE];
int msgLen;
- int burstLen;
- struct trxd_hdr_v01_dl *dl;
- char buffer[sizeof(*dl) + EDGE_BURST_NBITS];
- uint32_t fn;
- uint8_t tn;
+ struct osmo_trxd_parse_state st;
+ struct osmo_trxd_burst_req br;
+ int rc;
// check data socket
msgLen = read(mDataSockets[chan], buffer, sizeof(buffer));
@@ -1100,48 +1095,37 @@
return false;
}
- switch (msgLen) {
- case sizeof(*dl) + gSlotLen: /* GSM burst */
- burstLen = gSlotLen;
- break;
- case sizeof(*dl) + EDGE_BURST_NBITS: /* EDGE burst */
- if (cfg->tx_sps != 4) {
- LOGCHAN(chan, DTRXDDL, ERROR) << "EDGE burst received but SPS is set
to " << cfg->tx_sps;
- return false;
- }
- burstLen = EDGE_BURST_NBITS;
- break;
- default:
- LOGCHAN(chan, DTRXDDL, ERROR) << "badly formatted packet on GSM->TRX
interface (len="<< msgLen << ")";
- return false;
- }
-
- dl = (struct trxd_hdr_v01_dl *) buffer;
-
- /* Convert TDMA FN to the host endianness */
- fn = osmo_load32be(&dl->common.fn);
- tn = dl->common.tn;
-
- /* Make sure we support the received header format */
- switch (dl->common.version) {
- case 0:
- /* Version 1 has the same format */
- case 1:
- break;
- default:
- LOGCHAN(chan, DTRXDDL, ERROR) << "Rx TRXD message with unknown header
version " << unsigned(dl->common.version);
+ osmo_trxd_parse_state_init(&st);
+ rc = osmo_trxd_burst_req_parse(&st, &br, (const uint8_t *) buffer, msgLen);
+ if (rc < 0) {
+ LOGCHAN(chan, DTRXDDL, ERROR) << "failed to parse BURST.req (rc=" << rc <<
")";
return false;
}
- LOGCHAN(chan, DTRXDDL, DEBUG) << "Rx TRXD message (hdr_ver=" <<
unsigned(dl->common.version)
- << "): fn=" << fn << ", tn=" << unsigned(tn) << ", burst_len=" << burstLen;
+ switch (br.burst_len) {
+ case gSlotLen: /* GSM burst */
+ break;
+ case EDGE_BURST_NBITS: /* EDGE burst */
+ if (cfg->tx_sps != 4) {
+ LOGCHAN(chan, DTRXDDL, ERROR) << "EDGE burst received but SPS is set to
" << cfg->tx_sps;
+ return false;
+ }
+ break;
+ default:
+ LOGCHAN(chan, DTRXDDL, ERROR) << "badly formatted packet on GSM->TRX
interface (burst_len="
+ << br.burst_len << ")";
+ return false;
+ }
+
+ LOGCHAN(chan, DTRXDDL, DEBUG) << "Rx TRXD message: fn=" << br.fn << ", tn="
<< unsigned(br.tn)
+ << ", burst_len=" << br.burst_len;
TransceiverState *state = &mStates[chan];
- GSM::Time currTime = GSM::Time(fn, tn);
+ GSM::Time currTime = GSM::Time(br.fn, br.tn);
/* Verify proper FN order in DL stream */
- if (state->first_dl_fn_rcv[tn]) {
- int32_t delta = GSM::FNDelta(currTime.FN(),
state->last_dl_time_rcv[tn].FN());
+ if (state->first_dl_fn_rcv[br.tn]) {
+ int32_t delta = GSM::FNDelta(currTime.FN(),
state->last_dl_time_rcv[br.tn].FN());
if (delta == 1) {
/* usual expected scenario, continue code flow */
} else if (delta == 0) {
@@ -1151,7 +1135,7 @@
return true;
} else if (delta < 0) {
LOGCHAN(chan, DTRXDDL, INFO) << "Rx TRXD msg with previous FN " <<
currTime
- << " vs last " <<
state->last_dl_time_rcv[tn];
+ << " vs last " <<
state->last_dl_time_rcv[br.tn];
state->ctrs.tx_trxd_fn_outoforder++;
dispatch_trx_rate_ctr_change(state, chan);
/* Allow adding radio vector below, since it gets sorted in the queue */
@@ -1161,25 +1145,25 @@
* setups. Also, osmo-trx supports optionally filling empty bursts on
* its own. In that case bts-trx is not obliged to submit all bursts.
*/
LOGCHAN(chan, DTRXDDL, INFO) << "Rx TRXD msg with future FN " << currTime
- << " vs last " <<
state->last_dl_time_rcv[tn]
+ << " vs last " <<
state->last_dl_time_rcv[br.tn]
<< ", " << delta - 1 << " FN lost";
state->ctrs.tx_trxd_fn_skipped += delta - 1;
dispatch_trx_rate_ctr_change(state, chan);
}
if (delta > 0)
- state->last_dl_time_rcv[tn] = currTime;
+ state->last_dl_time_rcv[br.tn] = currTime;
} else { /* Initial check, simply store state */
- state->first_dl_fn_rcv[tn] = true;
- state->last_dl_time_rcv[tn] = currTime;
+ state->first_dl_fn_rcv[br.tn] = true;
+ state->last_dl_time_rcv[br.tn] = currTime;
}
- BitVector newBurst(burstLen);
+ BitVector newBurst(br.burst_len);
BitVector::iterator itr = newBurst.begin();
- uint8_t *bufferItr = dl->soft_bits;
+ const ubit_t *bufferItr = br.burst;
while (itr < newBurst.end())
*itr++ = *bufferItr++;
- addRadioVector(chan, newBurst, dl->tx_att, currTime);
+ addRadioVector(chan, newBurst, br.att, currTime);
return true;
}
@@ -1203,32 +1187,36 @@
return true;
}
-void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
+void Transceiver::logRxBurst(size_t chan, const struct osmo_trxd_burst_ind *bi)
{
std::ostringstream os;
- for (size_t i=0; i < bi->nbits; i++) {
- if (bi->rx_burst[i] > 0.5) os << "1";
- else if (bi->rx_burst[i] > 0.25) os << "|";
- else if (bi->rx_burst[i] > 0.0) os << "'";
+ for (size_t i = 0; i < bi->burst_len; i++) {
+ /* sbit_t polarity: <0 confident '1', 127 confident '0' (see
float_soft_bit_to_sbit()) */
+ if (bi->burst[i] < 0) os << "1";
+ else if (bi->burst[i] < 64) os << "|";
+ else if (bi->burst[i] < 127) os << "'";
else os << "-";
}
double rssi_offset = rssiOffset(chan);
+ double noise_dbfs = 20.0 * log10(rxFullScale / mStates[chan].mNoiseLev) +
rssi_offset;
+ double rssi_dbfs = -bi->rssi - rssi_offset;
LOGCHAN(chan, DTRXDUL, DEBUG) << std::fixed << std::right
<< " time: " << unsigned(bi->tn) << ":" << bi->fn
- << " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi -
rssi_offset)
- << "dBFS/" << std::setw(6) << -bi->rssi << "dBm"
- << " noise: " << std::setw(5) << std::setprecision(1) << (bi->noise -
rssi_offset)
- << "dBFS/" << std::setw(6) << -bi->noise << "dBm"
- << " TOA: " << std::setw(5) << std::setprecision(2) << bi->toa
- << " C/I: " << std::setw(5) << std::setprecision(2) << bi->ci << "dB"
+ << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi_dbfs
+ << "dBFS/" << std::setw(6) << int(bi->rssi) << "dBm"
+ << " noise: " << std::setw(5) << std::setprecision(1) << (noise_dbfs -
rssi_offset)
+ << "dBFS/" << std::setw(6) << -noise_dbfs << "dBm"
+ << " TOA: " << std::setw(5) << std::setprecision(2) << (bi->toa256 /
256.0)
+ << " C/I: " << std::setw(5) << std::setprecision(2) << (bi->ci_cb /
10.0) << "dB"
<< " bits: " << os;
}
bool Transceiver::driveReceiveFIFO(size_t chan)
{
- struct trx_ul_burst_ind bi;
+ struct osmo_trxd_burst_ind bi;
+ struct msgb *msg;
int rc;
if ((rc = pullRadioVector(chan, &bi)) < 0) {
@@ -1239,17 +1227,29 @@
return false; /* other errors: we want to stop the process */
}
- if (!bi.idle && log_check_level(DTRXDUL, LOGL_DEBUG))
+ if (!(bi.flags & OSMO_TRXD_F_NOPE_IND) && log_check_level(DTRXDUL,
LOGL_DEBUG))
logRxBurst(chan, &bi);
- switch (mVersionTRXD[chan]) {
- case 0:
- return trxd_send_burst_ind_v0(chan, mDataSockets[chan], &bi);
- case 1:
- return trxd_send_burst_ind_v1(chan, mDataSockets[chan], &bi);
- default:
- OSMO_ASSERT(false);
+ msg = msgb_alloc(OSMO_TRXD_MSG_BUF_SIZE, "trxd_burst_ind");
+ if (!msg)
+ return false;
+
+ rc = osmo_trxd_burst_ind_build(msg, mVersionTRXD[chan], &bi);
+ if (rc < 0) {
+ LOGCHAN(chan, DTRXDUL, ERROR) << "failed to build BURST.ind (rc=" << rc <<
")";
+ msgb_free(msg);
+ return false;
}
+ osmo_trxd_build_fin(msg, mVersionTRXD[chan]);
+
+ rc = write(mDataSockets[chan], msgb_data(msg), msgb_length(msg));
+ msgb_free(msg);
+ if (rc < 0) {
+ LOGCHAN(chan, DTRXDUL, NOTICE) << "mDataSockets write(" <<
mDataSockets[chan] << ") failed: " << rc;
+ return false;
+ }
+
+ return true;
}
void Transceiver::driveTxFIFO()
@@ -1310,16 +1310,22 @@
bool Transceiver::writeClockInterface()
{
- int msgLen;
- char command[50];
+ char command[64];
+ int rc;
// FIXME -- This should be adaptive.
- sprintf(command,"IND CLOCK %llu",(unsigned long long)
(mTransmitDeadlineClock.FN()+2));
+ uint32_t fn = mTransmitDeadlineClock.FN() + 2;
+
+ rc = osmo_trxc_clock_ind_build(command, sizeof(command), fn);
+ if (rc < 0) {
+ LOGC(DTRXCLK, ERROR) << "failed to build IND CLOCK " << fn;
+ return false;
+ }
LOGC(DTRXCLK, INFO) << "sending " << command;
- msgLen = write(mClockSocket, command, strlen(command) + 1);
- if (msgLen <= 0) {
- LOGC(DTRXCLK, ERROR) << "mClockSocket write(" << mClockSocket << ")
failed: " << msgLen;
+ rc = write(mClockSocket, command, strlen(command) + 1);
+ if (rc <= 0) {
+ LOGC(DTRXCLK, ERROR) << "mClockSocket write(" << mClockSocket << ")
failed: " << rc;
return false;
}
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
index babe420..8d27db9 100644
--- a/Transceiver52M/Transceiver.h
+++ b/Transceiver52M/Transceiver.h
@@ -34,6 +34,8 @@
extern "C" {
#include <osmocom/core/signal.h>
#include <osmocom/core/select.h>
+#include <osmocom/trx/trxc.h>
+#include <osmocom/trx/trxd.h>
#include "config_defs.h"
}
@@ -41,6 +43,9 @@
extern Transceiver *transceiver;
+/* The latest TRXD header format version advertised/accepted by this TRX
implementation */
+#define TRX_DATA_FORMAT_VER 1
+
/** Channel descriptor for transceiver object and channel number pair */
struct TrxChanThParams {
Transceiver *trx;
@@ -150,10 +155,9 @@
private:
size_t mChans;
struct ctrl_msg {
- char data[101];
+ char data[OSMO_TRXC_MSG_BUF_SIZE];
ctrl_msg() {};
};
-
struct ctrl_sock_state {
osmo_fd conn_bfd;
std::deque<ctrl_msg> txmsgqueue;
@@ -202,7 +206,7 @@
void pushRadioVector(GSM::Time &nowTime);
/** Pull and demodulate a burst from the receive FIFO */
- int pullRadioVector(size_t chan, struct trx_ul_burst_ind *ind);
+ int pullRadioVector(size_t chan, struct osmo_trxd_burst_ind *ind);
/** Set modulus for specific timeslot */
void setModulus(size_t timeslot, size_t chan);
@@ -264,7 +268,7 @@
double rssiOffset(size_t chan);
void reset();
- void logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi);
+ void logRxBurst(size_t chan, const struct osmo_trxd_burst_ind *bi);
};
void *RxUpperLoopAdapter(TrxChanThParams *params);
diff --git a/Transceiver52M/proto_trxd.c b/Transceiver52M/proto_trxd.c
deleted file mode 100644
index e5a889d..0000000
--- a/Transceiver52M/proto_trxd.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2019 sysmocom - s.f.m.c. GmbH
- * All Rights Reserved
- *
- * SPDX-License-Identifier: AGPL-3.0+
- *
- * Author: Pau Espin Pedrol <[email protected]>
- *
- * 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/>.
- * See the COPYING file in the main directory for details.
- */
-
-#include "proto_trxd.h"
-
-#include <osmocom/core/bits.h>
-
-static void trxd_fill_common(struct trxd_hdr_common *common, const struct
trx_ul_burst_ind *bi, uint8_t version)
-{
- common->version = version & 0b1111;
- common->reserved = 0;
- common->tn = bi->tn;
- osmo_store32be(bi->fn, &common->fn);
-}
-
-static void trxd_fill_v0_specific(struct trxd_hdr_v0_specific *v0, const
struct trx_ul_burst_ind *bi)
-{
- int toa_int;
-
- /* in 1/256 symbols, round to closest integer */
- toa_int = (int) (bi->toa * 256.0 + 0.5);
- v0->rssi = bi->rssi;
- osmo_store16be(toa_int, &v0->toa);
-}
-
-static void trxd_fill_v1_specific(struct trxd_hdr_v1_specific *v1, const
struct trx_ul_burst_ind *bi)
-{
- int16_t ci_int_cB;
-
- /* deciBels->centiBels, round to closest integer */
- ci_int_cB = (int16_t)((bi->ci * 10) + 0.5);
-
- v1->idle = !!bi->idle;
- v1->modulation = (bi->modulation == MODULATION_GMSK) ?
- TRXD_MODULATION_GMSK(bi->tss) :
- TRXD_MODULATION_8PSK(bi->tss);
- v1->tsc = bi->tsc;
- osmo_store16be(ci_int_cB, &v1->ci);
-}
-
-static void trxd_fill_burst_normalized255(uint8_t* soft_bits, const struct
trx_ul_burst_ind *bi)
-{
- unsigned i;
- for (i = 0; i < bi->nbits; i++)
- soft_bits[i] = (uint8_t) round(bi->rx_burst[i] * 255.0);
-}
-
-bool trxd_send_burst_ind_v0(size_t chan, int fd, const struct trx_ul_burst_ind
*bi) {
- int rc;
-
- /* v0 doesn't support idle frames, they are simply dropped, not sent */
- if (bi->idle)
- return true;
-
- /* +2: Historically (OpenBTS times), two extra non-used bytes are sent
appended to each burst */
- char buf[sizeof(struct trxd_hdr_v0) + bi->nbits + 2];
- struct trxd_hdr_v0* pkt = (struct trxd_hdr_v0*)buf;
-
- trxd_fill_common(&pkt->common, bi, 0);
- trxd_fill_v0_specific(&pkt->v0, bi);
- trxd_fill_burst_normalized255(&pkt->soft_bits[0], bi);
-
- /* +1: Historical reason. There's an uninitizalied byte in there:
pkt->soft_bits[bi->nbits] */
- pkt->soft_bits[bi->nbits + 1] = '\0';
-
- rc = write(fd, buf, sizeof(struct trxd_hdr_v0) + bi->nbits + 2);
- if (rc <= 0) {
- CLOGCHAN(chan, DMAIN, LOGL_NOTICE, "mDataSockets write(%d)
failed: %d\n", fd, rc);
- return false;
- }
- return true;
-}
-
-bool trxd_send_burst_ind_v1(size_t chan, int fd, const struct trx_ul_burst_ind
*bi) {
- int rc;
- size_t buf_len;
-
- buf_len = sizeof(struct trxd_hdr_v1);
- if (!bi->idle)
- buf_len += bi->nbits;
- char buf[buf_len];
-
- struct trxd_hdr_v1* pkt = (struct trxd_hdr_v1*)buf;
- trxd_fill_common(&pkt->common, bi, 1);
- trxd_fill_v0_specific(&pkt->v0, bi);
- trxd_fill_v1_specific(&pkt->v1, bi);
-
- if (!bi->idle)
- trxd_fill_burst_normalized255(&pkt->soft_bits[0], bi);
-
- rc = write(fd, buf, buf_len);
- if (rc <= 0) {
- CLOGCHAN(chan, DMAIN, LOGL_NOTICE, "mDataSockets write(%d)
failed: %d\n", fd, rc);
- return false;
- }
- return true;
-}
diff --git a/Transceiver52M/proto_trxd.h b/Transceiver52M/proto_trxd.h
deleted file mode 100644
index c250a74..0000000
--- a/Transceiver52M/proto_trxd.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <math.h>
-
-#include <osmocom/core/endian.h>
-
-#include "debug.h"
-
-#define MAX_RX_BURST_BUF_SIZE 444 /* 444 = EDGE_BURST_NBITS */
-
-enum Modulation {
- MODULATION_GMSK,
- MODULATION_8PSK,
-/* Not supported yet:
- MODULATION_AQPSK,
- MODULATION_16QAM,
- MODULATION_32QAM
-*/
-};
-
-struct trx_ul_burst_ind {
- float rx_burst[MAX_RX_BURST_BUF_SIZE]; /* soft bits normalized 0..1 */
- unsigned nbits; // number of symbols per slot in rxBurst, not counting
guard periods
- uint32_t fn; // TDMA frame number
- uint8_t tn; // TDMA time-slot number
- double rssi; // in dBFS
- double toa; // in symbols
- double noise; // noise level in dBFS
- bool idle; // true if no valid burst is included
- enum Modulation modulation; // modulation type
- uint8_t tss; // training sequence set
- uint8_t tsc; // training sequence code
- float ci; // Carrier-to-Interference ratio, in dB
-};
-
-bool trxd_send_burst_ind_v0(size_t chan, int fd, const struct trx_ul_burst_ind
*bi);
-bool trxd_send_burst_ind_v1(size_t chan, int fd, const struct trx_ul_burst_ind
*bi);
-
-/* The latest supported TRXD header format version */
-#define TRX_DATA_FORMAT_VER 1
-
-struct trxd_hdr_common {
-#if OSMO_IS_LITTLE_ENDIAN
- uint8_t tn:3,
- reserved:1,
- version:4;
-#elif OSMO_IS_BIG_ENDIAN
-/* auto-generated from the little endian part above
(libosmocore/contrib/struct_endianness.py) */
- uint8_t version:4, reserved:1, tn:3;
-#endif
- uint32_t fn; /* big endian */
-} __attribute__ ((packed));
-
-struct trxd_hdr_v0_specific {
- uint8_t rssi;
- uint16_t toa; /* big endian */
-} __attribute__ ((packed));
-
-struct trxd_hdr_v0 {
- struct trxd_hdr_common common;
- struct trxd_hdr_v0_specific v0;
- uint8_t soft_bits[0];
-} __attribute__ ((packed));
-
-/* Downlink burst (BTS->TRX), v0 anf v1 use same format */
-struct trxd_hdr_v01_dl {
- struct trxd_hdr_common common;
- uint8_t tx_att; /* Tx Attentuation */
- uint8_t soft_bits[0];
-} __attribute__ ((packed));
-
-
-#define TRXD_MODULATION_GMSK(ts_set) (0b0000 | (ts_set & 0b0011))
-#define TRXD_MODULATION_8PSK(ts_set) (0b0100 | (ts_set & 0b0001))
-#define TRXD_MODULATION_AQPSK(ts_set) (0b0110 | (ts_set & 0b0001))
-#define TRXD_MODULATION_16QAM(ts_set) (0b1000 | (ts_set & 0b0001))
-#define TRXD_MODULATION_32QAM(ts_set) (0b1010 | (ts_set & 0b0001))
-
-struct trxd_hdr_v1_specific {
-#if OSMO_IS_LITTLE_ENDIAN
- uint8_t tsc:3,
- modulation:4,
- idle:1;
-#elif OSMO_IS_BIG_ENDIAN
-/* auto-generated from the little endian part above
(libosmocore/contrib/struct_endianness.py) */
- uint8_t idle:1, modulation:4, tsc:3;
-#endif
- int16_t ci; /* big endian, in centiBels */
-} __attribute__ ((packed));
-
-struct trxd_hdr_v1 {
- struct trxd_hdr_common common;
- struct trxd_hdr_v0_specific v0;
- struct trxd_hdr_v1_specific v1;
- uint8_t soft_bits[0];
-} __attribute__ ((packed));
--
To view, visit https://gerrit.osmocom.org/c/osmo-trx/+/43115?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-Change-Id: I458ec85c56e2101d073c8c35f11c147191c4ea0c
Gerrit-Change-Number: 43115
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <[email protected]>