trxcon: abstract out the scheduler API from L1CTL/TRXD/TRXC

Change-Id: I31f77976a7a225ef292fe6dcd583513aec97ed44
Related: OS#5599, OS#3761
changes/54/28554/7
Vadim Yanitskiy 7 months ago
parent 97006ff1bd
commit 8428b1ea0a
  1. 2
      src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
  2. 3
      src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h
  3. 86
      src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h
  4. 11
      src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h
  5. 1
      src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
  6. 32
      src/host/trxcon/src/l1ctl.c
  7. 98
      src/host/trxcon/src/sched_lchan_common.c
  8. 46
      src/host/trxcon/src/sched_lchan_desc.c
  9. 29
      src/host/trxcon/src/sched_lchan_pdtch.c
  10. 34
      src/host/trxcon/src/sched_lchan_rach.c
  11. 43
      src/host/trxcon/src/sched_lchan_sch.c
  12. 49
      src/host/trxcon/src/sched_lchan_tchf.c
  13. 51
      src/host/trxcon/src/sched_lchan_tchh.c
  14. 38
      src/host/trxcon/src/sched_lchan_xcch.c
  15. 14
      src/host/trxcon/src/sched_prim.c
  16. 133
      src/host/trxcon/src/sched_trx.c
  17. 5
      src/host/trxcon/src/trx_if.c
  18. 193
      src/host/trxcon/src/trxcon.c

@ -11,7 +11,7 @@ int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg);
void l1ctl_shutdown_cb(struct l1ctl_link *l1l);
int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
struct l1ctl_info_dl *dl_info, uint8_t bsic);
const struct l1ctl_info_dl *dl_info, uint8_t bsic);
int l1ctl_tx_ccch_mode_conf(struct l1ctl_link *l1l, uint8_t mode);
int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
int dbm, int last);

