aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-virtual/scheduler_virtbts.c
diff options
context:
space:
mode:
authorSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
committerSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
commita8b7c8aa05bf7292c6ed289f22f961d9ec397fc1 (patch)
tree6b1d32a5de81a1c731d96e0c299343cdf384771b /src/osmo-bts-virtual/scheduler_virtbts.c
parent17eb1a45b446d631449143a52b503978e6661637 (diff)
VIRT-PHY: Added functionality to cooperate with osmocom-bb virt-phy.
This patch improves the virtual physical layer designed to replace the air interface. The purpose is to get rid of the hardware requirements and be able to start testing and implementing layer 2 communication functionality on one machine. Multicast sockets are used to enable bidirectional communication between the BTS and the MS process. The GSMTAP protocol designed for wireshark capturing is used to encapsulate the payload on the virtual physical layer. * Working mcast socket communication and extraction of its functionality. * Fixed OML and RSL startup sequences. * Icludes tests for mcast socket and virtual UM. * Ecapsulation and parsing methods to and from GSMTAP messages. * Basic handlers for file descriptor callbacks from incoming mcast messages. * Multiplexing to different channels based on GSMTAP header channel type.
Diffstat (limited to 'src/osmo-bts-virtual/scheduler_virtbts.c')
-rw-r--r--src/osmo-bts-virtual/scheduler_virtbts.c318
1 files changed, 189 insertions, 129 deletions
diff --git a/src/osmo-bts-virtual/scheduler_virtbts.c b/src/osmo-bts-virtual/scheduler_virtbts.c
index c23632c5..0531ef61 100644
--- a/src/osmo-bts-virtual/scheduler_virtbts.c
+++ b/src/osmo-bts-virtual/scheduler_virtbts.c
@@ -28,6 +28,8 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/core/gsmtap.h>
+#include <osmocom/gsm/rsl.h>
#include <osmocom/netif/rtp.h>
@@ -44,23 +46,48 @@
extern void *tall_bts_ctx;
-
-
+/**
+ * Send a message over the virtual um interface.
+ * This will at first wrap the msg with a gsmtap header and then write it to the declared multicast socket.
+ */
static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, struct msgb *msg)
+ enum trx_chan_type chan, struct msgb *msg)
{
const struct trx_chan_desc *chdesc = &trx_chan_desc[chan];
- uint8_t ss = 0; //FIXME(chdesc);
- uint8_t gsmtap_chan;
+ uint8_t chan_type, timeslot, subslot, signal_dbm, signal_snr;
+ rsl_dec_chan_nr(chdesc->chan_nr, &chan_type, &subslot, &timeslot);
+ if (chan_type == RSL_CHAN_PCH_AGCH) {
+ if (L1SAP_FN2CCCHBLOCK(fn) >= 1) {
+ chan_type = GSMTAP_CHANNEL_PCH;
+ } else {
+ chan_type = GSMTAP_CHANNEL_AGCH;
+ }
+ } else {
+ chan_type = chantype_rsl2gsmtap(chan_type, chdesc->link_id); // the logical channel type
+ }
+ //uint8_t timeslot = tn; // indicates the physical channel
+ //uint8_t subslot = 0; // indicates the logical channel subslot on the physical channel FIXME: calculate
+ signal_dbm = 63; // the signal strength is not needed in virt phy
+ signal_snr = 40; // the signal to noice ratio is not needed in virt phy
+ uint8_t *data = msgb_l2(msg); // data bits to transmit (whole message without l1 header)
+ uint8_t data_len = msgb_l2len(msg);
struct msgb *outmsg;
- gsmtap_chan = chantype_rsl2gsmtap(chdesc->chan_nr, chdesc->link_id);
- outmsg = gsmtap_makemsg(l1t->trx->arfcn, tn, gsmtap_chan, ss, fn,
- 0, 0, msgb_l2(msg), msgb_l2len(msg));
+ // TODO: encrypt and encode message data
+
+ outmsg = gsmtap_makemsg(l1t->trx->arfcn, timeslot, chan_type, subslot,
+ fn, signal_dbm, signal_snr, data, data_len);
if (outmsg) {
struct phy_instance *pinst = trx_phy_instance(l1t->trx);
struct virt_um_inst *virt_um = pinst->phy_link->u.virt.virt_um;
- virt_um_write_msg(virt_um, outmsg);
+ if (virt_um_write_msg(virt_um, outmsg) == -1) {
+ struct gsmtap_hdr *gh = (struct gsmtap_hdr *)msgb_data(
+ outmsg);
+ LOGP(DL1C, LOGL_ERROR,
+ "Message could not be written to virtual UM! arfcn = %u gsmtap_chan=%u fn=%u ts=%u\n",
+ gh->arfcn, gh->type, gh->frame_number,
+ gh->timeslot);
+ }
}
/* free message */
@@ -73,62 +100,67 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
return NULL;
}
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
return NULL;
}
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
return NULL;
}
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
struct msgb *msg;
+ if (fn == 57) {
+ DEBUGP(DL1P, "lol");
+ }
+
if (bid > 0)
return NULL;
/* get mac block from queue */
+ // what queue is that and who does fill it?
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
if (msg)
goto got_msg;
LOGP(DL1P, LOGL_INFO, "%s has not been served !! No prim for "
- "trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
+ "trx=%u ts=%u at fn=%u to transmit.\n",
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
-no_msg:
- return NULL;
+ no_msg: return NULL;
-got_msg:
+ got_msg:
/* check validity of message */
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
LOGP(DL1P, LOGL_FATAL, "Prim not 23 bytes, please FIX! "
- "(len=%d)\n", msgb_l2len(msg));
+ "(len=%d)\n", msgb_l2len(msg));
/* free message */
msgb_free(msg);
goto no_msg;
}
+ // transmit the msg received on dl from bsc to layer1 (virt um)
tx_to_virt_um(l1t, tn, fn, chan, msg);
return NULL;
}
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
@@ -144,21 +176,20 @@ ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
goto got_msg;
LOGP(DL1P, LOGL_INFO, "%s has not been served !! No prim for "
- "trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
+ "trx=%u ts=%u at fn=%u to transmit.\n",
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
-no_msg:
- return NULL;
+ no_msg: return NULL;
-got_msg:
- tx_to_virt_um(l1t, tn, fn, chan, msg);
+ got_msg: tx_to_virt_um(l1t, tn, fn, chan, msg);
return NULL;
}
static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,
- struct msgb **_msg_facch, int codec_mode_request)
+ enum trx_chan_type chan, uint8_t bid,
+ struct msgb **_msg_tch, struct msgb **_msg_facch,
+ int codec_mode_request)
{
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
@@ -169,16 +200,16 @@ static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
#if 0
/* handle loss detection of received TCH frames */
if (rsl_cmode == RSL_CMOD_SPD_SPEECH
- && ++(chan_state->lost) > 5) {
+ && ++(chan_state->lost) > 5) {
uint8_t tch_data[GSM_FR_BYTES];
int len;
LOGP(DL1P, LOGL_NOTICE, "Missing TCH bursts detected, sending "
- "BFI for %s\n", trx_chan_desc[chan].name);
+ "BFI for %s\n", trx_chan_desc[chan].name);
/* indicate bad frame */
switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR / HR */
+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */
if (chan != TRXC_TCHF) { /* HR */
tch_data[0] = 0x70; /* F = 0, FT = 111 */
memset(tch_data + 1, 0, 14);
@@ -188,29 +219,29 @@ static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
memset(tch_data, 0, GSM_FR_BYTES);
len = GSM_FR_BYTES;
break;
- case GSM48_CMODE_SPEECH_EFR: /* EFR */
+ case GSM48_CMODE_SPEECH_EFR: /* EFR */
if (chan != TRXC_TCHF)
- goto inval_mode1;
+ goto inval_mode1;
memset(tch_data, 0, GSM_EFR_BYTES);
len = GSM_EFR_BYTES;
break;
- case GSM48_CMODE_SPEECH_AMR: /* AMR */
+ case GSM48_CMODE_SPEECH_AMR: /* AMR */
len = amr_compose_payload(tch_data,
- chan_state->codec[chan_state->dl_cmr],
- chan_state->codec[chan_state->dl_ft], 1);
+ chan_state->codec[chan_state->dl_cmr],
+ chan_state->codec[chan_state->dl_ft], 1);
if (len < 2)
- break;
+ break;
memset(tch_data + 2, 0, len - 2);
_sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
break;
- default:
-inval_mode1:
+ default:
+ inval_mode1:
LOGP(DL1P, LOGL_ERROR, "TCH mode invalid, please "
- "fix!\n");
+ "fix!\n");
len = 0;
}
if (len)
- _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
+ _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
}
#endif
@@ -225,7 +256,7 @@ inval_mode1:
l1sap = msgb_l1sap_prim(msg2);
if (l1sap->oph.primitive == PRIM_TCH) {
LOGP(DL1P, LOGL_FATAL, "TCH twice, "
- "please FIX! ");
+ "please FIX! ");
msgb_free(msg2);
} else
msg_facch = msg2;
@@ -236,7 +267,7 @@ inval_mode1:
l1sap = msgb_l1sap_prim(msg2);
if (l1sap->oph.primitive != PRIM_TCH) {
LOGP(DL1P, LOGL_FATAL, "FACCH twice, "
- "please FIX! ");
+ "please FIX! ");
msgb_free(msg2);
} else
msg_tch = msg2;
@@ -253,7 +284,7 @@ inval_mode1:
/* check validity of message */
if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
LOGP(DL1P, LOGL_FATAL, "Prim not 23 bytes, please FIX! "
- "(len=%d)\n", msgb_l2len(msg_facch));
+ "(len=%d)\n", msgb_l2len(msg_facch));
/* free message */
msgb_free(msg_facch);
msg_facch = NULL;
@@ -266,10 +297,12 @@ inval_mode1:
int cmr, ft, i;
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
- LOGP(DL1P, LOGL_NOTICE, "%s Dropping speech frame, "
- "because we are not in speech mode trx=%u "
- "ts=%u at fn=%u.\n", trx_chan_desc[chan].name,
- l1t->trx->nr, tn, fn);
+ LOGP(DL1P, LOGL_NOTICE,
+ "%s Dropping speech frame, "
+ "because we are not in speech mode trx=%u "
+ "ts=%u at fn=%u.\n",
+ trx_chan_desc[chan].name, l1t->trx->nr,
+ tn, fn);
goto free_bad_msg;
}
@@ -278,24 +311,27 @@ inval_mode1:
if (chan != TRXC_TCHF) { /* HR */
len = 15;
if (msgb_l2len(msg_tch) >= 1
- && (msg_tch->l2h[0] & 0xf0) != 0x00) {
- LOGP(DL1P, LOGL_NOTICE, "%s "
- "Transmitting 'bad "
- "HR frame' trx=%u ts=%u at "
- "fn=%u.\n",
- trx_chan_desc[chan].name,
- l1t->trx->nr, tn, fn);
+ && (msg_tch->l2h[0] & 0xf0)
+ != 0x00) {
+ LOGP(DL1P, LOGL_NOTICE,
+ "%s "
+ "Transmitting 'bad "
+ "HR frame' trx=%u ts=%u at "
+ "fn=%u.\n",
+ trx_chan_desc[chan].name,
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
}
len = GSM_FR_BYTES;
if (msgb_l2len(msg_tch) >= 1
- && (msg_tch->l2h[0] >> 4) != 0xd) {
- LOGP(DL1P, LOGL_NOTICE, "%s Transmitting 'bad "
- "FR frame' trx=%u ts=%u at fn=%u.\n",
- trx_chan_desc[chan].name,
- l1t->trx->nr, tn, fn);
+ && (msg_tch->l2h[0] >> 4) != 0xd) {
+ LOGP(DL1P, LOGL_NOTICE,
+ "%s Transmitting 'bad "
+ "FR frame' trx=%u ts=%u at fn=%u.\n",
+ trx_chan_desc[chan].name,
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
@@ -304,26 +340,27 @@ inval_mode1:
goto inval_mode2;
len = GSM_EFR_BYTES;
if (msgb_l2len(msg_tch) >= 1
- && (msg_tch->l2h[0] >> 4) != 0xc) {
- LOGP(DL1P, LOGL_NOTICE, "%s Transmitting 'bad "
- "EFR frame' trx=%u ts=%u at fn=%u.\n",
- trx_chan_desc[chan].name,
- l1t->trx->nr, tn, fn);
+ && (msg_tch->l2h[0] >> 4) != 0xc) {
+ LOGP(DL1P, LOGL_NOTICE,
+ "%s Transmitting 'bad "
+ "EFR frame' trx=%u ts=%u at fn=%u.\n",
+ trx_chan_desc[chan].name,
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
case GSM48_CMODE_SPEECH_AMR: /* AMR */
#if 0
len = amr_decompose_payload(msg_tch->l2h,
- msgb_l2len(msg_tch), &cmr_codec, &ft_codec,
- &bfi);
+ msgb_l2len(msg_tch), &cmr_codec, &ft_codec,
+ &bfi);
cmr = -1;
ft = -1;
for (i = 0; i < chan_state->codecs; i++) {
if (chan_state->codec[i] == cmr_codec)
- cmr = i;
+ cmr = i;
if (chan_state->codec[i] == ft_codec)
- ft = i;
+ ft = i;
}
if (cmr >= 0) { /* new request */
chan_state->dl_cmr = cmr;
@@ -335,46 +372,47 @@ inval_mode1:
}
if (ft < 0) {
LOGP(DL1P, LOGL_ERROR, "%s Codec (FT = %d) "
- " of RTP frame not in list. "
- "trx=%u ts=%u\n",
- trx_chan_desc[chan].name, ft_codec,
- l1t->trx->nr, tn);
+ " of RTP frame not in list. "
+ "trx=%u ts=%u\n",
+ trx_chan_desc[chan].name, ft_codec,
+ l1t->trx->nr, tn);
goto free_bad_msg;
}
if (codec_mode_request && chan_state->dl_ft != ft) {
LOGP(DL1P, LOGL_NOTICE, "%s Codec (FT = %d) "
- " of RTP cannot be changed now, but in "
- "next frame. trx=%u ts=%u\n",
- trx_chan_desc[chan].name, ft_codec,
- l1t->trx->nr, tn);
+ " of RTP cannot be changed now, but in "
+ "next frame. trx=%u ts=%u\n",
+ trx_chan_desc[chan].name, ft_codec,
+ l1t->trx->nr, tn);
goto free_bad_msg;
}
chan_state->dl_ft = ft;
if (bfi) {
LOGP(DL1P, LOGL_NOTICE, "%s Transmitting 'bad "
- "AMR frame' trx=%u ts=%u at fn=%u.\n",
- trx_chan_desc[chan].name,
- l1t->trx->nr, tn, fn);
+ "AMR frame' trx=%u ts=%u at fn=%u.\n",
+ trx_chan_desc[chan].name,
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
#endif
break;
default:
-inval_mode2:
+ inval_mode2:
LOGP(DL1P, LOGL_ERROR, "TCH mode invalid, please "
- "fix!\n");
+ "fix!\n");
goto free_bad_msg;
}
if (len < 0) {
LOGP(DL1P, LOGL_ERROR, "Cannot send invalid AMR "
- "payload\n");
+ "payload\n");
goto free_bad_msg;
}
if (msgb_l2len(msg_tch) != len) {
- LOGP(DL1P, LOGL_ERROR, "Cannot send payload with "
- "invalid length! (expecing %d, received %d)\n",
- len, msgb_l2len(msg_tch));
-free_bad_msg:
+ LOGP(DL1P, LOGL_ERROR,
+ "Cannot send payload with "
+ "invalid length! (expecing %d, received %d)\n",
+ len, msgb_l2len(msg_tch));
+ free_bad_msg:
/* free message */
msgb_free(msg_tch);
msg_tch = NULL;
@@ -382,13 +420,12 @@ free_bad_msg:
}
}
-send_frame:
- *_msg_tch = msg_tch;
+ send_frame: *_msg_tch = msg_tch;
*_msg_facch = msg_facch;
}
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
@@ -400,13 +437,13 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
return NULL;
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
- (((fn + 4) % 26) >> 2) & 1);
+ (((fn + 4) % 26) >> 2) & 1);
/* no message at all */
if (!msg_tch && !msg_facch) {
LOGP(DL1P, LOGL_INFO, "%s has not been served !! No prim for "
- "trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
+ "trx=%u ts=%u at fn=%u to transmit.\n",
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
goto send_burst;
}
@@ -416,13 +453,13 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
} else
tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
-send_burst:
+ send_burst:
return NULL;
}
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
@@ -436,13 +473,13 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
/* get TCH and/or FACCH */
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
- (((fn + 4) % 26) >> 2) & 1);
+ (((fn + 4) % 26) >> 2) & 1);
/* check for FACCH alignment */
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
LOGP(DL1P, LOGL_ERROR, "%s Cannot transmit FACCH starting on "
- "even frames, please fix RTS!\n",
- trx_chan_desc[chan].name);
+ "even frames, please fix RTS!\n",
+ trx_chan_desc[chan].name);
msgb_free(msg_facch);
msg_facch = NULL;
}
@@ -450,8 +487,8 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
/* no message at all */
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
LOGP(DL1P, LOGL_INFO, "%s has not been served !! No prim for "
- "trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
+ "trx=%u ts=%u at fn=%u to transmit.\n",
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
goto send_burst;
}
@@ -461,11 +498,9 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
} else
tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
-send_burst:
- return NULL;
+ send_burst: return NULL;
}
-
/***********************************************************************
* RX on uplink (indication to upper layer)
***********************************************************************/
@@ -475,42 +510,43 @@ send_burst:
* towards receiving bursts */
int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
- float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits,
+ uint16_t nbits, int8_t rssi, float toa)
{
return 0;
}
/*! \brief a single burst was received by the PHY, process it */
int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
- float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits,
+ uint16_t nbits, int8_t rssi, float toa)
{
return 0;
}
int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
- float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits,
+ uint16_t nbits, int8_t rssi, float toa)
{
return 0;
}
int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
- float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits,
+ uint16_t nbits, int8_t rssi, float toa)
{
return 0;
}
int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
- float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits,
+ uint16_t nbits, int8_t rssi, float toa)
{
return 0;
}
-void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
+void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss,
+ int activate)
{
}
@@ -524,22 +560,36 @@ void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int ac
static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
{
struct gsm_bts_trx *trx;
+ uint16_t nbits;
/* send time indication */
+ // update model with new frame number, lot of stuff happening, mesurements of timeslots
+ // saving gsm time in bts model, and more
l1if_mph_time_ind(bts, fn);
/* advance the frame number? */
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
+ // is this the time advance functionality that depends of the distance to the ms???
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ {
struct phy_instance *pinst = trx_phy_instance(trx);
struct l1sched_trx *l1t = &pinst->u.virt.sched;
int tn;
-
+ const ubit_t *bits;
+ // do for each of the 8 timeslots
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
- /* Generate RTS.ind to higher layers */
- _sched_rts(l1t, tn, (fn + RTS_ADVANCE) % GSM_HYPERFRAME);
+ /* Generate RTS indication to higher layers */
+ // ST: This will basically do 2 things (check l1_if:bts_model_l1sap_down):
+ // 1) Get pending messages from layer 2 (from the lapdm queue)
+ // 2) Process the messages
+ // --> Handle and process non-transparent RSL-Messages (activate channel, )
+ // --> Forward transparent RSL-DATA-Messages to the ms by appending them to the l1-dl-queue
+ _sched_rts(l1t, tn,
+ (fn + RTS_ADVANCE) % GSM_HYPERFRAME);
/* schedule transmit backend functions */
- _sched_dl_burst(l1t, tn, fn);
+ // ST: Process data in the l1-dlqueue and forward it to ms
+ // the returned bits are not used here, the routines called will directly forward their bits to the virt um
+ bits = _sched_dl_burst(l1t, tn, fn, &nbits);
+
}
}
@@ -556,25 +606,34 @@ static void vbts_fn_timer_cb(void *data)
gettimeofday(&tv_now, NULL);
- elapsed_us = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 +
- (tv_now.tv_usec - tv_clock->tv_usec);
+ // check how much time elapsed till the last timer callback call
+ // this value should be about 4.615 ms (a bit greater) as this is the scheduling interval
+ elapsed_us = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000
+ + (tv_now.tv_usec - tv_clock->tv_usec);
- if (elapsed_us > 2*FRAME_DURATION_uS)
- LOGP(DL1P, LOGL_NOTICE, "vbts_fn_timer_cb after %d us\n", elapsed_us);
+ // not so good somehow a lot of time passed between two timer callbacks
+ if (elapsed_us > 2 * FRAME_DURATION_uS)
+ LOGP(DL1P, LOGL_NOTICE, "vbts_fn_timer_cb after %d us\n",
+ elapsed_us);
+ // schedule the current frame/s (fn = frame number)
+ // this loop will be called at least once, but can also be executed
+ // multiple times if more than one frame duration (4615us) passed till the last callback
while (elapsed_us > FRAME_DURATION_uS / 2) {
- const struct timeval tv_frame = {
- .tv_sec = 0,
- .tv_usec = FRAME_DURATION_uS,
- };
+ const struct timeval tv_frame = {.tv_sec = 0, .tv_usec =
+ FRAME_DURATION_uS, };
timeradd(tv_clock, &tv_frame, tv_clock);
+ // increment the frame number in the bts model instance
btsb->vbts.last_fn = (btsb->vbts.last_fn + 1) % GSM_HYPERFRAME;
vbts_sched_fn(bts, btsb->vbts.last_fn);
elapsed_us -= FRAME_DURATION_uS;
}
/* re-schedule the timer */
- osmo_timer_schedule(&btsb->vbts.fn_timer, 0, FRAME_DURATION_uS - elapsed_us);
+ // timer is set to frame duration - elapsed time to guarantee that this cb method will be
+ // periodically executed every 4.615ms
+ osmo_timer_schedule(&btsb->vbts.fn_timer, 0,
+ FRAME_DURATION_uS - elapsed_us);
}
int vbts_sched_start(struct gsm_bts *bts)
@@ -588,6 +647,7 @@ int vbts_sched_start(struct gsm_bts *bts)
btsb->vbts.fn_timer.data = bts;
gettimeofday(&btsb->vbts.tv_clock, NULL);
+ // trigger the first timer after 4615us (a frame duration)
osmo_timer_schedule(&btsb->vbts.fn_timer, 0, FRAME_DURATION_uS);
return 0;