trxcon/scheduler: introduce and use struct sched_burst_req

Similar to what we do in osmo-bts-trx, group everything related to
an Uplink burst into a structure.  Pass a pointer to this structure
to the logical channel handlers.  This makes the code easier to read,
and facilitates sending NOPE indications to the transceiver
(will be introduced in the upcoming patch).

Get rid of sched_trx_handle_tx_burst(), and instead just call
sched_trx_a5_burst_enc() directly from sched_frame_clck_cb().

Change-Id: Id45b27180c233fdc42ae1ef0b195554dd299a056
Related: SYS#5313, OS#1569
changes/61/24661/4
Vadim Yanitskiy 2 years ago
parent c652349b4a
commit 529d54b13a
  1. 15
      src/host/trxcon/sched_lchan_desc.c
  2. 42
      src/host/trxcon/sched_lchan_pdtch.c
  3. 29
      src/host/trxcon/sched_lchan_rach.c
  4. 42
      src/host/trxcon/sched_lchan_tchf.c
  5. 35
      src/host/trxcon/sched_lchan_tchh.c
  6. 42
      src/host/trxcon/sched_lchan_xcch.c
  7. 54
      src/host/trxcon/sched_trx.c
  8. 22
      src/host/trxcon/sched_trx.h
  9. 23
      src/host/trxcon/trx_if.c
  10. 4
      src/host/trxcon/trx_if.h