@ -30,6 +30,9 @@ struct l1ctl_link {
struct osmo_fd listen_bfd;
struct osmo_wqueue wq;
/* Scheduler for this interface */
struct l1sched_state *sched;
/* Bind TRX instance */
struct trx_instance *trx;

@ -38,11 +38,9 @@
#define MAX_A5_KEY_LEN (128 / 8)
#define TRX_TS_COUNT 8
/* Forward declaration to avoid mutual include */
struct l1sched_lchan_state;
struct l1sched_meas_set;
struct l1sched_state;
struct trx_instance;
struct l1sched_ts;
enum l1sched_clck_state {
@ -109,6 +107,29 @@ enum l1sched_lchan_type {
_L1SCHED_CHAN_MAX
};
enum l1sched_data_type {
L1SCHED_DT_PACKET_DATA,
L1SCHED_DT_SIGNALING,
L1SCHED_DT_TRAFFIC,
L1SCHED_DT_OTHER, /* SCH and RACH */
};
enum l1sched_config_type {
/*! Channel combination for a timeslot */
L1SCHED_CFG_PCHAN_COMB,
};
/* Represents a (re)configuration request */
struct l1sched_config_req {
enum l1sched_config_type type;
union {
struct {
uint8_t tn;
uint8_t pchan;
} pchan_comb;
};
};
/* Represents a burst to be transmitted */
struct l1sched_burst_req {
uint32_t fn;
@ -122,13 +143,11 @@ struct l1sched_burst_req {
size_t burst_len;
};
typedef int l1sched_lchan_rx_func(struct trx_instance *trx,
struct l1sched_ts *ts, struct l1sched_lchan_state *lchan,
typedef int l1sched_lchan_rx_func(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
typedef int l1sched_lchan_tx_func(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
typedef int l1sched_lchan_tx_func(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
struct l1sched_lchan_desc {
@ -223,6 +242,8 @@ struct l1sched_lchan_state {
/*! Mode for TCH channels (see GSM48_CMODE_*) */
uint8_t tch_mode;
/*! Training Sequence Code */
uint8_t tsc;
/*! FACCH/H on downlink */
bool dl_ongoing_facch;
@ -297,8 +318,8 @@ struct l1sched_ts {
struct llist_head lchans;
/*! Queue primitives for TX */
struct llist_head tx_prims;
/* backpointer to its TRX */
struct trx_instance *trx;
/*! Backpointer to the scheduler */
struct l1sched_state *sched;
};
/* Represents one TX primitive in the queue of l1sched_ts */
@ -341,8 +362,10 @@ struct l1sched_state {
struct osmo_timer_list clock_timer;
/*! Frame callback */
void (*clock_cb)(struct l1sched_state *sched);
/*! Private data (e.g. pointer to trx instance) */
void *data;
/*! List of timeslots maintained by this scheduler */
struct l1sched_ts *ts_list[TRX_TS_COUNT];
/*! BSIC value learned from SCH bursts */
uint8_t bsic;
};
extern const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX];
@ -350,15 +373,15 @@ const struct l1sched_tdma_multiframe *l1sched_mframe_layout(
enum gsm_phys_chan_config config, int tn);
/* Scheduler management functions */
int l1sched_init(struct trx_instance *trx, uint32_t fn_advance);
int l1sched_reset(struct trx_instance *trx, bool reset_clock);
int l1sched_shutdown(struct trx_instance *trx);
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance);
void l1sched_reset(struct l1sched_state *sched, bool reset_clock);
void l1sched_free(struct l1sched_state *sched);
/* Timeslot management functions */
struct l1sched_ts *l1sched_add_ts(struct trx_instance *trx, int tn);
void l1sched_del_ts(struct trx_instance *trx, int tn);
int l1sched_reset_ts(struct trx_instance *trx, int tn);
int l1sched_configure_ts(struct trx_instance *trx, int tn,
struct l1sched_ts *l1sched_add_ts(struct l1sched_state *sched, int tn);
void l1sched_del_ts(struct l1sched_state *sched, int tn);
int l1sched_reset_ts(struct l1sched_state *sched, int tn);
int l1sched_configure_ts(struct l1sched_state *sched, int tn,
enum gsm_phys_chan_config config);
int l1sched_start_ciphering(struct l1sched_ts *ts, uint8_t algo,
uint8_t *key, uint8_t key_len);
@ -369,14 +392,15 @@ enum l1sched_lchan_type l1sched_chan_nr2lchan_type(uint8_t chan_nr,
uint8_t link_id);
void l1sched_deactivate_all_lchans(struct l1sched_ts *ts);
int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr, int active, uint8_t tch_mode);
int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr,
int active, uint8_t tch_mode, uint8_t tsc);
int l1sched_activate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan);
int l1sched_deactivate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan);
struct l1sched_lchan_state *l1sched_find_lchan(struct l1sched_ts *ts,
enum l1sched_lchan_type chan);
/* Primitive management functions */
struct l1sched_ts_prim *l1sched_prim_push(struct trx_instance *trx,
struct l1sched_ts_prim *l1sched_prim_push(struct l1sched_state *sched,
enum l1sched_ts_prim_type type,
uint8_t chan_nr, uint8_t link_id,
const uint8_t *pl, size_t pl_len);
@ -419,7 +443,7 @@ int l1sched_prim_dummy(struct l1sched_lchan_state *lchan);
void l1sched_prim_drop(struct l1sched_lchan_state *lchan);
void l1sched_prim_flush_queue(struct llist_head *list);
int l1sched_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
int l1sched_handle_rx_burst(struct l1sched_state *sched, uint8_t tn,
uint32_t fn, sbit_t *bits, uint16_t nbits,
const struct l1sched_meas_set *meas);
@ -428,14 +452,6 @@ extern const uint8_t l1sched_nb_training_bits[8][26];
const char *l1sched_burst_mask2str(const uint8_t *mask, int bits);
size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan);
int l1sched_send_dt_ind(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint8_t *l2, size_t l2_len,
int bit_error_count, bool dec_failed, bool traffic);
int l1sched_send_dt_conf(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, bool traffic);
int l1sched_gsmtap_send(enum l1sched_lchan_type lchan_type, uint32_t fn, uint8_t tn,
uint16_t band_arfcn, int8_t signal_dbm, uint8_t snr,
const uint8_t *data, size_t data_len);
/* Interleaved TCH/H block TDMA frame mapping */
uint32_t l1sched_tchh_block_dl_first_fn(enum l1sched_lchan_type chan,
@ -459,3 +475,17 @@ void l1sched_lchan_meas_avg(struct l1sched_lchan_state *lchan, unsigned int n);
int l1sched_clck_handle(struct l1sched_state *sched, uint32_t fn);
void l1sched_clck_reset(struct l1sched_state *sched);
/* External L1 API, must be implemented by the API user */
int l1sched_handle_config_req(struct l1sched_state *sched,
const struct l1sched_config_req *cr);
int l1sched_handle_burst_req(struct l1sched_state *sched,
const struct l1sched_burst_req *br);
/* External L2 API, must be implemented by the API user */
int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
const uint8_t *data, size_t data_len,
int n_errors, int n_bits_total,
enum l1sched_data_type dt);
int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
uint32_t fn, enum l1sched_data_type dt);

@ -5,12 +5,12 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/fsm.h>
#include <osmocom/bb/trxcon/l1sched.h>
#define TRXC_BUF_SIZE 1024
#define TRXD_BUF_SIZE 512
/* Forward declaration to avoid mutual include */
struct l1sched_burst_req;
struct l1sched_state;
struct l1ctl_link;
enum trx_fsm_states {
@ -37,13 +37,10 @@ struct trx_instance {
uint16_t pm_band_arfcn_stop;
uint16_t band_arfcn;
uint8_t tx_power;
uint8_t bsic;
uint8_t tsc;
int8_t ta;
/* Scheduler stuff */
struct l1sched_state sched;
struct l1sched_ts *ts_list[TRX_TS_COUNT];
/* Scheduler for this interface */
struct l1sched_state *sched;
/* Bind L1CTL link */
struct l1ctl_link *l1l;

@ -3,7 +3,6 @@
#define GEN_MASK(state) (0x01 << state)
extern struct osmo_fsm_inst *trxcon_fsm;
extern struct gsmtap_inst *gsmtap;
enum trxcon_fsm_states {
TRXCON_STATE_IDLE = 0,

@ -164,7 +164,7 @@ static struct l1ctl_fbsb_conf *fbsb_conf_make(struct msgb *msg, uint8_t result,
}
int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
struct l1ctl_info_dl *dl_info, uint8_t bsic)
const struct l1ctl_info_dl *dl_info, uint8_t bsic)
{
struct l1ctl_fbsb_conf *conf;
struct msgb *msg;
@ -174,7 +174,6 @@ int l1ctl_tx_fbsb_conf(struct l1ctl_link *l1l, uint8_t result,
return -ENOMEM;
put_dl_info_hdr(msg, dl_info);
talloc_free(dl_info);
conf = fbsb_conf_make(msg, result, bsic);
@ -344,10 +343,10 @@ static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
band_arfcn &~ ARFCN_FLAG_MASK);
/* Reset scheduler and clock counter */
l1sched_reset(l1l->trx, true);
l1sched_reset(l1l->sched, true);
/* Configure a single timeslot */
l1sched_configure_ts(l1l->trx, 0, ch_config);
l1sched_configure_ts(l1l->sched, 0, ch_config);
/* Ask SCH handler to send L1CTL_FBSB_CONF */
l1l->fbsb_conf_sent = false;
@ -434,7 +433,7 @@ static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Fall through */
case L1CTL_RES_T_SCHED:
l1sched_reset(l1l->trx, true);
l1sched_reset(l1l->sched, true);
break;
default:
LOGP(DL1C, LOGL_ERROR, "Unknown L1CTL_RESET_REQ type\n");
@ -483,7 +482,7 @@ static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
req->ccch_mode); /* TODO: add value-string for ccch_mode */
/* Make sure that TS0 is allocated and configured */
ts = l1l->trx->ts_list[0];
ts = l1l->sched->ts_list[0];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DL1C, LOGL_ERROR, "TS0 is not configured");
rc = -EINVAL;
@ -495,7 +494,7 @@ static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Do nothing if the current mode matches required */
if (ts->mf_layout->chan_config != ch_config)
rc = l1sched_configure_ts(l1l->trx, 0, ch_config);
rc = l1sched_configure_ts(l1l->sched, 0, ch_config);
/* Confirm reconfiguration */
if (!rc)
@ -554,7 +553,7 @@ static int l1ctl_rx_rach_req(struct l1ctl_link *l1l, struct msgb *msg, bool ext)
* Indicated timeslot needs to be configured.
*/
prim_type = ext ? L1SCHED_PRIM_RACH11 : L1SCHED_PRIM_RACH8;
prim = l1sched_prim_push(l1l->trx, prim_type, ul->chan_nr, ul->link_id,
prim = l1sched_prim_push(l1l->sched, prim_type, ul->chan_nr, ul->link_id,
(const uint8_t *)&rach, sizeof(rach));
if (prim == NULL)
rc = -ENOMEM;
@ -658,12 +657,9 @@ static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
if (rc)
goto exit;
/* Update TSC (Training Sequence Code) */
l1l->trx->tsc = est_req->tsc;
/* Configure requested TS */
rc = l1sched_configure_ts(l1l->trx, tn, config);
ts = l1l->trx->ts_list[tn];
rc = l1sched_configure_ts(l1l->sched, tn, config);
ts = l1l->sched->ts_list[tn];
if (rc) {
rc = -EINVAL;
goto exit;
@ -673,7 +669,7 @@ static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
l1sched_deactivate_all_lchans(ts);
/* Activate only requested lchans */
rc = l1sched_set_lchans(ts, chan_nr, 1, est_req->tch_mode);
rc = l1sched_set_lchans(ts, chan_nr, 1, est_req->tch_mode, est_req->tsc);
if (rc) {
LOGP(DL1C, LOGL_ERROR, "Couldn't activate requested lchans\n");
rc = -EINVAL;
@ -690,7 +686,7 @@ static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ, resetting scheduler\n");
/* Reset scheduler */
l1sched_reset(l1l->trx, false);
l1sched_reset(l1l->sched, false);
msgb_free(msg);
return 0;
@ -724,7 +720,7 @@ static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
chan_nr, link_id, payload_len);
/* Push this primitive to transmit queue */
prim = l1sched_prim_push(l1l->trx, L1SCHED_PRIM_DATA,
prim = l1sched_prim_push(l1l->sched, L1SCHED_PRIM_DATA,
chan_nr, link_id, ul->payload, payload_len);
if (prim == NULL)
rc = -ENOMEM;
@ -771,7 +767,7 @@ static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Iterate over timeslot list */
for (i = 0; i < TRX_TS_COUNT; i++) {
/* Timeslot is not allocated */
ts = l1l->trx->ts_list[i];
ts = l1l->sched->ts_list[i];
if (ts == NULL)
continue;
@ -817,7 +813,7 @@ static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
tn = ul->chan_nr & 0x7;
/* Make sure that required TS is allocated and configured */
ts = l1l->trx->ts_list[tn];
ts = l1l->sched->ts_list[tn];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DL1C, LOGL_ERROR, "TS %u is not configured\n", tn);
rc = -EINVAL;

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: common routines for lchan handlers
*
* (C) 2017-2020 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -36,12 +37,8 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trxcon.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
/* GSM 05.02 Chapter 5.2.3 Normal Burst (NB) */
const uint8_t l1sched_nb_training_bits[8][26] = {
@ -98,97 +95,6 @@ const char *l1sched_burst_mask2str(const uint8_t *mask, int bits)
return buf;
}
int l1sched_gsmtap_send(enum l1sched_lchan_type lchan_type, uint32_t fn, uint8_t tn,
uint16_t band_arfcn, int8_t signal_dbm, uint8_t snr,
const uint8_t *data, size_t data_len)
{
const struct l1sched_lchan_desc *lchan_desc = &l1sched_lchan_desc[lchan_type];
/* GSMTAP logging may not be enabled */
if (gsmtap == NULL)
return 0;
/* Omit frames with unknown channel type */
if (lchan_desc->gsmtap_chan_type == GSMTAP_CHANNEL_UNKNOWN)
return 0;
/* TODO: distinguish GSMTAP_CHANNEL_PCH and GSMTAP_CHANNEL_AGCH */
return gsmtap_send(gsmtap, band_arfcn, tn, lchan_desc->gsmtap_chan_type,
lchan_desc->ss_nr, fn, signal_dbm, snr, data, data_len);
}
int l1sched_send_dt_ind(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint8_t *l2, size_t l2_len,
int bit_error_count, bool dec_failed, bool traffic)
{
const struct l1sched_meas_set *meas = &lchan->meas_avg;
const struct l1sched_lchan_desc *lchan_desc;
struct l1ctl_info_dl dl_hdr;
/* Set up pointers */
lchan_desc = &l1sched_lchan_desc[lchan->type];
/* Fill in known downlink info */
dl_hdr.chan_nr = lchan_desc->chan_nr | ts->index;
dl_hdr.link_id = lchan_desc->link_id;
dl_hdr.band_arfcn = htons(trx->band_arfcn);
dl_hdr.num_biterr = bit_error_count;
/* l1sched_lchan_meas_avg() gives us TDMA frame number of the first burst */
dl_hdr.frame_nr = htonl(meas->fn);
/* RX level: 0 .. 63 in typical GSM notation (dBm + 110) */
dl_hdr.rx_level = dbm2rxlev(meas->rssi);
/* FIXME: set proper values */
dl_hdr.snr = 0;
/* Mark frame as broken if so */
dl_hdr.fire_crc = dec_failed ? 2 : 0;
/* Put a packet to higher layers */
l1ctl_tx_dt_ind(trx->l1l, &dl_hdr, l2, l2_len, traffic);
/* Optional GSMTAP logging */
if (l2_len > 0 && (!traffic || lchan_desc->chan_nr == RSL_CHAN_OSMO_PDCH)) {
l1sched_gsmtap_send(lchan->type, meas->fn, ts->index,
trx->band_arfcn, meas->rssi, 0, l2, l2_len);
}
return 0;
}
int l1sched_send_dt_conf(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, bool traffic)
{
const struct l1sched_lchan_desc *lchan_desc;
struct l1ctl_info_dl dl_hdr;
/* Set up pointers */
lchan_desc = &l1sched_lchan_desc[lchan->type];
/* Zero-initialize DL header, because we don't set all fields */
memset(&dl_hdr, 0x00, sizeof(struct l1ctl_info_dl));
/* Fill in known downlink info */
dl_hdr.chan_nr = lchan_desc->chan_nr | ts->index;
dl_hdr.link_id = lchan_desc->link_id;
dl_hdr.band_arfcn = htons(trx->band_arfcn);
dl_hdr.frame_nr = htonl(fn);
l1ctl_tx_dt_conf(trx->l1l, &dl_hdr, traffic);
/* Optional GSMTAP logging */
if (!traffic || lchan_desc->chan_nr == RSL_CHAN_OSMO_PDCH) {
l1sched_gsmtap_send(lchan->type, fn, ts->index,
trx->band_arfcn | ARFCN_UPLINK,
0, 0, lchan->prim->payload,
lchan->prim->payload_len);
}
return 0;
}
/**
* Composes a bad frame indication message
* according to the current tch_mode.

@ -5,6 +5,7 @@
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
* (C) 2015 by Harald Welte <laforge@gnumonks.org>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -29,44 +30,39 @@
#include <osmocom/bb/trxcon/l1sched.h>
/* Forward declaration of handlers */
int rx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas);
int rx_data_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
int tx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_data_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
int rx_sch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas);
int rx_sch_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
int tx_rach_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_rach_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas);
int rx_tchf_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
int tx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_tchf_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
int rx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas);
int rx_tchh_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
int tx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_tchh_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
int rx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas);
int rx_pdtch_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas);
int tx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_pdtch_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = {

@ -2,7 +2,7 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2018-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
@ -30,15 +30,12 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
int rx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas)
int rx_pdtch_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas)
{
const struct l1sched_lchan_desc *lchan_desc;
uint8_t l2[GPRS_L2_MAX_LEN], *mask;
@ -52,7 +49,7 @@ int rx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
buffer = lchan->rx_bursts;
LOGP(DSCHD, LOGL_DEBUG, "Packet data received on %s: "
"fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, ts->index, bid);
"fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, lchan->ts->index, bid);
/* Align to the first burst of a block */
if (*mask == 0x00 && bid != 0)
@ -81,8 +78,8 @@ int rx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
"fn=%u (%u/%u) for %s\n",
l1sched_burst_mask2str(mask, 4), lchan->meas_avg.fn,
lchan->meas_avg.fn % ts->mf_layout->period,
ts->mf_layout->period,
lchan->meas_avg.fn % lchan->ts->mf_layout->period,
lchan->ts->mf_layout->period,
lchan_desc->name);
/* NOTE: do not abort here, give it a try. Maybe we're lucky ;) */
}
@ -102,15 +99,13 @@ int rx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
l2_len = rc > 0 ? rc : 0;
/* Send a L2 frame to the higher layers */
l1sched_send_dt_ind(trx, ts, lchan,
l2, l2_len, n_errors, rc < 0, true);
l1sched_handle_data_ind(lchan, l2, l2_len, n_errors, n_bits_total, L1SCHED_DT_PACKET_DATA);
return 0;
}
int tx_pdtch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_pdtch_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br)
{
const struct l1sched_lchan_desc *lchan_desc;
@ -154,7 +149,7 @@ send_burst:
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = l1sched_nb_training_bits[trx->tsc];
tsc = l1sched_nb_training_bits[lchan->tsc];
/* Compose a new burst */
memset(br->burst, 0, 3); /* TB */
@ -165,12 +160,12 @@ send_burst:
br->burst_len = GSM_BURST_LEN;
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
lchan_desc->name, br->fn, lchan->ts->index, br->bid);
/* If we have sent the last (4/4) burst */
if ((*mask & 0x0f) == 0x0f) {
/* Confirm data / traffic sending */
l1sched_send_dt_conf(trx, ts, lchan, br->fn, true);
l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_PACKET_DATA);
/* Forget processed primitive */
l1sched_prim_drop(lchan);

