summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h2
-rw-r--r--src/host/trxcon/include/osmocom/bb/l1sched/prim.h3
-rw-r--r--src/host/trxcon/src/sched_lchan_common.c49
-rw-r--r--src/host/trxcon/src/sched_lchan_tchf.c45
-rw-r--r--src/host/trxcon/src/sched_lchan_tchh.c119
-rw-r--r--src/host/trxcon/src/sched_lchan_xcch.c2
-rw-r--r--src/host/trxcon/src/sched_prim.c83
7 files changed, 53 insertions, 250 deletions
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
index cee26600..5385c00d 100644
--- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
+++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
@@ -389,8 +389,6 @@ int l1sched_handle_burst_req(struct l1sched_state *sched,
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);
-bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr);
/* Interleaved TCH/H block TDMA frame mapping */
bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan,
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h
index c0e6af60..af3ac3b6 100644
--- a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h
+++ b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h
@@ -116,9 +116,10 @@ void l1sched_prim_init(struct msgb *msg,
struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type,
enum osmo_prim_operation op);
+bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr);
struct msgb *l1sched_lchan_prim_dequeue_sacch(struct l1sched_lchan_state *lchan);
struct msgb *l1sched_lchan_prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch);
-struct msgb *l1sched_lchan_prim_dummy(struct l1sched_lchan_state *lchan);
+struct msgb *l1sched_lchan_prim_dummy_lapdm(const struct l1sched_lchan_state *lchan);
void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan);
int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan,
diff --git a/src/host/trxcon/src/sched_lchan_common.c b/src/host/trxcon/src/sched_lchan_common.c
index ad42d9e8..bf318316 100644
--- a/src/host/trxcon/src/sched_lchan_common.c
+++ b/src/host/trxcon/src/sched_lchan_common.c
@@ -93,55 +93,6 @@ const char *l1sched_burst_mask2str(const uint8_t *mask, int bits)
return buf;
}
-/**
- * Composes a bad frame indication message
- * according to the current tch_mode.
- *
- * @param l2 Caller-allocated byte array
- * @param lchan Logical channel to generate BFI for
- * @return How much bytes were written
- */
-size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan)
-{
- int rc;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- if (lchan->type == L1SCHED_TCHF) { /* Full Rate */
- memset(l2, 0x00, GSM_FR_BYTES);
- l2[0] = 0xd0;
- return GSM_FR_BYTES;
- } else { /* Half Rate */
- memset(l2 + 1, 0x00, GSM_HR_BYTES);
- l2[0] = 0x70; /* F = 0, FT = 111 */
- return GSM_HR_BYTES + 1;
- }
- case GSM48_CMODE_SPEECH_EFR: /* Enhanced Full Rate */
- memset(l2, 0x00, GSM_EFR_BYTES);
- l2[0] = 0xc0;
- return GSM_EFR_BYTES;
- case GSM48_CMODE_SPEECH_AMR: /* Adaptive Multi Rate */
- rc = osmo_amr_rtp_enc(l2,
- lchan->amr.codec[lchan->amr.dl_cmr],
- lchan->amr.codec[lchan->amr.dl_ft],
- AMR_BAD);
- if (rc < 2) {
- LOGP_LCHAND(lchan, LOGL_ERROR,
- "Failed to encode AMR_BAD frame (rc=%d), "
- "not sending BFI\n", rc);
- return 0;
- }
- memset(l2 + 2, 0, rc - 2);
- return rc;
- case GSM48_CMODE_SIGN:
- LOGP_LCHAND(lchan, LOGL_ERROR, "BFI is not allowed in signalling mode\n");
- return 0;
- default:
- LOGP_LCHAND(lchan, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->tch_mode);
- return 0;
- }
-}
-
bool l1sched_lchan_amr_prim_is_valid(struct l1sched_lchan_state *lchan, bool is_cmr)
{
enum osmo_amr_type ft_codec;
diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c
index a87efafe..cd53c46f 100644
--- a/src/host/trxcon/src/sched_lchan_tchf.c
+++ b/src/host/trxcon/src/sched_lchan_tchf.c
@@ -167,16 +167,17 @@ int rx_tchf_fn(struct l1sched_lchan_state *lchan,
"Received bad frame (rc=%d, ber=%d/%d) at fn=%u\n",
rc, n_errors, n_bits_total, lchan->meas_avg.fn);
- /* Send BFI */
- goto bfi;
+ /* Send BFI (DATA.ind without payload) */
+ tch_data_len = 0;
} else if (rc == GSM_MACBLOCK_LEN) {
/* FACCH received, forward it to the higher layers */
l1sched_lchan_emit_data_ind(lchan, &tch_data[amr], GSM_MACBLOCK_LEN,
n_errors, n_bits_total, false);
- /* Send BFI substituting a stolen TCH frame */
- n_errors = -1; /* ensure fake measurements */
- goto bfi;
+ /* Send BFI (DATA.ind without payload) */
+ if (lchan->tch_mode == GSM48_CMODE_SIGN)
+ return 0;
+ tch_data_len = 0;
} else {
/* A good TCH frame received */
tch_data_len = rc;
@@ -185,32 +186,6 @@ int rx_tchf_fn(struct l1sched_lchan_state *lchan,
/* Send a traffic frame to the higher layers */
return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len,
n_errors, n_bits_total, true);
-
-bfi:
- /* Didn't try to decode, fake measurements */
- if (n_errors < 0) {
- lchan->meas_avg = (struct l1sched_meas_set) {
- .fn = lchan->meas_avg.fn,
- .toa256 = 0,
- .rssi = -110,
- };
-
- /* No bursts => no errors */
- n_errors = 0;
- }
-
- /* BFI is not applicable in signalling mode */
- if (lchan->tch_mode == GSM48_CMODE_SIGN) {
- return l1sched_lchan_emit_data_ind(lchan, NULL, 0,
- n_errors, n_bits_total, false);
- }
-
- /* Bad frame indication */
- tch_data_len = l1sched_bad_frame_ind(&tch_data[0], lchan);
-
- /* Send a BFI frame to the higher layers */
- return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len,
- n_errors, n_bits_total, true);
}
static struct msgb *prim_dequeue_tchf(struct l1sched_lchan_state *lchan)
@@ -255,11 +230,9 @@ int tx_tchf_fn(struct l1sched_lchan_state *lchan,
*mask = *mask << 4;
lchan->prim = prim_dequeue_tchf(lchan);
- if (lchan->prim == NULL) {
- lchan->prim = l1sched_lchan_prim_dummy(lchan);
- if (lchan->prim == NULL)
- return -ENOENT;
- }
+ if (lchan->prim == NULL)
+ lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan);
+ OSMO_ASSERT(lchan->prim != NULL);
/* populate the buffer with bursts */
switch (lchan->tch_mode) {
diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c
index 67e21320..3fa823ba 100644
--- a/src/host/trxcon/src/sched_lchan_tchh.c
+++ b/src/host/trxcon/src/sched_lchan_tchh.c
@@ -180,60 +180,6 @@ bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan,
return false;
}
-/**
- * Calculates a frame number of the first burst
- * using given frame number of the last burst.
- *
- * See GSM 05.02, clause 7, table 1
- *
- * @param chan channel type (L1SCHED_TCHH_0 or L1SCHED_TCHH_1)
- * @param last_fn frame number of the last burst
- * @param facch FACCH/H or traffic?
- * @return either frame number of the first burst,
- * or fn=last_fn if calculation failed
- */
-static uint32_t tchh_block_dl_first_fn(const struct l1sched_lchan_state *lchan,
- uint32_t last_fn, bool facch)
-{
- enum l1sched_lchan_type chan = lchan->type;
- uint8_t fn_mf, fn_diff;
- int i = 0;
-
- /* Just to be sure */
- OSMO_ASSERT(chan == L1SCHED_TCHH_0 || chan == L1SCHED_TCHH_1);
-
- /* Calculate a modulo */
- fn_mf = facch ? (last_fn % 26) : (last_fn % 13);
-
-#define BLOCK_FIRST_FN(map) \
- do { \
- if (map[i][ARRAY_SIZE(map[i]) - 1] == fn_mf) { \
- fn_diff = GSM_TDMA_FN_DIFF(fn_mf, map[i][0]); \
- return GSM_TDMA_FN_SUB(last_fn, fn_diff); \
- } \
- } while (++i < ARRAY_SIZE(map))
-
- /* Choose a proper block map */
- if (facch) {
- if (chan == L1SCHED_TCHH_0)
- BLOCK_FIRST_FN(tch_h0_dl_facch_block_map);
- else
- BLOCK_FIRST_FN(tch_h1_dl_facch_block_map);
- } else {
- if (chan == L1SCHED_TCHH_0)
- BLOCK_FIRST_FN(tch_h0_traffic_block_map);
- else
- BLOCK_FIRST_FN(tch_h1_traffic_block_map);
- }
-
- LOGP_LCHAND(lchan, LOGL_ERROR,
- "Failed to calculate TDMA frame number of the first burst of %s block, "
- "using the current fn=%u\n", facch ? "FACCH/H" : "TCH/H", last_fn);
-
- /* Couldn't calculate the first fn, return the last */
- return last_fn;
-}
-
int rx_tchh_fn(struct l1sched_lchan_state *lchan,
const struct l1sched_burst_ind *bi)
{
@@ -290,21 +236,13 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan,
if (bi->bid != 1)
return 0;
- /* Wait for complete set of bursts */
- if (lchan->tch_mode == GSM48_CMODE_SIGN) {
- /* FACCH/H is interleaved over 6 bursts */
- if ((*mask & 0x3f) != 0x3f)
- goto bfi;
- } else {
- /* Traffic is interleaved over 4 bursts */
- if ((*mask & 0x0f) != 0x0f)
- goto bfi;
- }
-
/* Skip decoding attempt in case of FACCH/H */
if (lchan->dl_ongoing_facch) {
+ /* Send BFI (DATA.ind without payload) for the 2nd stolen TCH frame */
+ l1sched_lchan_meas_avg(lchan, 4);
+ l1sched_lchan_emit_data_ind(lchan, NULL, 0, 0, 0, true);
lchan->dl_ongoing_facch = false;
- goto bfi; /* 2/2 BFI */
+ return 0;
}
switch (lchan->tch_mode) {
@@ -350,15 +288,12 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan,
/* Check decoding result */
if (rc < 4) {
- /* Calculate AVG of the measurements (assuming 4 bursts) */
- l1sched_lchan_meas_avg(lchan, 4);
-
LOGP_LCHAND(lchan, LOGL_ERROR,
"Received bad frame (rc=%d, ber=%d/%d) at fn=%u\n",
rc, n_errors, n_bits_total, lchan->meas_avg.fn);
- /* Send BFI */
- goto bfi;
+ /* Send BFI (DATA.ind without payload) */
+ tch_data_len = 0;
} else if (rc == GSM_MACBLOCK_LEN) {
/* Skip decoding of the next 2 stolen bursts */
lchan->dl_ongoing_facch = true;
@@ -370,44 +305,19 @@ int rx_tchh_fn(struct l1sched_lchan_state *lchan,
l1sched_lchan_emit_data_ind(lchan, &tch_data[amr], GSM_MACBLOCK_LEN,
n_errors, n_bits_total, false);
- /* Send BFI substituting 1/2 stolen TCH frames */
- n_errors = -1; /* ensure fake measurements */
- goto bfi;
+ /* Send BFI (DATA.ind without payload) for the 1st stolen TCH frame */
+ if (lchan->tch_mode == GSM48_CMODE_SIGN)
+ return 0;
+ tch_data_len = 0;
} else {
/* A good TCH frame received */
tch_data_len = rc;
-
- /* Calculate AVG of the measurements (traffic takes 4 bursts) */
- l1sched_lchan_meas_avg(lchan, 4);
- }
-
- /* Send a traffic frame to the higher layers */
- return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len,
- n_errors, n_bits_total, true);
-
-bfi:
- /* Didn't try to decode, fake measurements */
- if (n_errors < 0) {
- lchan->meas_avg = (struct l1sched_meas_set) {
- .fn = tchh_block_dl_first_fn(lchan, bi->fn, false),
- .toa256 = 0,
- .rssi = -110,
- };
-
- /* No bursts => no errors */
- n_errors = 0;
}
- /* BFI is not applicable in signalling mode */
- if (lchan->tch_mode == GSM48_CMODE_SIGN) {
- return l1sched_lchan_emit_data_ind(lchan, NULL, 0,
- n_errors, n_bits_total, false);
- }
-
- /* Bad frame indication */
- tch_data_len = l1sched_bad_frame_ind(&tch_data[0], lchan);
+ /* Calculate AVG of the measurements (traffic takes 4 bursts) */
+ l1sched_lchan_meas_avg(lchan, 4);
- /* Send a BFI frame to the higher layers */
+ /* Send a traffic frame to the higher layers */
return l1sched_lchan_emit_data_ind(lchan, &tch_data[0], tch_data_len,
n_errors, n_bits_total, true);
}
@@ -473,7 +383,8 @@ int tx_tchh_fn(struct l1sched_lchan_state *lchan,
lchan->prim = prim_dequeue_tchh(lchan, br->fn);
if (lchan->prim == NULL) {
- lchan->prim = l1sched_lchan_prim_dummy(lchan);
+ if (l1sched_tchh_facch_start(lchan->type, br->fn, 1))
+ lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan);
if (lchan->prim == NULL)
return -ENOENT;
}
diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c
index 7f1dd11a..e2638362 100644
--- a/src/host/trxcon/src/sched_lchan_xcch.c
+++ b/src/host/trxcon/src/sched_lchan_xcch.c
@@ -141,7 +141,7 @@ int tx_data_fn(struct l1sched_lchan_state *lchan,
lchan->prim = prim_dequeue_xcch(lchan);
if (lchan->prim == NULL)
- lchan->prim = l1sched_lchan_prim_dummy(lchan);
+ lchan->prim = l1sched_lchan_prim_dummy_lapdm(lchan);
OSMO_ASSERT(lchan->prim != NULL);
/* Encode payload */
diff --git a/src/host/trxcon/src/sched_prim.c b/src/host/trxcon/src/sched_prim.c
index 3301df4d..46756750 100644
--- a/src/host/trxcon/src/sched_prim.c
+++ b/src/host/trxcon/src/sched_prim.c
@@ -260,81 +260,50 @@ void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan)
}
/**
- * Allocate a dummy DATA.req for the given logical channel.
+ * Allocate a DATA.req with dummy LAPDm func=UI frame for the given logical channel.
* To be used when no suitable DATA.req is present in the Tx queue.
*
* @param lchan lchan to allocate a dummy primitive for
* @return an msgb with DATA.req primitive, or NULL
*/
-struct msgb *l1sched_lchan_prim_dummy(struct l1sched_lchan_state *lchan)
+struct msgb *l1sched_lchan_prim_dummy_lapdm(const struct l1sched_lchan_state *lchan)
{
- const struct l1sched_lchan_desc *lchan_desc;
- enum l1sched_lchan_type chan = lchan->type;
- uint8_t tch_mode = lchan->tch_mode;
struct l1sched_prim *prim;
struct msgb *msg;
- uint8_t prim_buffer[40];
- size_t prim_len = 0;
- int i;
+ uint8_t *ptr;
- /**
- * TS 144.006, section 8.4.2.3 "Fill frames"
- * A fill frame is a UI command frame for SAPI 0, P=0
- * and with an information field of 0 octet length.
- */
- static const uint8_t lapdm_fill_frame[] = {
- 0x01, 0x03, 0x01, 0x2b,
- /* Pending part is to be randomized */
- };
-
- /* Not applicable for SACCH! */
+ /* LAPDm func=UI is not applicable for SACCH */
OSMO_ASSERT(!L1SCHED_CHAN_IS_SACCH(lchan->type));
- lchan_desc = &l1sched_lchan_desc[lchan->type];
-
- /**
- * Determine what actually should be generated:
- * TCH in GSM48_CMODE_SIGN: LAPDm fill frame;
- * TCH in other modes: silence frame;
- * other channels: LAPDm fill frame.
- */
- if (L1SCHED_CHAN_IS_TCH(chan) && L1SCHED_TCH_MODE_IS_SPEECH(tch_mode)) {
- /* Bad frame indication */
- prim_len = l1sched_bad_frame_ind(prim_buffer, lchan);
- } else if (L1SCHED_CHAN_IS_TCH(chan) && L1SCHED_TCH_MODE_IS_DATA(tch_mode)) {
- /* FIXME: should we do anything for CSD? */
- return NULL;
- } else {
- /* Copy LAPDm fill frame's header */
- memcpy(prim_buffer, lapdm_fill_frame, sizeof(lapdm_fill_frame));
-
- /**
- * TS 144.006, section 5.2 "Frame delimitation and fill bits"
- * Except for the first octet containing fill bits which shall
- * be set to the binary value "00101011", each fill bit should
- * be set to a random value when sent by the network.
- */
- for (i = sizeof(lapdm_fill_frame); i < GSM_MACBLOCK_LEN; i++)
- prim_buffer[i] = (uint8_t) rand();
-
- /* Define a prim length */
- prim_len = GSM_MACBLOCK_LEN;
- }
-
- /* Nothing to allocate / assign */
- if (!prim_len)
- return NULL;
-
msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST);
OSMO_ASSERT(msg != NULL);
prim = l1sched_prim_from_msgb(msg);
prim->data_req = (struct l1sched_prim_chdr) {
- .chan_nr = lchan_desc->chan_nr | lchan->ts->index,
- .link_id = lchan_desc->link_id,
+ .chan_nr = l1sched_lchan_desc[lchan->type].chan_nr | lchan->ts->index,
+ .link_id = l1sched_lchan_desc[lchan->type].link_id,
};
- memcpy(msgb_put(msg, prim_len), &prim_buffer[0], prim_len);
+ ptr = msgb_put(msg, GSM_MACBLOCK_LEN);
+
+ /**
+ * TS 144.006, section 8.4.2.3 "Fill frames"
+ * A fill frame is a UI command frame for SAPI 0, P=0
+ * and with an information field of 0 octet length.
+ */
+ *(ptr++) = 0x01;
+ *(ptr++) = 0x03;
+ *(ptr++) = 0x01;
+
+ /**
+ * TS 144.006, section 5.2 "Frame delimitation and fill bits"
+ * Except for the first octet containing fill bits which shall
+ * be set to the binary value "00101011", each fill bit should
+ * be set to a random value when sent by the network.
+ */
+ *(ptr++) = 0x2b;
+ while (ptr < msg->tail)
+ *(ptr++) = (uint8_t)rand();
return msg;
}