@ -34,35 +34,40 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
const sbit_t *bits, const struct trx_meas_set *meas);
int tx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
int rx_sch_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct trx_meas_set *meas);
int tx_rach_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
int rx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct trx_meas_set *meas);
int tx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct trx_meas_set *meas);
int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct trx_meas_set *meas);
int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX] = {
[TRXC_IDLE] = {

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2018-2020 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -117,10 +118,10 @@ int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)
struct trx_lchan_state *lchan,
struct sched_burst_req *br)
{
const struct trx_lchan_desc *lchan_desc;
ubit_t burst[GSM_BURST_LEN];
ubit_t *buffer, *offset;
const uint8_t *tsc;
uint8_t *mask;
@ -131,7 +132,7 @@ int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
mask = &lchan->tx_burst_mask;
buffer = lchan->tx_bursts;
if (bid > 0) {
if (br->bid > 0) {
/* If we have encoded bursts */
if (*mask)
goto send_burst;
@ -155,40 +156,29 @@ int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,
send_burst:
/* Determine which burst should be sent */
offset = buffer + bid * 116;
offset = buffer + br->bid * 116;
/* Update mask */
*mask |= (1 << bid);
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = sched_nb_training_bits[trx->tsc];
/* Compose a new burst */
memset(burst, 0, 3); /* TB */
memcpy(burst + 3, offset, 58); /* Payload 1/2 */
memcpy(burst + 61, tsc, 26); /* TSC */
memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(burst + 145, 0, 3); /* TB */
LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, fn, ts->index, bid);
/* Forward burst to scheduler */
rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);
if (rc) {
/* Forget this primitive */
sched_prim_drop(lchan);
memset(br->burst, 0, 3); /* TB */
memcpy(br->burst + 3, offset, 58); /* Payload 1/2 */
memcpy(br->burst + 61, tsc, 26); /* TSC */
memcpy(br->burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(br->burst + 145, 0, 3); /* TB */
br->burst_len = GSM_BURST_LEN;
/* Reset mask */
*mask = 0x00;
return rc;
}
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
/* If we have sent the last (4/4) burst */
if ((*mask & 0x0f) == 0x0f) {
/* Confirm data / traffic sending */
sched_send_dt_conf(trx, ts, lchan, fn, true);
sched_send_dt_conf(trx, ts, lchan, br->fn, true);
/* Forget processed primitive */
sched_prim_drop(lchan);

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2019 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -77,13 +78,13 @@ static struct value_string rach_synch_seq_names[] = {
/* Obtain a to-be-transmitted RACH burst */
int tx_rach_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)
struct trx_lchan_state *lchan,
struct sched_burst_req *br)
{
struct l1ctl_ext_rach_req *ext_req = NULL;
struct l1ctl_rach_req *req = NULL;
enum rach_synch_seq_t synch_seq;
uint8_t burst[GSM_BURST_LEN];
uint8_t *burst_ptr = burst;
uint8_t *burst_ptr = br->burst;
uint8_t payload[36];
int i, rc;
@ -155,27 +156,19 @@ int tx_rach_fn(struct trx_instance *trx, struct trx_ts *ts,
burst_ptr += RACH_PAYLOAD_LEN;
/* BN85-156: tail bits & extended guard period */
memset(burst_ptr, 0, burst + GSM_BURST_LEN - burst_ptr);
memset(burst_ptr, 0, br->burst + GSM_BURST_LEN - burst_ptr);
br->burst_len = GSM_BURST_LEN;
LOGP(DSCHD, LOGL_NOTICE, "Transmitting %s RACH (%s) on fn=%u, tn=%u, lchan=%s\n",
LOGP(DSCHD, LOGL_NOTICE, "Scheduled %s RACH (%s) on fn=%u, tn=%u, lchan=%s\n",
PRIM_IS_RACH11(lchan->prim) ? "extended (11-bit)" : "regular (8-bit)",
get_value_string(rach_synch_seq_names, synch_seq), fn,
get_value_string(rach_synch_seq_names, synch_seq), br->fn,
ts->index, trx_lchan_desc[lchan->type].name);
/* Forward burst to scheduler */
rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);
if (rc) {
/* Forget this primitive */
sched_prim_drop(lchan);
return rc;
}
/* Confirm RACH request */
l1ctl_tx_rach_conf(trx->l1l, trx->band_arfcn, fn);
l1ctl_tx_rach_conf(trx->l1l, trx->band_arfcn, br->fn);
/* Optional GSMTAP logging */
sched_gsmtap_send(lchan->type, fn, ts->index,
sched_gsmtap_send(lchan->type, br->fn, ts->index,
trx->band_arfcn | ARFCN_UPLINK, 0, 0,
PRIM_IS_RACH11(lchan->prim) ? (uint8_t *) &ext_req->ra11 : &req->ra,
PRIM_IS_RACH11(lchan->prim) ? 2 : 1);

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2020 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -173,10 +174,10 @@ bfi:
}
int tx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)
struct trx_lchan_state *lchan,
struct sched_burst_req *br)
{
const struct trx_lchan_desc *lchan_desc;
ubit_t burst[GSM_BURST_LEN];
ubit_t *buffer, *offset;
const uint8_t *tsc;
uint8_t *mask;
@ -193,7 +194,7 @@ int tx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
goto send_burst;
/* Wait until a first burst in period */
if (bid > 0)
if (br->bid > 0)
return 0;
/* Check the current TCH mode */
@ -257,40 +258,29 @@ int tx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,
send_burst:
/* Determine which burst should be sent */
offset = buffer + bid * 116;
offset = buffer + br->bid * 116;
/* Update mask */
*mask |= (1 << bid);
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = sched_nb_training_bits[trx->tsc];
/* Compose a new burst */
memset(burst, 0, 3); /* TB */
memcpy(burst + 3, offset, 58); /* Payload 1/2 */
memcpy(burst + 61, tsc, 26); /* TSC */
memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(burst + 145, 0, 3); /* TB */
LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, fn, ts->index, bid);
memset(br->burst, 0, 3); /* TB */
memcpy(br->burst + 3, offset, 58); /* Payload 1/2 */
memcpy(br->burst + 61, tsc, 26); /* TSC */
memcpy(br->burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(br->burst + 145, 0, 3); /* TB */
br->burst_len = GSM_BURST_LEN;
/* Forward burst to scheduler */
rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);
if (rc) {
/* Forget this primitive */
sched_prim_drop(lchan);
/* Reset mask */
*mask = 0x00;
return rc;
}
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
/* If we have sent the last (4/4) burst */
if (*mask == 0x0f) {
/* Confirm data / traffic sending */
sched_send_dt_conf(trx, ts, lchan, fn, PRIM_IS_TCH(lchan->prim));
sched_send_dt_conf(trx, ts, lchan, br->fn, PRIM_IS_TCH(lchan->prim));
/* Forget processed primitive */
sched_prim_drop(lchan);

@ -2,8 +2,9 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2018-2020 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018 by Harald Welte <laforge@gnumonks.org>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -361,10 +362,10 @@ bfi:
}
int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)
struct trx_lchan_state *lchan,
struct sched_burst_req *br)
{
const struct trx_lchan_desc *lchan_desc;
ubit_t burst[GSM_BURST_LEN];
ubit_t *buffer, *offset;
const uint8_t *tsc;
uint8_t *mask;
@ -376,7 +377,7 @@ int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
mask = &lchan->tx_burst_mask;
buffer = lchan->tx_bursts;
if (bid > 0) {
if (br->bid > 0) {
/* Align to the first burst */
if (*mask == 0x00)
return 0;
@ -386,7 +387,7 @@ int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
if (*mask == 0x00) {
/* Align transmission of the first FACCH/H frame */
if (lchan->tch_mode == GSM48_CMODE_SIGN)
if (!sched_tchh_facch_start(lchan->type, fn, 1))
if (!sched_tchh_facch_start(lchan->type, br->fn, 1))
return 0;
}
@ -459,26 +460,24 @@ int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,
send_burst:
/* Determine which burst should be sent */
offset = buffer + bid * 116;
offset = buffer + br->bid * 116;
/* Update mask */
*mask |= (1 << bid);
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = sched_nb_training_bits[trx->tsc];
/* Compose a new burst */
memset(burst, 0, 3); /* TB */
memcpy(burst + 3, offset, 58); /* Payload 1/2 */
memcpy(burst + 61, tsc, 26); /* TSC */
memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(burst + 145, 0, 3); /* TB */
LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, fn, ts->index, bid);
memset(br->burst, 0, 3); /* TB */
memcpy(br->burst + 3, offset, 58); /* Payload 1/2 */
memcpy(br->burst + 61, tsc, 26); /* TSC */
memcpy(br->burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(br->burst + 145, 0, 3); /* TB */
br->burst_len = GSM_BURST_LEN;
/* Forward burst to transceiver */
sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
/* In case of a FACCH/H frame, one block less */
if (lchan->ul_facch_blocks)
@ -490,7 +489,7 @@ send_burst:
* confirm data / traffic sending
*/
if (!lchan->ul_facch_blocks)
sched_send_dt_conf(trx, ts, lchan, fn,
sched_send_dt_conf(trx, ts, lchan, br->fn,
PRIM_IS_TCH(lchan->prim));
/* Forget processed primitive */

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2020 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -119,10 +120,10 @@ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
}
int tx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)
struct trx_lchan_state *lchan,
struct sched_burst_req *br)
{
const struct trx_lchan_desc *lchan_desc;
ubit_t burst[GSM_BURST_LEN];
ubit_t *buffer, *offset;
const uint8_t *tsc;
uint8_t *mask;
@ -133,7 +134,7 @@ int tx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
mask = &lchan->tx_burst_mask;
buffer = lchan->tx_bursts;
if (bid > 0) {
if (br->bid > 0) {
/* If we have encoded bursts */
if (*mask)
goto send_burst;
@ -165,40 +166,29 @@ int tx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
send_burst:
/* Determine which burst should be sent */
offset = buffer + bid * 116;
offset = buffer + br->bid * 116;
/* Update mask */
*mask |= (1 << bid);
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = sched_nb_training_bits[trx->tsc];
/* Compose a new burst */
memset(burst, 0, 3); /* TB */
memcpy(burst + 3, offset, 58); /* Payload 1/2 */
memcpy(burst + 61, tsc, 26); /* TSC */
memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(burst + 145, 0, 3); /* TB */
LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, fn, ts->index, bid);
/* Forward burst to scheduler */
rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);
if (rc) {
/* Forget this primitive */
sched_prim_drop(lchan);
/* Reset mask */
*mask = 0x00;
memset(br->burst, 0, 3); /* TB */
memcpy(br->burst + 3, offset, 58); /* Payload 1/2 */
memcpy(br->burst + 61, tsc, 26); /* TSC */
memcpy(br->burst + 87, offset + 58, 58); /* Payload 2/2 */
memset(br->burst + 145, 0, 3); /* TB */
br->burst_len = GSM_BURST_LEN;
return rc;
}
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
/* If we have sent the last (4/4) burst */
if ((*mask & 0x0f) == 0x0f) {
/* Confirm data sending */
sched_send_dt_conf(trx, ts, lchan, fn, false);
sched_send_dt_conf(trx, ts, lchan, br->fn, false);
/* Forget processed primitive */
sched_prim_drop(lchan);

@ -41,14 +41,18 @@
#include "trx_if.h"
#include "logging.h"
static void sched_trx_a5_burst_enc(struct trx_lchan_state *lchan,
struct sched_burst_req *br);
static void sched_frame_clck_cb(struct trx_sched *sched)
{
struct trx_instance *trx = (struct trx_instance *) sched->data;
struct sched_burst_req br[TRX_TS_COUNT];
const struct trx_frame *frame;
struct trx_lchan_state *lchan;
trx_lchan_tx_func *handler;
enum trx_lchan_type chan;
uint8_t offset, bid;
uint8_t offset;
struct trx_ts *ts;
int i;
@ -59,6 +63,14 @@ static void sched_frame_clck_cb(struct trx_sched *sched)
/* Iterate over timeslot list */
for (i = 0; i < TRX_TS_COUNT; i++) {
/* Initialize the buffer for this timeslot */
br[i] = (struct sched_burst_req) {
.fn = fn,
.tn = i,
.pwr = trx->tx_power,
.burst_len = 0, /* NOPE.ind */
};
/* Timeslot is not allocated */
ts = trx->ts_list[i];
if (ts == NULL)
@ -73,7 +85,7 @@ static void sched_frame_clck_cb(struct trx_sched *sched)
frame = ts->mf_layout->frames + offset;
/* Get required info from frame */
bid = frame->ul_bid;
br[i].bid = frame->ul_bid;
chan = frame->ul_chan;
handler = trx_lchan_desc[chan].tx_fn;
@ -120,8 +132,16 @@ static void sched_frame_clck_cb(struct trx_sched *sched)
handler = trx_lchan_desc[TRXC_RACH].tx_fn;
/* Poke lchan handler */
handler(trx, ts, lchan, fn, bid);
handler(trx, ts, lchan, &br[i]);
/* Perform A5/X burst encryption if required */
if (lchan->a5.algo)
sched_trx_a5_burst_enc(lchan, &br[i]);
}
/* Send all bursts for this TDMA frame */
for (i = 0; i < ARRAY_SIZE(br); i++)
trx_if_tx_burst(trx, &br[i]);
}
int sched_trx_init(struct trx_instance *trx, uint32_t fn_advance)
@ -602,18 +622,18 @@ static void sched_trx_a5_burst_dec(struct trx_lchan_state *lchan,
}
static void sched_trx_a5_burst_enc(struct trx_lchan_state *lchan,
uint32_t fn, ubit_t *burst)
struct sched_burst_req *br)
{
ubit_t ks[114];
int i;
/* Generate keystream for an UL burst */
osmo_a5(lchan->a5.algo, lchan->a5.key, fn, NULL, ks);
osmo_a5(lchan->a5.algo, lchan->a5.key, br->fn, NULL, ks);
/* Apply keystream over plaintext */
for (i = 0; i < 57; i++) {
burst[i + 3] ^= ks[i];
burst[i + 88] ^= ks[i + 57];
br->burst[i + 3] ^= ks[i];
br->burst[i + 88] ^= ks[i + 57];
}
}
@ -764,26 +784,6 @@ int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
return 0;
}
int sched_trx_handle_tx_burst(struct trx_instance *trx,
struct trx_ts *ts, struct trx_lchan_state *lchan,
uint32_t fn, ubit_t *bits)
{
int rc;
/* Perform A5/X burst encryption if required */
if (lchan->a5.algo)
sched_trx_a5_burst_enc(lchan, fn, bits);
/* Forward burst to transceiver */
rc = trx_if_tx_burst(trx, ts->index, fn, trx->tx_power, bits);
if (rc) {
LOGP(DSCHD, LOGL_ERROR, "Could not send burst to transceiver\n");
return rc;
}
return 0;
}
#define MEAS_HIST_FIRST(hist) \
(&hist->buf[0])
#define MEAS_HIST_LAST(hist) \

@ -97,14 +97,27 @@ enum trx_lchan_type {
_TRX_CHAN_MAX
};
/* Represents a burst to be transmitted */
struct sched_burst_req {
uint32_t fn;
uint8_t tn;
uint8_t pwr;
/* Internally used by the scheduler */
uint8_t bid;
ubit_t burst[EDGE_BURST_LEN];
size_t burst_len;
};
typedef int trx_lchan_rx_func(struct trx_instance *trx,
struct trx_ts *ts, struct trx_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct trx_meas_set *meas);
typedef int trx_lchan_tx_func(struct trx_instance *trx,
struct trx_ts *ts, struct trx_lchan_state *lchan,
uint32_t fn, uint8_t bid);
typedef int trx_lchan_tx_func(struct trx_instance *trx, struct trx_ts *ts,
struct trx_lchan_state *lchan,
struct sched_burst_req *br);
struct trx_lchan_desc {
/*! \brief Human-readable name */
@ -366,9 +379,6 @@ void sched_prim_flush_queue(struct llist_head *list);
int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
uint32_t fn, sbit_t *bits, uint16_t nbits,
const struct trx_meas_set *meas);
int sched_trx_handle_tx_burst(struct trx_instance *trx,
struct trx_ts *ts, struct trx_lchan_state *lchan,
uint32_t fn, ubit_t *bits);
/* Shared declarations for lchan handlers */
extern const uint8_t sched_nb_training_bits[8][26];

@ -629,10 +629,14 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
return 0;
}
int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
uint8_t pwr, const ubit_t *bits)
int trx_if_tx_burst(struct trx_instance *trx,
const struct sched_burst_req *br)
{
uint8_t buf[TRXD_BUF_SIZE];
size_t length;
if (br->burst_len == 0)
return 0;
/**
* We must be sure that we have clock,
@ -649,17 +653,20 @@ int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
}
#endif
LOGP(DTRXD, LOGL_DEBUG, "TX burst tn=%u fn=%u pwr=%u\n", tn, fn, pwr);
LOGP(DTRXD, LOGL_DEBUG, "TX burst tn=%u fn=%u pwr=%u\n",
br->tn, br->fn, br->pwr);
buf[0] = tn;
osmo_store32be(fn, buf + 1);
buf[5] = pwr;
buf[0] = br->tn;
osmo_store32be(br->fn, buf + 1);
buf[5] = br->pwr;
length = 6;
/* Copy ubits {0,1} */
memcpy(buf + 6, bits, 148);
memcpy(buf + 6, br->burst, br->burst_len);
length += br->burst_len;
/* Send data to transceiver */
send(trx->trx_ofd_data.fd, buf, 154, 0);
send(trx->trx_ofd_data.fd, buf, length, 0);
return 0;
}

@ -79,5 +79,5 @@ int trx_if_cmd_setfh(struct trx_instance *trx, uint8_t hsn,
int trx_if_cmd_measure(struct trx_instance *trx,
uint16_t band_arfcn_start, uint16_t band_arfcn_stop);
int trx_if_tx_burst(struct trx_instance *trx, uint8_t tn, uint32_t fn,
uint8_t pwr, const ubit_t *bits);
int trx_if_tx_burst(struct trx_instance *trx,
const struct sched_burst_req *br);

Loading…
Cancel
Save