@ -2,7 +2,7 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
@ -30,11 +30,8 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)" */
#define RACH_EXT_TAIL_BITS_LEN 8
@ -72,14 +69,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 l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_rach_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br)
{
const uint8_t bsic = lchan->ts->sched->bsic;
struct l1sched_ts_prim_rach *rach;
uint8_t *burst_ptr = br->burst;
uint8_t payload[36];
uint8_t ra_buf[2];
int i, rc;
rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload;
@ -101,10 +97,10 @@ int tx_rach_fn(struct trx_instance *trx, struct l1sched_ts *ts,
}
/* Encode extended (11-bit) payload */
rc = gsm0503_rach_ext_encode(payload, rach->ra, trx->bsic, true);
rc = gsm0503_rach_ext_encode(payload, rach->ra, bsic, true);
if (rc) {
LOGP(DSCHD, LOGL_ERROR, "Could not encode extended RACH burst "
"(ra=%u bsic=%u)\n", rach->ra, trx->bsic);
"(ra=%u bsic=%u)\n", rach->ra, bsic);
/* Forget this primitive */
l1sched_prim_drop(lchan);
@ -114,10 +110,10 @@ int tx_rach_fn(struct trx_instance *trx, struct l1sched_ts *ts,
rach->synch_seq = RACH_SYNCH_SEQ_TS0;
/* Encode regular (8-bit) payload */
rc = gsm0503_rach_ext_encode(payload, rach->ra, trx->bsic, false);
rc = gsm0503_rach_ext_encode(payload, rach->ra, bsic, false);
if (rc) {
LOGP(DSCHD, LOGL_ERROR, "Could not encode RACH burst "
"(ra=%u bsic=%u)\n", rach->ra, trx->bsic);
"(ra=%u bsic=%u)\n", rach->ra, bsic);
/* Forget this primitive */
l1sched_prim_drop(lchan);
@ -150,22 +146,10 @@ int tx_rach_fn(struct trx_instance *trx, struct l1sched_ts *ts,
LOGP(DSCHD, LOGL_NOTICE, "Scheduled %s RACH (%s) on fn=%u, tn=%u, lchan=%s\n",
L1SCHED_PRIM_IS_RACH11(lchan->prim) ? "extended (11-bit)" : "regular (8-bit)",
get_value_string(rach_synch_seq_names, rach->synch_seq), br->fn,
ts->index, l1sched_lchan_desc[lchan->type].name);
lchan->ts->index, l1sched_lchan_desc[lchan->type].name);
/* Confirm RACH request */
l1ctl_tx_rach_conf(trx->l1l, trx->band_arfcn, br->fn);
if (L1SCHED_PRIM_IS_RACH11(lchan->prim)) {
ra_buf[0] = (uint8_t)(rach->ra >> 3);
ra_buf[1] = (uint8_t)(rach->ra & 0x07);
} else {
ra_buf[0] = (uint8_t)(rach->ra);
}
/* Optional GSMTAP logging */
l1sched_gsmtap_send(lchan->type, br->fn, ts->index,
trx->band_arfcn | ARFCN_UPLINK, 0, 0,
&ra_buf[0], L1SCHED_PRIM_IS_RACH11(lchan->prim) ? 2 : 1);
l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_OTHER);
/* Forget processed primitive */
l1sched_prim_drop(lchan);

@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@ -31,11 +32,8 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
static void decode_sb(struct gsm_time *time, uint8_t *bsic, uint8_t *sb_info)
{
@ -63,9 +61,9 @@ static void decode_sb(struct gsm_time *time, uint8_t *bsic, uint8_t *sb_info)
time->fn = gsm_gsmtime2fn(time);
}
int rx_sch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas)
int rx_sch_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas)
{
sbit_t payload[2 * 39];
struct gsm_time time;
@ -88,7 +86,7 @@ int rx_sch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
decode_sb(&time, &bsic, sb_info);
LOGP(DSCHD, LOGL_DEBUG, "Received SCH: bsic=%u, fn=%u, sched_fn=%u\n",
bsic, time.fn, trx->sched.fn_counter_proc);
bsic, time.fn, lchan->ts->sched->fn_counter_proc);
/* Check if decoded frame number matches */
if (time.fn != fn) {
@ -97,32 +95,11 @@ int rx_sch_fn(struct trx_instance *trx, struct l1sched_ts *ts,
return -EINVAL;
}
/* We don't need to send L1CTL_FBSB_CONF */
if (trx->l1l->fbsb_conf_sent)
return 0;
/* Update BSIC value in the scheduler state */
lchan->ts->sched->bsic = bsic;
/* Send L1CTL_FBSB_CONF to higher layers */
struct l1ctl_info_dl *data;
data = talloc_zero_size(ts, sizeof(struct l1ctl_info_dl));
if (data == NULL)
return -ENOMEM;
/* Fill in some downlink info */
data->chan_nr = l1sched_lchan_desc[lchan->type].chan_nr | ts->index;
data->link_id = l1sched_lchan_desc[lchan->type].link_id;
data->band_arfcn = htons(trx->band_arfcn);
data->frame_nr = htonl(fn);
data->rx_level = -(meas->rssi);
/* FIXME: set proper values */
data->num_biterr = 0;
data->fire_crc = 0;
data->snr = 0;
l1ctl_tx_fbsb_conf(trx->l1l, 0, data, bsic);
/* Update BSIC value of trx_instance */
trx->bsic = bsic;
l1sched_handle_data_ind(lchan, (const uint8_t *)&time, sizeof(time),
0, 39 * 2, L1SCHED_DT_OTHER);
return 0;
}

