fixeria has uploaded this change for review.
trxcon: abstract out the scheduler API from L1CTL/TRXD/TRXC
Change-Id: I31f77976a7a225ef292fe6dcd583513aec97ed44
Related: OS#5599, OS#3761
---
M src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h
M src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h
M src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h
M src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
M src/host/trxcon/src/l1ctl.c
M src/host/trxcon/src/sched_lchan_common.c
M src/host/trxcon/src/sched_lchan_desc.c
M src/host/trxcon/src/sched_lchan_pdtch.c
M src/host/trxcon/src/sched_lchan_rach.c
M src/host/trxcon/src/sched_lchan_sch.c
M src/host/trxcon/src/sched_lchan_tchf.c
M src/host/trxcon/src/sched_lchan_tchh.c
M src/host/trxcon/src/sched_lchan_xcch.c
M src/host/trxcon/src/sched_prim.c
M src/host/trxcon/src/sched_trx.c
M src/host/trxcon/src/trx_if.c
M src/host/trxcon/src/trxcon.c
17 files changed, 458 insertions(+), 404 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/54/28554/1
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h
index a333e40..4604e27 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl_link.h
@@ -30,6 +30,9 @@
struct osmo_fd listen_bfd;
struct osmo_wqueue wq;
+ /* Scheduler for this interface */
+ struct l1sched_state *sched;
+
/* Bind TRX instance */
struct trx_instance *trx;
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h
index da2334f..7fe9459 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h
@@ -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 @@
_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_CHAN_COMB,
+};
+
+/* Represents a (re)configuration request */
+struct l1sched_config_req {
+ enum l1sched_config_type type;
+ union {
+ struct {
+ uint8_t tn;
+ uint8_t comb;
+ } chan_comb;
+ };
+};
+
/* Represents a burst to be transmitted */
struct l1sched_burst_req {
uint32_t fn;
@@ -122,13 +143,11 @@
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 @@
/*! 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 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 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 @@
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 @@
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);
@@ -413,7 +437,7 @@
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);
@@ -422,14 +446,6 @@
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,
@@ -453,3 +469,17 @@
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);
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h b/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h
index 033eaa3..f176417 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/trx_if.h
@@ -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 @@
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;
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
index 9a0792b..f66a628 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
@@ -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,
diff --git a/src/host/trxcon/src/l1ctl.c b/src/host/trxcon/src/l1ctl.c
index cb3a06c..7372202 100644
--- a/src/host/trxcon/src/l1ctl.c
+++ b/src/host/trxcon/src/l1ctl.c
@@ -344,10 +344,10 @@
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 +434,7 @@
/* 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 +483,7 @@
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 +495,7 @@
/* 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 +554,7 @@
* 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 +658,9 @@
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 +670,7 @@
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 +687,7 @@
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 +721,7 @@
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 +768,7 @@
/* 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 +814,7 @@
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;
diff --git a/src/host/trxcon/src/sched_lchan_common.c b/src/host/trxcon/src/sched_lchan_common.c
index c2d79de..da7f485 100644
--- a/src/host/trxcon/src/sched_lchan_common.c
+++ b/src/host/trxcon/src/sched_lchan_common.c
@@ -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,9 @@
#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 +96,6 @@
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.
diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c
index 96a7092..60cba7a 100644
--- a/src/host/trxcon/src/sched_lchan_desc.c
+++ b/src/host/trxcon/src/sched_lchan_desc.c
@@ -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] = {
diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c
index 6063438..cb0f1ec 100644
--- a/src/host/trxcon/src/sched_lchan_pdtch.c
+++ b/src/host/trxcon/src/sched_lchan_pdtch.c
@@ -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 @@
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 @@
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 @@
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 @@
*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 @@
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);
diff --git a/src/host/trxcon/src/sched_lchan_rach.c b/src/host/trxcon/src/sched_lchan_rach.c
index 40a3134..2640bab 100644
--- a/src/host/trxcon/src/sched_lchan_rach.c
+++ b/src/host/trxcon/src/sched_lchan_rach.c
@@ -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 @@
};
/* 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 @@
}
/* 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 @@
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 @@
LOGP(DSCHD, LOGL_NOTICE, "Scheduled %s RACH (%s) on fn=%u, tn=%u, lchan=%s\n",
lchan->prim->type == L1SCHED_PRIM_RACH11 ? "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 (lchan->prim->type == L1SCHED_PRIM_RACH11) {
- 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], lchan->prim->type == L1SCHED_PRIM_RACH11 ? 2 : 1);
+ l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_OTHER);
/* Forget processed primitive */
l1sched_prim_drop(lchan);
diff --git a/src/host/trxcon/src/sched_lchan_sch.c b/src/host/trxcon/src/sched_lchan_sch.c
index 59f1691..d29083c 100644
--- a/src/host/trxcon/src/sched_lchan_sch.c
+++ b/src/host/trxcon/src/sched_lchan_sch.c
@@ -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 @@
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 @@
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 @@
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;
}
diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c
index fe36e1d..9f7c012 100644
--- a/src/host/trxcon/src/sched_lchan_tchf.c
+++ b/src/host/trxcon/src/sched_lchan_tchf.c
@@ -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 @@
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 @@
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 @@
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 @@
}
/* 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 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 @@
*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 @@
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, PRIM_IS_TCH(lchan->prim));
+ enum l1sched_data_type dt = 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);
diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c
index 3350ea9..57bee10 100644
--- a/src/host/trxcon/src/sched_lchan_tchh.c
+++ b/src/host/trxcon/src/sched_lchan_tchh.c
@@ -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 @@
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 @@
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 @@
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 @@
}
/* 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 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 @@
*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 @@
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 @@
* 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,
- PRIM_IS_TCH(lchan->prim));
+ if (!lchan->ul_facch_blocks) {
+ enum l1sched_data_type dt = 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);
diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c
index 758f41f..e9ed05f 100644
--- a/src/host/trxcon/src/sched_lchan_xcch.c
+++ b/src/host/trxcon/src/sched_lchan_xcch.c
@@ -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 @@
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 @@
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 @@
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 @@
*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 */
@@ -175,12 +165,12 @@
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 sending */
- l1sched_send_dt_conf(trx, ts, lchan, br->fn, false);
+ l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_SIGNALING);
/* Forget processed primitive */
l1sched_prim_drop(lchan);
diff --git a/src/host/trxcon/src/sched_prim.c b/src/host/trxcon/src/sched_prim.c
index ec5e8d5..5b74fcc 100644
--- a/src/host/trxcon/src/sched_prim.c
+++ b/src/host/trxcon/src/sched_prim.c
@@ -31,7 +31,6 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/bb/trxcon/l1sched.h>
-#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/logging.h>
/**
@@ -78,14 +77,14 @@
* Adds a primitive to the end of transmit queue of a particular
* timeslot, whose index is parsed from chan_nr.
*
- * @param trx TRX instance
+ * @param sched scheduler instance
* @param chan_nr RSL channel description
* @param link_id RSL link description
* @param pl Payload data
* @param pl_len Payload length
* @return queued primitive or NULL
*/
-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)
@@ -98,7 +97,7 @@
tn = chan_nr & 0x7;
/* Check whether required timeslot is allocated and configured */
- ts = trx->ts_list[tn];
+ ts = sched->ts_list[tn];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DSCH, LOGL_ERROR, "Timeslot %u isn't configured\n", tn);
return NULL;
@@ -187,8 +186,11 @@
* decide whether to update the cached L1 SACCH header here.
*/
if (!cached) {
- prim->payload[0] = lchan->ts->trx->tx_power;
- prim->payload[1] = lchan->ts->trx->ta;
+#warning "FIXME: no direct access to trx->{tx_power,ta}"
+#if 0
+ prim->payload[0] = lchan->ts->sched->trx->tx_power;
+ prim->payload[1] = lchan->ts->sched->trx->ta;
+#endif
}
/* Inform about the cache usage count */
diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c
index 68801c4..62a0da5 100644
--- a/src/host/trxcon/src/sched_trx.c
+++ b/src/host/trxcon/src/sched_trx.c
@@ -2,7 +2,8 @@
* OsmocomBB <-> SDR connection bridge
* TDMA scheduler: GSM PHY routines
*
- * (C) 2017-2019 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,17 +32,28 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/linuxlist.h>
-#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/trxcon/l1sched.h>
-#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/logging.h>
+static int l1sched_config_setslot_req(struct l1sched_state *sched,
+ uint8_t tn, uint8_t comb)
+{
+ const struct l1sched_config_req cr = {
+ .type = L1SCHED_CFG_CHAN_COMB,
+ .chan_comb = {
+ .tn = tn,
+ .comb = comb,
+ },
+ };
+
+ return l1sched_handle_config_req(sched, &cr);
+}
+
static void l1sched_a5_burst_enc(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
static void sched_frame_clck_cb(struct l1sched_state *sched)
{
- struct trx_instance *trx = (struct trx_instance *) sched->data;
struct l1sched_burst_req br[TRX_TS_COUNT];
const struct l1sched_tdma_frame *frame;
struct l1sched_lchan_state *lchan;
@@ -62,12 +74,11 @@
br[i] = (struct l1sched_burst_req) {
.fn = fn,
.tn = i,
- .pwr = trx->tx_power,
.burst_len = 0, /* NOPE.ind */
};
/* Timeslot is not allocated */
- ts = trx->ts_list[i];
+ ts = sched->ts_list[i];
if (ts == NULL)
continue;
@@ -127,7 +138,7 @@
handler = l1sched_lchan_desc[L1SCHED_RACH].tx_fn;
/* Poke lchan handler */
- handler(trx, ts, lchan, &br[i]);
+ handler(lchan, &br[i]);
/* Perform A5/X burst encryption if required */
if (lchan->a5.algo)
@@ -136,100 +147,88 @@
/* Send all bursts for this TDMA frame */
for (i = 0; i < ARRAY_SIZE(br); i++)
- trx_if_tx_burst(trx, &br[i]);
+ l1sched_handle_burst_req(sched, &br[i]);
}
-int l1sched_init(struct trx_instance *trx, uint32_t fn_advance)
+struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance)
{
struct l1sched_state *sched;
- if (!trx)
- return -EINVAL;
-
LOGP(DSCH, LOGL_NOTICE, "Init scheduler\n");
- /* Obtain a scheduler instance from TRX */
- sched = &trx->sched;
+ sched = talloc(ctx, struct l1sched_state);
+ if (!sched)
+ return NULL;
- /* Register frame clock callback */
- sched->clock_cb = sched_frame_clck_cb;
+ *sched = (struct l1sched_state) {
+ /* .clock_timer is set up in l1sched_clck_correct() */
+ .clock_cb = &sched_frame_clck_cb,
+ .fn_counter_advance = fn_advance,
+ };
- /* Set pointers */
- sched = &trx->sched;
- sched->data = trx;
-
- /* Set frame counter advance */
- sched->fn_counter_advance = fn_advance;
-
- return 0;
+ return sched;
}
-int l1sched_shutdown(struct trx_instance *trx)
+void l1sched_free(struct l1sched_state *sched)
{
int i;
- if (!trx)
- return -EINVAL;
+ if (sched == NULL)
+ return;
LOGP(DSCH, LOGL_NOTICE, "Shutdown scheduler\n");
/* Free all potentially allocated timeslots */
for (i = 0; i < TRX_TS_COUNT; i++)
- l1sched_del_ts(trx, i);
+ l1sched_del_ts(sched, i);
- return 0;
+ l1sched_clck_reset(sched);
+ talloc_free(sched);
}
-int l1sched_reset(struct trx_instance *trx, bool reset_clock)
+void l1sched_reset(struct l1sched_state *sched, bool reset_clock)
{
int i;
- if (!trx)
- return -EINVAL;
+ if (sched == NULL)
+ return;
LOGP(DSCH, LOGL_NOTICE, "Reset scheduler %s\n",
reset_clock ? "and clock counter" : "");
/* Free all potentially allocated timeslots */
for (i = 0; i < TRX_TS_COUNT; i++)
- l1sched_del_ts(trx, i);
+ l1sched_del_ts(sched, i);
/* Stop and reset clock counter if required */
if (reset_clock)
- l1sched_clck_reset(&trx->sched);
-
- return 0;
+ l1sched_clck_reset(sched);
}
-struct l1sched_ts *l1sched_add_ts(struct trx_instance *trx, int tn)
+struct l1sched_ts *l1sched_add_ts(struct l1sched_state *sched, int tn)
{
/* Make sure that ts isn't allocated yet */
- if (trx->ts_list[tn] != NULL) {
+ if (sched->ts_list[tn] != NULL) {
LOGP(DSCH, LOGL_ERROR, "Timeslot #%u already allocated\n", tn);
return NULL;
}
LOGP(DSCH, LOGL_NOTICE, "Add a new TDMA timeslot #%u\n", tn);
- /* Allocate a new one */
- trx->ts_list[tn] = talloc_zero(trx, struct l1sched_ts);
+ sched->ts_list[tn] = talloc_zero(sched, struct l1sched_ts);
+ sched->ts_list[tn]->sched = sched;
+ sched->ts_list[tn]->index = tn;
- /* Add backpointer */
- trx->ts_list[tn]->trx = trx;
-
- /* Assign TS index */
- trx->ts_list[tn]->index = tn;
-
- return trx->ts_list[tn];
+ return sched->ts_list[tn];
}
-void l1sched_del_ts(struct trx_instance *trx, int tn)
+void l1sched_del_ts(struct l1sched_state *sched, int tn)
{
struct l1sched_lchan_state *lchan, *lchan_next;
struct l1sched_ts *ts;
/* Find ts in list */
- ts = trx->ts_list[tn];
+ ts = sched->ts_list[tn];
if (ts == NULL)
return;
@@ -248,31 +247,31 @@
l1sched_prim_flush_queue(&ts->tx_prims);
/* Remove ts from list and free memory */
- trx->ts_list[tn] = NULL;
+ sched->ts_list[tn] = NULL;
talloc_free(ts);
/* Notify transceiver about that */
- trx_if_cmd_setslot(trx, tn, 0);
+ l1sched_config_setslot_req(sched, tn, 0);
}
#define LAYOUT_HAS_LCHAN(layout, lchan) \
(layout->lchan_mask & ((uint64_t) 0x01 << lchan))
-int l1sched_configure_ts(struct trx_instance *trx, int tn,
- enum gsm_phys_chan_config config)
+int l1sched_configure_ts(struct l1sched_state *sched, int tn,
+ enum gsm_phys_chan_config config)
{
struct l1sched_lchan_state *lchan;
enum l1sched_lchan_type type;
struct l1sched_ts *ts;
/* Try to find specified ts */
- ts = trx->ts_list[tn];
+ ts = sched->ts_list[tn];
if (ts != NULL) {
/* Reconfiguration of existing one */
- l1sched_reset_ts(trx, tn);
+ l1sched_reset_ts(sched, tn);
} else {
/* Allocate a new one if doesn't exist */
- ts = l1sched_add_ts(trx, tn);
+ ts = l1sched_add_ts(sched, tn);
if (ts == NULL)
return -ENOMEM;
}
@@ -318,18 +317,18 @@
/* Notify transceiver about TS activation */
/* FIXME: set proper channel type */
- trx_if_cmd_setslot(trx, tn, 1);
+ l1sched_config_setslot_req(sched, tn, 1);
return 0;
}
-int l1sched_reset_ts(struct trx_instance *trx, int tn)
+int l1sched_reset_ts(struct l1sched_state *sched, int tn)
{
struct l1sched_lchan_state *lchan, *lchan_next;
struct l1sched_ts *ts;
/* Try to find specified ts */
- ts = trx->ts_list[tn];
+ ts = sched->ts_list[tn];
if (ts == NULL)
return -EINVAL;
@@ -349,7 +348,7 @@
}
/* Notify transceiver about that */
- trx_if_cmd_setslot(trx, tn, 0);
+ l1sched_config_setslot_req(sched, tn, 0);
return 0;
}
@@ -397,7 +396,8 @@
return NULL;
}
-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)
{
const struct l1sched_lchan_desc *lchan_desc;
struct l1sched_lchan_state *lchan;
@@ -417,6 +417,7 @@
if (active) {
rc |= l1sched_activate_lchan(ts, lchan->type);
lchan->tch_mode = tch_mode;
+ lchan->tsc = tsc;
} else
rc |= l1sched_deactivate_lchan(ts, lchan->type);
}
@@ -694,9 +695,7 @@
LOGP(DSCHD, LOGL_NOTICE, "Substituting lost TDMA frame %u on %s\n",
fake_meas.fn, l1sched_lchan_desc[lchan->type].name);
- handler(lchan->ts->trx, lchan->ts, lchan,
- fake_meas.fn, fp->dl_bid,
- bits, &fake_meas);
+ handler(lchan, fake_meas.fn, fp->dl_bid, bits, &fake_meas);
/* Update TDMA frame statistics */
lchan->tdma.last_proc = fake_meas.fn;
@@ -707,7 +706,7 @@
return 0;
}
-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)
{
@@ -721,7 +720,7 @@
int rc;
/* Check whether required timeslot is allocated and configured */
- ts = trx->ts_list[tn];
+ ts = sched->ts_list[tn];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DSCHD, LOGL_DEBUG, "TDMA timeslot #%u isn't configured, "
"ignoring burst...\n", tn);
@@ -761,7 +760,7 @@
l1sched_a5_burst_dec(lchan, fn, bits);
/* Put burst to handler */
- handler(trx, ts, lchan, fn, bid, bits, meas);
+ handler(lchan, fn, bid, bits, meas);
/* Update TDMA frame statistics */
lchan->tdma.last_proc = fn;
diff --git a/src/host/trxcon/src/trx_if.c b/src/host/trxcon/src/trx_if.c
index a251da0..b247064 100644
--- a/src/host/trxcon/src/trx_if.c
+++ b/src/host/trxcon/src/trx_if.c
@@ -39,6 +39,7 @@
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/l1ctl.h>
#include <osmocom/bb/trxcon/trxcon.h>
#include <osmocom/bb/trxcon/trx_if.h>
@@ -619,11 +620,11 @@
};
/* Poke scheduler */
- l1sched_handle_rx_burst(trx, tn, fn, bits, 148, &meas);
+ l1sched_handle_rx_burst(trx->sched, tn, fn, bits, 148, &meas);
/* Correct local clock counter */
if (fn % 51 == 0)
- l1sched_clck_handle(&trx->sched, fn);
+ l1sched_clck_handle(trx->sched, fn);
return 0;
}
diff --git a/src/host/trxcon/src/trxcon.c b/src/host/trxcon/src/trxcon.c
index 08050d3..d11b140 100644
--- a/src/host/trxcon/src/trxcon.c
+++ b/src/host/trxcon/src/trxcon.c
@@ -1,7 +1,8 @@
/*
* OsmocomBB <-> SDR connection bridge
*
- * (C) 2016-2020 by Vadim Yanitskiy <axilirator@gmail.com>
+ * (C) 2016-2022 by Vadim Yanitskiy <axilirator@gmail.com>
+ * Contributions by sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
@@ -24,6 +25,7 @@
#include <getopt.h>
#include <unistd.h>
#include <signal.h>
+#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
@@ -48,7 +50,8 @@
#include <osmocom/bb/trxcon/l1sched.h>
#define COPYRIGHT \
- "Copyright (C) 2016-2020 by Vadim Yanitskiy <axilirator@gmail.com>\n" \
+ "Copyright (C) 2016-2022 by Vadim Yanitskiy <axilirator@gmail.com>\n" \
+ "Contributions by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>\n" \
"License GPLv2+: GNU GPL version 2 or later " \
"<http://gnu.org/licenses/gpl.html>\n" \
"This is free software: you are free to change and redistribute it.\n" \
@@ -59,6 +62,9 @@
int daemonize;
int quit;
+ /* The scheduler */
+ struct l1sched_state *sched;
+
/* L1CTL specific */
struct l1ctl_link *l1l;
const char *bind_socket;
@@ -69,13 +75,176 @@
const char *trx_remote_ip;
uint16_t trx_base_port;
uint32_t trx_fn_advance;
+
+ /* GSMTAP specific */
+ struct gsmtap_inst *gsmtap;
const char *gsmtap_ip;
} app_data;
static void *tall_trxcon_ctx = NULL;
-struct gsmtap_inst *gsmtap = NULL;
struct osmo_fsm_inst *trxcon_fsm;
+void trxcon_gsmtap_send(const struct l1sched_lchan_desc *lchan_desc,
+ 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)
+{
+ /* GSMTAP logging may be not enabled */
+ if (app_data.gsmtap == NULL)
+ return;
+
+ /* Omit frames with unknown channel type */
+ if (lchan_desc->gsmtap_chan_type == GSMTAP_CHANNEL_UNKNOWN)
+ return;
+
+ /* TODO: distinguish GSMTAP_CHANNEL_PCH and GSMTAP_CHANNEL_AGCH */
+ gsmtap_send(app_data.gsmtap, band_arfcn, tn, lchan_desc->gsmtap_chan_type,
+ lchan_desc->ss_nr, fn, signal_dbm, snr, data, data_len);
+}
+
+/* External L1 API for the scheduler */
+int l1sched_handle_config_req(struct l1sched_state *sched,
+ const struct l1sched_config_req *cr)
+{
+ switch (cr->type) {
+ case L1SCHED_CFG_CHAN_COMB:
+ return trx_if_cmd_setslot(app_data.trx,
+ cr->chan_comb.tn,
+ cr->chan_comb.comb);
+ default:
+ LOGPFSML(trxcon_fsm, LOGL_ERROR,
+ "Unhandled config request (type 0x%02x)\n", cr->type);
+ return -ENODEV;
+ }
+}
+
+int l1sched_handle_burst_req(struct l1sched_state *sched,
+ const struct l1sched_burst_req *br)
+{
+ return trx_if_tx_burst(app_data.trx, br);
+}
+
+/* External L2 API for the scheduler */
+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)
+{
+ const struct l1sched_meas_set *meas = &lchan->meas_avg;
+ const struct l1sched_lchan_desc *lchan_desc;
+ struct l1ctl_info_dl dl_hdr;
+ int rc;
+
+ lchan_desc = &l1sched_lchan_desc[lchan->type];
+
+ dl_hdr = (struct l1ctl_info_dl) {
+ .chan_nr = lchan_desc->chan_nr | lchan->ts->index,
+ .link_id = lchan_desc->link_id,
+ .frame_nr = htonl(meas->fn),
+ .band_arfcn = htons(app_data.trx->band_arfcn),
+ .fire_crc = data_len > 0 ? 0 : 2,
+ .rx_level = dbm2rxlev(meas->rssi),
+ .num_biterr = n_errors,
+ /* TODO: set proper .snr */
+ };
+
+ switch (dt) {
+ case L1SCHED_DT_TRAFFIC:
+ case L1SCHED_DT_PACKET_DATA:
+ rc = l1ctl_tx_dt_ind(app_data.l1l, &dl_hdr, data, data_len, true);
+ break;
+ case L1SCHED_DT_SIGNALING:
+ rc = l1ctl_tx_dt_ind(app_data.l1l, &dl_hdr, data, data_len, false);
+ break;
+ case L1SCHED_DT_OTHER:
+ if (lchan->type == L1SCHED_SCH) {
+ if (app_data.l1l->fbsb_conf_sent)
+ return 0;
+ rc = l1ctl_tx_fbsb_conf(app_data.l1l, 0, &dl_hdr,
+ lchan->ts->sched->bsic);
+ break;
+ }
+ /* fall through */
+ default:
+ LOGPFSML(trxcon_fsm, LOGL_ERROR,
+ "Unhandled L2 DATA.ind (type 0x%02x)\n", dt);
+ return -ENODEV;
+ }
+
+ if (data != NULL && data_len > 0) {
+ trxcon_gsmtap_send(lchan_desc, meas->fn, lchan->ts->index,
+ app_data.trx->band_arfcn, meas->rssi, 0,
+ data, data_len);
+ }
+
+ return rc;
+}
+
+int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
+ uint32_t fn, enum l1sched_data_type dt)
+{
+ const struct l1sched_lchan_desc *lchan_desc;
+ struct l1ctl_info_dl dl_hdr;
+ const uint8_t *data;
+ uint8_t ra_buf[2];
+ size_t data_len;
+ int rc;
+
+ lchan_desc = &l1sched_lchan_desc[lchan->type];
+
+ dl_hdr = (struct l1ctl_info_dl) {
+ .chan_nr = lchan_desc->chan_nr | lchan->ts->index,
+ .link_id = lchan_desc->link_id,
+ .frame_nr = htonl(fn),
+ .band_arfcn = htons(app_data.trx->band_arfcn),
+ };
+
+ switch (dt) {
+ case L1SCHED_DT_TRAFFIC:
+ case L1SCHED_DT_PACKET_DATA:
+ rc = l1ctl_tx_dt_conf(app_data.l1l, &dl_hdr, true);
+ data_len = lchan->prim->payload_len;
+ data = lchan->prim->payload;
+ break;
+ case L1SCHED_DT_SIGNALING:
+ rc = l1ctl_tx_dt_conf(app_data.l1l, &dl_hdr, false);
+ data_len = lchan->prim->payload_len;
+ data = lchan->prim->payload;
+ break;
+ case L1SCHED_DT_OTHER:
+ if (PRIM_IS_RACH(lchan->prim)) {
+ const struct l1sched_ts_prim_rach *rach;
+
+ rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload;
+
+ rc = l1ctl_tx_rach_conf(app_data.l1l, app_data.trx->band_arfcn, fn);
+ if (lchan->prim->type == L1SCHED_PRIM_RACH11) {
+ ra_buf[0] = (uint8_t)(rach->ra >> 3);
+ ra_buf[1] = (uint8_t)(rach->ra & 0x07);
+ data = &ra_buf[0];
+ data_len = 2;
+ } else {
+ ra_buf[0] = (uint8_t)(rach->ra);
+ data = &ra_buf[0];
+ data_len = 1;
+ }
+ break;
+ }
+ /* fall through */
+ default:
+ LOGPFSML(trxcon_fsm, LOGL_ERROR,
+ "Unhandled L2 DATA.cnf (type 0x%02x)\n", dt);
+ return -ENODEV;
+ }
+
+ trxcon_gsmtap_send(lchan_desc, fn, lchan->ts->index,
+ app_data.trx->band_arfcn | ARFCN_UPLINK,
+ 0, 0, data, data_len);
+
+ return rc;
+}
+
+/* The trxcon state machine */
static void trxcon_fsm_idle_action(struct osmo_fsm_inst *fi,
uint32_t event, void *data)
{
@@ -92,7 +261,7 @@
if (app_data.trx->fsm->state != TRX_STATE_OFFLINE) {
/* Reset scheduler and clock counter */
- l1sched_reset(app_data.trx, true);
+ l1sched_reset(app_data.sched, true);
/* TODO: implement trx_if_reset() */
trx_if_cmd_poweroff(app_data.trx);
@@ -297,13 +466,13 @@
/* Optional GSMTAP */
if (app_data.gsmtap_ip != NULL) {
- gsmtap = gsmtap_source_init(app_data.gsmtap_ip, GSMTAP_UDP_PORT, 1);
- if (!gsmtap) {
+ app_data.gsmtap = gsmtap_source_init(app_data.gsmtap_ip, GSMTAP_UDP_PORT, 1);
+ if (!app_data.gsmtap) {
LOGP(DAPP, LOGL_ERROR, "Failed to init GSMTAP\n");
goto exit;
}
/* Suppress ICMP "destination unreachable" errors */
- gsmtap_source_add_sink(gsmtap);
+ gsmtap_source_add_sink(app_data.gsmtap);
}
/* Allocate the application state machine */
@@ -329,10 +498,14 @@
app_data.trx->l1l = app_data.l1l;
/* Init scheduler */
- rc = l1sched_init(app_data.trx, app_data.trx_fn_advance);
- if (rc)
+ app_data.sched = l1sched_alloc(tall_trxcon_ctx, app_data.trx_fn_advance);
+ if (app_data.sched == NULL)
goto exit;
+ /* Let both L1CTL and TRX interfaces access to the scheduler */
+ app_data.l1l->sched = app_data.sched;
+ app_data.trx->sched = app_data.sched;
+
LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
if (app_data.daemonize) {
@@ -352,7 +525,7 @@
exit:
/* Close active connections */
l1ctl_link_shutdown(app_data.l1l);
- l1sched_shutdown(app_data.trx);
+ l1sched_free(app_data.sched);
trx_if_close(app_data.trx);
/* Shutdown main state machine */
To view, visit change 28554. To unsubscribe, or for help writing mail filters, visit settings.