diff options
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h | 2 | ||||
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/prim.h | 3 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_common.c | 49 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchf.c | 45 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchh.c | 119 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_xcch.c | 2 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_prim.c | 83 |
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; } |