@ -2,7 +2,7 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
@ -32,15 +32,12 @@
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/codec/codec.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas)
int rx_tchf_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas)
{
const struct l1sched_lchan_desc *lchan_desc;
int n_errors = -1, n_bits_total, rc;
@ -54,7 +51,7 @@ int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
buffer = lchan->rx_bursts;
LOGP(DSCHD, LOGL_DEBUG, "Traffic received on %s: fn=%u ts=%u bid=%u\n",
lchan_desc->name, fn, ts->index, bid);
lchan_desc->name, fn, lchan->ts->index, bid);
/* Align to the first burst of a block */
if (*mask == 0x00 && bid != 0)
@ -83,8 +80,8 @@ int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) traffic frame at "
"fn=%u (%u/%u) for %s\n",
l1sched_burst_mask2str(mask, 8), lchan->meas_avg.fn,
lchan->meas_avg.fn % ts->mf_layout->period,
ts->mf_layout->period,
lchan->meas_avg.fn % lchan->ts->mf_layout->period,
lchan->ts->mf_layout->period,
lchan_desc->name);
/* NOTE: do not abort here, give it a try. Maybe we're lucky ;) */
@ -127,8 +124,9 @@ int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
goto bfi;
} else if (rc == GSM_MACBLOCK_LEN) {
/* FACCH received, forward it to the higher layers */
l1sched_send_dt_ind(trx, ts, lchan, l2, GSM_MACBLOCK_LEN,
n_errors, false, false);
l1sched_handle_data_ind(lchan, l2, GSM_MACBLOCK_LEN,
n_errors, n_bits_total,
L1SCHED_DT_SIGNALING);
/* Send BFI substituting a stolen TCH frame */
n_errors = -1; /* ensure fake measurements */
@ -139,8 +137,7 @@ int rx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
}
/* Send a traffic frame to the higher layers */
return l1sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
n_errors, false, true);
return l1sched_handle_data_ind(lchan, l2, l2_len, n_errors, n_bits_total, L1SCHED_DT_TRAFFIC);
bfi:
/* Didn't try to decode, fake measurements */
@ -156,20 +153,22 @@ bfi:
}
/* BFI is not applicable in signalling mode */
if (lchan->tch_mode == GSM48_CMODE_SIGN)
return l1sched_send_dt_ind(trx, ts, lchan, NULL, 0,
n_errors, true, false);
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
return l1sched_handle_data_ind(lchan, NULL, 0,
n_errors, n_bits_total,
L1SCHED_DT_TRAFFIC);
}
/* Bad frame indication */
l2_len = l1sched_bad_frame_ind(l2, lchan);
/* Send a BFI frame to the higher layers */
return l1sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
n_errors, true, true);
return l1sched_handle_data_ind(lchan, l2, l2_len,
n_errors, n_bits_total,
L1SCHED_DT_TRAFFIC);
}
int tx_tchf_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_tchf_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br)
{
const struct l1sched_lchan_desc *lchan_desc;
@ -259,7 +258,7 @@ send_burst:
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = l1sched_nb_training_bits[trx->tsc];
tsc = l1sched_nb_training_bits[lchan->tsc];
/* Compose a new burst */
memset(br->burst, 0, 3); /* TB */
@ -270,12 +269,14 @@ send_burst:
br->burst_len = GSM_BURST_LEN;
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
lchan_desc->name, br->fn, lchan->ts->index, br->bid);
/* If we have sent the last (4/4) burst */
if (*mask == 0x0f) {
/* Confirm data / traffic sending */
l1sched_send_dt_conf(trx, ts, lchan, br->fn, L1SCHED_PRIM_IS_TCH(lchan->prim));
enum l1sched_data_type dt = L1SCHED_PRIM_IS_TCH(lchan->prim) ?
L1SCHED_DT_TRAFFIC : L1SCHED_DT_SIGNALING;
l1sched_handle_data_cnf(lchan, br->fn, dt);
/* Forget processed primitive */
l1sched_prim_drop(lchan);

@ -2,7 +2,7 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2018-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2018 by Harald Welte <laforge@gnumonks.org>
* Contributions by sysmocom - s.f.m.c. GmbH
*
@ -35,11 +35,8 @@
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/codec/codec.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
static const uint8_t tch_h0_traffic_block_map[3][4] = {
/* B0(0,2,4,6), B1(4,6,8,10), B2(8,10,0,2) */
@ -194,9 +191,9 @@ uint32_t l1sched_tchh_block_dl_first_fn(enum l1sched_lchan_type chan,
return last_fn;
}
int rx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas)
int rx_tchh_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas)
{
const struct l1sched_lchan_desc *lchan_desc;
int n_errors = -1, n_bits_total, rc;
@ -210,7 +207,7 @@ int rx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
buffer = lchan->rx_bursts;
LOGP(DSCHD, LOGL_DEBUG, "Traffic received on %s: fn=%u ts=%u bid=%u\n",
lchan_desc->name, fn, ts->index, bid);
lchan_desc->name, fn, lchan->ts->index, bid);
if (*mask == 0x00) {
/* Align to the first burst */
@ -303,8 +300,9 @@ int rx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
l1sched_lchan_meas_avg(lchan, 6);
/* FACCH/H received, forward to the higher layers */
l1sched_send_dt_ind(trx, ts, lchan, l2, GSM_MACBLOCK_LEN,
n_errors, false, false);
l1sched_handle_data_ind(lchan, l2, GSM_MACBLOCK_LEN,
n_errors, n_bits_total,
L1SCHED_DT_SIGNALING);
/* Send BFI substituting 1/2 stolen TCH frames */
n_errors = -1; /* ensure fake measurements */
@ -318,8 +316,9 @@ int rx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
}
/* Send a traffic frame to the higher layers */
return l1sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
n_errors, false, true);
return l1sched_handle_data_ind(lchan, l2, l2_len,
n_errors, n_bits_total,
L1SCHED_DT_TRAFFIC);
bfi_shift:
/* Shift buffer */
@ -343,20 +342,22 @@ bfi:
}
/* BFI is not applicable in signalling mode */
if (lchan->tch_mode == GSM48_CMODE_SIGN)
return l1sched_send_dt_ind(trx, ts, lchan, NULL, 0,
n_errors, true, false);
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
return l1sched_handle_data_ind(lchan, NULL, 0,
n_errors, n_bits_total,
L1SCHED_DT_SIGNALING);
}
/* Bad frame indication */
l2_len = l1sched_bad_frame_ind(l2, lchan);
/* Send a BFI frame to the higher layers */
return l1sched_send_dt_ind(trx, ts, lchan, l2, l2_len,
n_errors, true, true);
return l1sched_handle_data_ind(lchan, l2, l2_len,
n_errors, n_bits_total,
L1SCHED_DT_TRAFFIC);
}
int tx_tchh_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_tchh_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br)
{
const struct l1sched_lchan_desc *lchan_desc;
@ -460,7 +461,7 @@ send_burst:
*mask |= (1 << br->bid);
/* Choose proper TSC */
tsc = l1sched_nb_training_bits[trx->tsc];
tsc = l1sched_nb_training_bits[lchan->tsc];
/* Compose a new burst */
memset(br->burst, 0, 3); /* TB */
@ -471,7 +472,7 @@ send_burst:
br->burst_len = GSM_BURST_LEN;
LOGP(DSCHD, LOGL_DEBUG, "Scheduled %s fn=%u ts=%u burst=%u\n",
lchan_desc->name, br->fn, ts->index, br->bid);
lchan_desc->name, br->fn, lchan->ts->index, br->bid);
/* In case of a FACCH/H frame, one block less */
if (lchan->ul_facch_blocks)
@ -482,9 +483,11 @@ send_burst:
* If no more FACCH/H blocks pending,
* confirm data / traffic sending
*/
if (!lchan->ul_facch_blocks)
l1sched_send_dt_conf(trx, ts, lchan, br->fn,
L1SCHED_PRIM_IS_TCH(lchan->prim));
if (!lchan->ul_facch_blocks) {
enum l1sched_data_type dt = L1SCHED_PRIM_IS_TCH(lchan->prim) ?
L1SCHED_DT_TRAFFIC : L1SCHED_DT_SIGNALING;
l1sched_handle_data_cnf(lchan, br->fn, dt);
}
/* Forget processed primitive */
l1sched_prim_drop(lchan);

