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", &params)) {
+  } 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", &params)) {
+    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", &params)) {
+    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", &params)) {
+    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", &params)) {
-    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", &params)) {
-    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", &params)) {
-    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", &params)) {
-    // 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", &params)) {
-    // 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", &params)) {
-    // 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", &params)) {
+    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", &timeslot, &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", &params)) {
+    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", &params)) {
+    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", &params)) {
+    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]>

Reply via email to