From 8428b1ea0a68d653d62778a36f8d7bf4435623f2 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Wed, 6 Jul 2022 18:06:07 +0700 Subject: [PATCH] trxcon: abstract out the scheduler API from L1CTL/TRXD/TRXC Change-Id: I31f77976a7a225ef292fe6dcd583513aec97ed44 Related: OS#5599, OS#3761 --- .../trxcon/include/osmocom/bb/trxcon/l1ctl.h | 2 +- .../include/osmocom/bb/trxcon/l1ctl_link.h | 3 + .../include/osmocom/bb/trxcon/l1sched.h | 86 +++++--- .../trxcon/include/osmocom/bb/trxcon/trx_if.h | 11 +- .../trxcon/include/osmocom/bb/trxcon/trxcon.h | 1 - src/host/trxcon/src/l1ctl.c | 32 ++- src/host/trxcon/src/sched_lchan_common.c | 98 +-------- src/host/trxcon/src/sched_lchan_desc.c | 46 ++--- src/host/trxcon/src/sched_lchan_pdtch.c | 29 ++- src/host/trxcon/src/sched_lchan_rach.c | 34 +-- src/host/trxcon/src/sched_lchan_sch.c | 43 +--- src/host/trxcon/src/sched_lchan_tchf.c | 49 ++--- src/host/trxcon/src/sched_lchan_tchh.c | 51 ++--- src/host/trxcon/src/sched_lchan_xcch.c | 38 ++-- src/host/trxcon/src/sched_prim.c | 14 +- src/host/trxcon/src/sched_trx.c | 133 ++++++------ src/host/trxcon/src/trx_if.c | 5 +- src/host/trxcon/src/trxcon.c | 193 +++++++++++++++++- 18 files changed, 460 insertions(+), 408 deletions(-) diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h index 2e7e21903..6fac3a05e 100644 --- a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h +++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h @@ -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); 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 a333e4073..4604e2788 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 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; diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h b/src/host/trxcon/include/osmocom/bb/trxcon/l1sched.h index 03dfec361..f78230b00 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 @@ 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); 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 033eaa3c9..f1764179d 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 #include -#include - #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; diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h index 9a0792bfb..f66a62858 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 cb3a06c07..526772bc7 100644 --- a/src/host/trxcon/src/l1ctl.c +++ b/src/host/trxcon/src/l1ctl.c @@ -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; diff --git a/src/host/trxcon/src/sched_lchan_common.c b/src/host/trxcon/src/sched_lchan_common.c index c2d79de6f..0f8cb959d 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 + * (C) 2017-2022 by Vadim Yanitskiy + * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -36,12 +37,8 @@ #include #include -#include #include #include -#include -#include -#include /* 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. diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c index 96a709205..60cba7af7 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 * (C) 2015 by Alexander Chemeris * (C) 2015 by Harald Welte + * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -29,44 +30,39 @@ #include /* 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 6063438b8..cb0f1ec91 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 + * (C) 2018-2022 by Vadim Yanitskiy * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved @@ -30,15 +30,12 @@ #include #include -#include #include #include -#include -#include -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); diff --git a/src/host/trxcon/src/sched_lchan_rach.c b/src/host/trxcon/src/sched_lchan_rach.c index d322030ad..808cfe8f8 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 + * (C) 2017-2022 by Vadim Yanitskiy * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved @@ -30,11 +30,8 @@ #include #include -#include #include #include -#include -#include /* 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); diff --git a/src/host/trxcon/src/sched_lchan_sch.c b/src/host/trxcon/src/sched_lchan_sch.c index 59f1691c9..d29083c0d 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 + * (C) 2017-2022 by Vadim Yanitskiy + * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -31,11 +32,8 @@ #include #include -#include #include #include -#include -#include 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; } diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c index fe7370ea6..e7a044466 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 + * (C) 2017-2022 by Vadim Yanitskiy * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved @@ -32,15 +32,12 @@ #include #include -#include #include #include -#include -#include -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); diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c index 706b74af1..b34bc6b2b 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 + * (C) 2018-2022 by Vadim Yanitskiy * (C) 2018 by Harald Welte * Contributions by sysmocom - s.f.m.c. GmbH * @@ -35,11 +35,8 @@ #include #include -#include #include #include -#include -#include 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); diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c index 758f41fe2..e9ed05fcd 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 + * (C) 2017-2022 by Vadim Yanitskiy * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved @@ -30,15 +30,12 @@ #include #include -#include #include #include -#include -#include -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 */ - 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 @@ 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 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 55a23d1ae..17d0141c6 100644 --- a/src/host/trxcon/src/sched_prim.c +++ b/src/host/trxcon/src/sched_prim.c @@ -31,7 +31,6 @@ #include #include -#include #include /** @@ -79,14 +78,14 @@ static struct l1sched_ts_prim *prim_alloc(void *ctx, size_t pl_len, * 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) @@ -99,7 +98,7 @@ struct l1sched_ts_prim *l1sched_prim_push(struct trx_instance *trx, 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; @@ -188,8 +187,11 @@ static struct l1sched_ts_prim *prim_compose_mr(struct l1sched_lchan_state *lchan * 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 c34e2b70c..48d8e1798 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 + * (C) 2017-2022 by Vadim Yanitskiy + * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -31,17 +32,28 @@ #include #include -#include #include -#include #include +static int l1sched_cfg_pchan_comb_req(struct l1sched_state *sched, + uint8_t tn, uint8_t pchan) +{ + const struct l1sched_config_req cr = { + .type = L1SCHED_CFG_PCHAN_COMB, + .pchan_comb = { + .tn = tn, + .pchan = pchan, + }, + }; + + 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 @@ static void sched_frame_clck_cb(struct l1sched_state *sched) 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 @@ static void sched_frame_clck_cb(struct l1sched_state *sched) 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 @@ static void sched_frame_clck_cb(struct l1sched_state *sched) /* 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 @@ void l1sched_del_ts(struct trx_instance *trx, int tn) 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_cfg_pchan_comb_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 @@ int l1sched_configure_ts(struct trx_instance *trx, int tn, /* Notify transceiver about TS activation */ /* FIXME: set proper channel type */ - trx_if_cmd_setslot(trx, tn, 1); + l1sched_cfg_pchan_comb_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 @@ int l1sched_reset_ts(struct trx_instance *trx, int tn) } /* Notify transceiver about that */ - trx_if_cmd_setslot(trx, tn, 0); + l1sched_cfg_pchan_comb_req(sched, tn, 0); return 0; } @@ -397,7 +396,8 @@ struct l1sched_lchan_state *l1sched_find_lchan(struct l1sched_ts *ts, 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 @@ int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr, int active, uint8 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 @@ static int subst_frame_loss(struct l1sched_lchan_state *lchan, 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 @@ static int subst_frame_loss(struct l1sched_lchan_state *lchan, 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 l1sched_handle_rx_burst(struct trx_instance *trx, uint8_t tn, 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 @@ int l1sched_handle_rx_burst(struct trx_instance *trx, uint8_t tn, 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 a251da0b6..b247064ff 100644 --- a/src/host/trxcon/src/trx_if.c +++ b/src/host/trxcon/src/trx_if.c @@ -39,6 +39,7 @@ #include +#include #include #include #include @@ -619,11 +620,11 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what) }; /* 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 08050d371..08dec8487 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 + * (C) 2016-2022 by Vadim Yanitskiy + * Contributions by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -48,7 +50,8 @@ #include #define COPYRIGHT \ - "Copyright (C) 2016-2020 by Vadim Yanitskiy \n" \ + "Copyright (C) 2016-2022 by Vadim Yanitskiy \n" \ + "Contributions by sysmocom - s.f.m.c. GmbH \n" \ "License GPLv2+: GNU GPL version 2 or later " \ "\n" \ "This is free software: you are free to change and redistribute it.\n" \ @@ -59,6 +62,9 @@ static struct { int daemonize; int quit; + /* The scheduler */ + struct l1sched_state *sched; + /* L1CTL specific */ struct l1ctl_link *l1l; const char *bind_socket; @@ -69,13 +75,176 @@ static struct { 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_PCHAN_COMB: + return trx_if_cmd_setslot(app_data.trx, + cr->pchan_comb.tn, + cr->pchan_comb.pchan); + 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 (L1SCHED_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 @@ static void trxcon_fsm_managed_action(struct osmo_fsm_inst *fi, 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 @@ int main(int argc, char **argv) /* 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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) 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 */