@ -2,7 +2,7 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: handlers for DL / UL bursts on logical channels
*
* (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
* (C) 2017-2022 by Vadim Yanitskiy <axilirator@gmail.com>
* Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
@ -30,15 +30,12 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1ctl.h>
int rx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan, uint32_t fn, uint8_t bid,
const sbit_t *bits, const struct l1sched_meas_set *meas)
int rx_data_fn(struct l1sched_lchan_state *lchan,
uint32_t fn, uint8_t bid, const sbit_t *bits,
const struct l1sched_meas_set *meas)
{
const struct l1sched_lchan_desc *lchan_desc;
uint8_t l2[GSM_MACBLOCK_LEN], *mask;
@ -51,7 +48,7 @@ int rx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
buffer = lchan->rx_bursts;
LOGP(DSCHD, LOGL_DEBUG, "Data received on %s: fn=%u ts=%u bid=%u\n",
lchan_desc->name, fn, ts->index, bid);
lchan_desc->name, fn, lchan->ts->index, bid);
/* Align to the first burst of a block */
if (*mask == 0x00 && bid != 0)
@ -80,8 +77,8 @@ int rx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
LOGP(DSCHD, LOGL_ERROR, "Received incomplete (%s) data frame at "
"fn=%u (%u/%u) for %s\n",
l1sched_burst_mask2str(mask, 4), lchan->meas_avg.fn,
lchan->meas_avg.fn % ts->mf_layout->period,
ts->mf_layout->period,
lchan->meas_avg.fn % lchan->ts->mf_layout->period,
lchan->ts->mf_layout->period,
lchan_desc->name);
/* NOTE: xCCH has an insane amount of redundancy for error
* correction, so even just 2 valid bursts might be enough
@ -97,22 +94,15 @@ int rx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
if (rc) {
LOGP(DSCHD, LOGL_ERROR, "Received bad %s frame (rc=%d, ber=%d/%d) at fn=%u\n",
lchan_desc->name, rc, n_errors, n_bits_total, lchan->meas_avg.fn);
/**
* We should anyway send dummy frame for
* proper measurement reporting...
*/
return l1sched_send_dt_ind(trx, ts, lchan, NULL, 0,
n_errors, true, false);
}
/* Send a L2 frame to the higher layers */
return l1sched_send_dt_ind(trx, ts, lchan, l2, GSM_MACBLOCK_LEN,
n_errors, false, false);
return l1sched_handle_data_ind(lchan, l2, rc ? 0 : GSM_MACBLOCK_LEN,
n_errors, n_bits_total,
L1SCHED_DT_SIGNALING);
}
int tx_data_fn(struct trx_instance *trx, struct l1sched_ts *ts,
struct l1sched_lchan_state *lchan,
int tx_data_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br)
{
const struct l1sched_lchan_desc *lchan_desc;
@ -164,7 +154,7 @@ send_burst:
*mask |= (1 << br->bid);
/* Choose proper TSC */