2017-05-25 17:50:21 +00:00
|
|
|
/* Scheduler worker functions for OsmoBTS-TRX */
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
|
2017-06-24 00:09:43 +00:00
|
|
|
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
|
2016-01-09 21:17:52 +00:00
|
|
|
*
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <ctype.h>
|
2017-06-24 00:09:43 +00:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <sys/timerfd.h>
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/talloc.h>
|
2018-08-17 12:25:30 +00:00
|
|
|
#include <osmocom/core/timer_compat.h>
|
2016-06-21 11:14:27 +00:00
|
|
|
#include <osmocom/codec/codec.h>
|
2017-12-06 17:08:38 +00:00
|
|
|
#include <osmocom/codec/ecu.h>
|
2016-01-09 21:17:52 +00:00
|
|
|
#include <osmocom/core/bits.h>
|
|
|
|
#include <osmocom/gsm/a5.h>
|
2017-05-19 12:21:00 +00:00
|
|
|
#include <osmocom/coding/gsm0503_coding.h>
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
#include <osmo-bts/gsm_data.h>
|
|
|
|
#include <osmo-bts/logging.h>
|
|
|
|
#include <osmo-bts/rsl.h>
|
2018-02-01 18:24:10 +00:00
|
|
|
#include <osmo-bts/bts.h>
|
2016-01-09 21:17:52 +00:00
|
|
|
#include <osmo-bts/l1sap.h>
|
2016-06-24 09:18:33 +00:00
|
|
|
#include <osmo-bts/msg_utils.h>
|
2016-01-09 22:28:57 +00:00
|
|
|
#include <osmo-bts/scheduler.h>
|
|
|
|
#include <osmo-bts/scheduler_backend.h>
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
#include "l1_if.h"
|
|
|
|
#include "trx_if.h"
|
|
|
|
#include "loops.h"
|
|
|
|
|
|
|
|
extern void *tall_bts_ctx;
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
/* Maximum size of a EGPRS message in bytes */
|
|
|
|
#define EGPRS_0503_MAX_BYTES 155
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:56:27 +00:00
|
|
|
|
|
|
|
/* Compute the bit error rate in 1/10000 units */
|
|
|
|
static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)
|
|
|
|
{
|
|
|
|
if (n_bits_total == 0)
|
|
|
|
return 10000;
|
|
|
|
else
|
|
|
|
return 10000 * n_errors / n_bits_total;
|
|
|
|
}
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
/*
|
|
|
|
* TX on downlink
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* 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,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting IDLE\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting FCCH\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
/* BURST BYPASS */
|
|
|
|
|
|
|
|
return (ubit_t *) _sched_fcch_burst;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted SCH (synchronization channel) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
2016-07-01 07:10:31 +00:00
|
|
|
static ubit_t bits[GSM_BURST_LEN], burst[78];
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t sb_info[4];
|
|
|
|
struct gsm_time t;
|
|
|
|
uint8_t t3p, bsic;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting SCH\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* BURST BYPASS */
|
|
|
|
|
|
|
|
/* create SB info from GSM time and BSIC */
|
|
|
|
gsm_fn2gsmtime(&t, fn);
|
|
|
|
t3p = t.t3 / 10;
|
|
|
|
bsic = l1t->trx->bts->bsic;
|
|
|
|
sb_info[0] =
|
|
|
|
((bsic & 0x3f) << 2) |
|
|
|
|
((t.t1 & 0x600) >> 9);
|
2017-07-04 11:38:44 +00:00
|
|
|
sb_info[1] =
|
2016-01-09 21:17:52 +00:00
|
|
|
((t.t1 & 0x1fe) >> 1);
|
2017-07-04 11:38:44 +00:00
|
|
|
sb_info[2] =
|
2016-01-09 21:17:52 +00:00
|
|
|
((t.t1 & 0x001) << 7) |
|
|
|
|
((t.t2 & 0x1f) << 2) |
|
|
|
|
((t3p & 0x6) >> 1);
|
|
|
|
sb_info[3] =
|
|
|
|
(t3p & 0x1);
|
|
|
|
|
|
|
|
/* encode bursts */
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_sch_encode(burst, sb_info);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* compose burst */
|
|
|
|
memset(bits, 0, 3);
|
|
|
|
memcpy(bits + 3, burst, 39);
|
|
|
|
memcpy(bits + 42, _sched_sch_train, 64);
|
|
|
|
memcpy(bits + 106, burst + 39, 39);
|
|
|
|
memset(bits + 145, 0, 3);
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted data (SACCH/SDCCH) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
2016-01-09 21:39:04 +00:00
|
|
|
uint8_t link_id = trx_chan_desc[chan].link_id;
|
|
|
|
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
2016-01-09 21:17:52 +00:00
|
|
|
struct msgb *msg = NULL; /* make GCC happy */
|
|
|
|
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
2016-07-01 07:10:31 +00:00
|
|
|
static ubit_t bits[GSM_BURST_LEN];
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* send burst, if we already got a frame */
|
|
|
|
if (bid > 0) {
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
2016-01-09 21:39:04 +00:00
|
|
|
/* send clock information to loops process */
|
|
|
|
if (L1SAP_IS_LINK_SACCH(link_id))
|
|
|
|
trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]);
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
/* get mac block from queue */
|
|
|
|
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
|
|
|
if (msg)
|
|
|
|
goto got_msg;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
no_msg:
|
|
|
|
/* free burst memory */
|
|
|
|
if (*bursts_p) {
|
|
|
|
talloc_free(*bursts_p);
|
|
|
|
*bursts_p = NULL;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
got_msg:
|
|
|
|
/* check validity of message */
|
|
|
|
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "
|
2016-01-09 21:17:52 +00:00
|
|
|
"(len=%d)\n", msgb_l2len(msg));
|
|
|
|
/* free message */
|
|
|
|
msgb_free(msg);
|
|
|
|
goto no_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BURST BYPASS */
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* handle loss detection of SACCH */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
|
|
|
|
/* count and send BFI */
|
2018-07-31 19:16:30 +00:00
|
|
|
if (++(l1ts->chan_state[chan].lost_frames) > 1) {
|
2016-01-09 21:17:52 +00:00
|
|
|
/* TODO: Should we pass old TOA here? Otherwise we risk
|
|
|
|
* unnecessary decreasing TA */
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* Send uplink measurement information to L2 */
|
2016-01-09 21:17:52 +00:00
|
|
|
l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
|
|
|
|
456, 456, -110, 0);
|
2016-07-28 12:46:00 +00:00
|
|
|
/* FIXME: use actual values for BER etc */
|
|
|
|
_sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,
|
|
|
|
-110, 0, 0, 10000,
|
|
|
|
PRES_INFO_INVALID);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 464);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* encode bursts */
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_xcch_encode(*bursts_p, msg->l2h);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* free message */
|
|
|
|
msgb_free(msg);
|
|
|
|
|
|
|
|
send_burst:
|
|
|
|
/* compose burst */
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memset(bits, 0, 3);
|
|
|
|
memcpy(bits + 3, burst, 58);
|
|
|
|
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
|
|
|
memcpy(bits + 87, burst + 58, 58);
|
|
|
|
memset(bits + 145, 0, 3);
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted PDTCH (packet data) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
|
|
|
struct msgb *msg = NULL; /* make GCC happy */
|
|
|
|
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;
|
|
|
|
static ubit_t bits[EGPRS_BURST_LEN];
|
|
|
|
int rc = 0;
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* send burst, if we already got a frame */
|
|
|
|
if (bid > 0) {
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get mac block from queue */
|
|
|
|
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
|
|
|
if (msg)
|
|
|
|
goto got_msg;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
no_msg:
|
|
|
|
/* free burst memory */
|
|
|
|
if (*bursts_p) {
|
|
|
|
talloc_free(*bursts_p);
|
|
|
|
*bursts_p = NULL;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
got_msg:
|
|
|
|
/* BURST BYPASS */
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
2016-07-01 07:10:31 +00:00
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx,
|
|
|
|
GSM0503_EGPRS_BURSTS_NBITS);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* encode bursts */
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_pdtch_egprs_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);
|
2016-07-01 07:10:31 +00:00
|
|
|
if (rc < 0)
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* check validity of message */
|
2016-07-01 07:10:31 +00:00
|
|
|
if (rc < 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim invalid length, please FIX! "
|
2016-07-01 07:10:31 +00:00
|
|
|
"(len=%ld)\n", msg->tail - msg->l2h);
|
2016-01-09 21:17:52 +00:00
|
|
|
/* free message */
|
|
|
|
msgb_free(msg);
|
|
|
|
goto no_msg;
|
2016-07-01 07:10:31 +00:00
|
|
|
} else if (rc == GSM0503_EGPRS_BURSTS_NBITS) {
|
|
|
|
*burst_type = TRX_BURST_8PSK;
|
|
|
|
} else {
|
|
|
|
*burst_type = TRX_BURST_GMSK;
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free message */
|
|
|
|
msgb_free(msg);
|
|
|
|
|
|
|
|
send_burst:
|
|
|
|
/* compose burst */
|
2016-07-01 07:10:31 +00:00
|
|
|
if (*burst_type == TRX_BURST_8PSK) {
|
|
|
|
burst = *bursts_p + bid * 348;
|
|
|
|
memset(bits, 1, 9);
|
|
|
|
memcpy(bits + 9, burst, 174);
|
|
|
|
memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
|
|
|
|
memcpy(bits + 261, burst + 174, 174);
|
|
|
|
memset(bits + 435, 1, 9);
|
|
|
|
|
|
|
|
if (nbits)
|
|
|
|
*nbits = EGPRS_BURST_LEN;
|
|
|
|
} else {
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memset(bits, 0, 3);
|
|
|
|
memcpy(bits + 3, burst, 58);
|
|
|
|
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
|
|
|
memcpy(bits + 87, burst + 58, 58);
|
|
|
|
memset(bits + 145, 0, 3);
|
|
|
|
|
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
}
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2017-05-26 09:25:49 +00:00
|
|
|
/* determine if the FN is transmitting a CMR (1) or not (0) */
|
|
|
|
static inline int fn_is_codec_mode_request(uint32_t fn)
|
|
|
|
{
|
|
|
|
return (((fn + 4) % 26) >> 2) & 1;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* common section for generation of TCH bursts (TCH/H and TCH/F) */
|
2016-01-09 21:17:52 +00:00
|
|
|
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,
|
2017-05-26 09:25:49 +00:00
|
|
|
struct msgb **_msg_facch)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
uint8_t rsl_cmode = chan_state->rsl_cmode;
|
|
|
|
uint8_t tch_mode = chan_state->tch_mode;
|
|
|
|
struct osmo_phsap_prim *l1sap;
|
|
|
|
|
|
|
|
/* handle loss detection of received TCH frames */
|
|
|
|
if (rsl_cmode == RSL_CMOD_SPD_SPEECH
|
2018-07-31 19:16:30 +00:00
|
|
|
&& ++(chan_state->lost_frames) > 5) {
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t tch_data[GSM_FR_BYTES];
|
|
|
|
int len;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"Missing TCH bursts detected, sending BFI\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* indicate bad frame */
|
|
|
|
switch (tch_mode) {
|
|
|
|
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);
|
|
|
|
len = 15;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
memset(tch_data, 0, GSM_FR_BYTES);
|
|
|
|
len = GSM_FR_BYTES;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
|
|
|
if (chan != TRXC_TCHF)
|
|
|
|
goto inval_mode1;
|
|
|
|
memset(tch_data, 0, GSM_EFR_BYTES);
|
|
|
|
len = GSM_EFR_BYTES;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
2016-06-21 11:14:27 +00:00
|
|
|
len = osmo_amr_rtp_enc(tch_data,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec[chan_state->dl_cmr],
|
2016-06-21 11:14:27 +00:00
|
|
|
chan_state->codec[chan_state->dl_ft], AMR_BAD);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (len < 2)
|
|
|
|
break;
|
|
|
|
memset(tch_data + 2, 0, len - 2);
|
2016-06-24 09:18:33 +00:00
|
|
|
_sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len);
|
2016-01-09 21:17:52 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inval_mode1:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
if (len)
|
2016-06-24 09:18:33 +00:00
|
|
|
_sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* get frame and unlink from queue */
|
|
|
|
msg1 = _sched_dequeue_prim(l1t, tn, fn, chan);
|
|
|
|
msg2 = _sched_dequeue_prim(l1t, tn, fn, chan);
|
|
|
|
if (msg1) {
|
|
|
|
l1sap = msgb_l1sap_prim(msg1);
|
|
|
|
if (l1sap->oph.primitive == PRIM_TCH) {
|
|
|
|
msg_tch = msg1;
|
|
|
|
if (msg2) {
|
|
|
|
l1sap = msgb_l1sap_prim(msg2);
|
|
|
|
if (l1sap->oph.primitive == PRIM_TCH) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"TCH twice, please FIX!\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
msgb_free(msg2);
|
|
|
|
} else
|
|
|
|
msg_facch = msg2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
msg_facch = msg1;
|
|
|
|
if (msg2) {
|
|
|
|
l1sap = msgb_l1sap_prim(msg2);
|
|
|
|
if (l1sap->oph.primitive != PRIM_TCH) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"FACCH twice, please FIX!\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
msgb_free(msg2);
|
|
|
|
} else
|
|
|
|
msg_tch = msg2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (msg2) {
|
|
|
|
l1sap = msgb_l1sap_prim(msg2);
|
|
|
|
if (l1sap->oph.primitive == PRIM_TCH)
|
|
|
|
msg_tch = msg2;
|
|
|
|
else
|
|
|
|
msg_facch = msg2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check validity of message */
|
|
|
|
if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "
|
2016-01-09 21:17:52 +00:00
|
|
|
"(len=%d)\n", msgb_l2len(msg_facch));
|
|
|
|
/* free message */
|
|
|
|
msgb_free(msg_facch);
|
|
|
|
msg_facch = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check validity of message, get AMR ft and cmr */
|
|
|
|
if (!msg_facch && msg_tch) {
|
|
|
|
int len;
|
2016-06-21 11:14:27 +00:00
|
|
|
uint8_t cmr_codec;
|
2016-01-09 21:17:52 +00:00
|
|
|
int cmr, ft, i;
|
2016-06-21 11:14:27 +00:00
|
|
|
enum osmo_amr_type ft_codec;
|
|
|
|
enum osmo_amr_quality bfi;
|
|
|
|
int8_t sti, cmi;
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, "
|
2017-12-02 15:29:15 +00:00
|
|
|
"because we are not in speech mode\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (tch_mode) {
|
|
|
|
case GSM48_CMODE_SPEECH_V1: /* FR / HR */
|
2017-06-24 14:50:00 +00:00
|
|
|
if (chan != TRXC_TCHF) /* HR */
|
2016-01-09 21:17:52 +00:00
|
|
|
len = 15;
|
2017-06-24 14:50:00 +00:00
|
|
|
else
|
|
|
|
len = GSM_FR_BYTES;
|
2016-01-09 21:17:52 +00:00
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
|
|
|
if (chan != TRXC_TCHF)
|
|
|
|
goto inval_mode2;
|
|
|
|
len = GSM_EFR_BYTES;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
2016-06-21 11:14:27 +00:00
|
|
|
len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch),
|
|
|
|
&cmr_codec, &cmi, &ft_codec,
|
|
|
|
&bfi, &sti);
|
2016-01-09 21:17:52 +00:00
|
|
|
cmr = -1;
|
|
|
|
ft = -1;
|
|
|
|
for (i = 0; i < chan_state->codecs; i++) {
|
|
|
|
if (chan_state->codec[i] == cmr_codec)
|
|
|
|
cmr = i;
|
|
|
|
if (chan_state->codec[i] == ft_codec)
|
|
|
|
ft = i;
|
|
|
|
}
|
|
|
|
if (cmr >= 0) { /* new request */
|
|
|
|
chan_state->dl_cmr = cmr;
|
|
|
|
/* disable AMR loop */
|
|
|
|
trx_loop_amr_set(chan_state, 0);
|
|
|
|
} else {
|
|
|
|
/* enable AMR loop */
|
|
|
|
trx_loop_amr_set(chan_state, 1);
|
|
|
|
}
|
|
|
|
if (ft < 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"Codec (FT = %d) of RTP frame not in list\n", ft_codec);
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
2017-05-26 09:25:49 +00:00
|
|
|
if (fn_is_codec_mode_request(fn) && chan_state->dl_ft != ft) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Codec (FT = %d) "
|
2017-12-02 15:29:15 +00:00
|
|
|
" of RTP cannot be changed now, but in next frame\n", ft_codec);
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
|
|
|
chan_state->dl_ft = ft;
|
2016-06-21 11:14:27 +00:00
|
|
|
if (bfi == AMR_BAD) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"Transmitting 'bad AMR frame'\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inval_mode2:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
|
|
|
if (len < 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send invalid AMR payload\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto free_bad_msg;
|
|
|
|
}
|
|
|
|
if (msgb_l2len(msg_tch) != len) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send payload with "
|
2017-06-04 11:26:00 +00:00
|
|
|
"invalid length! (expecting %d, received %d)\n",
|
2016-01-09 21:17:52 +00:00
|
|
|
len, msgb_l2len(msg_tch));
|
|
|
|
free_bad_msg:
|
|
|
|
/* free message */
|
|
|
|
msgb_free(msg_tch);
|
|
|
|
msg_tch = NULL;
|
|
|
|
goto send_frame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
send_frame:
|
|
|
|
*_msg_tch = msg_tch;
|
|
|
|
*_msg_facch = msg_facch;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
uint8_t tch_mode = chan_state->tch_mode;
|
|
|
|
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
2016-07-01 07:10:31 +00:00
|
|
|
static ubit_t bits[GSM_BURST_LEN];
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* send burst, if we already got a frame */
|
|
|
|
if (bid > 0) {
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
2017-05-26 09:25:49 +00:00
|
|
|
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* BURST BYPASS */
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already,
|
2016-01-09 21:17:52 +00:00
|
|
|
* otherwise shift buffer by 4 bursts for interleaving */
|
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 928);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
memcpy(*bursts_p, *bursts_p + 464, 464);
|
|
|
|
memset(*bursts_p + 464, 0, 464);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no message at all */
|
|
|
|
if (!msg_tch && !msg_facch) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* encode bursts (prioritize FACCH) */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (msg_facch)
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),
|
2016-01-09 21:17:52 +00:00
|
|
|
1);
|
|
|
|
else if (tch_mode == GSM48_CMODE_SPEECH_AMR)
|
|
|
|
/* the first FN 4,13,21 defines that CMI is included in frame,
|
|
|
|
* the first FN 0,8,17 defines that CMR is included in frame.
|
|
|
|
*/
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,
|
2017-05-26 09:25:49 +00:00
|
|
|
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec, chan_state->codecs,
|
|
|
|
chan_state->dl_ft,
|
|
|
|
chan_state->dl_cmr);
|
|
|
|
else
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* free message */
|
|
|
|
if (msg_tch)
|
|
|
|
msgb_free(msg_tch);
|
|
|
|
if (msg_facch)
|
|
|
|
msgb_free(msg_facch);
|
|
|
|
|
|
|
|
send_burst:
|
|
|
|
/* compose burst */
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memset(bits, 0, 3);
|
|
|
|
memcpy(bits + 3, burst, 58);
|
|
|
|
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
|
|
|
memcpy(bits + 87, burst + 58, 58);
|
|
|
|
memset(bits + 145, 0, 3);
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
|
2016-01-09 21:17:52 +00:00
|
|
|
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
uint8_t tch_mode = chan_state->tch_mode;
|
|
|
|
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
2016-07-01 07:10:31 +00:00
|
|
|
static ubit_t bits[GSM_BURST_LEN];
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* send burst, if we already got a frame */
|
|
|
|
if (bid > 0) {
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get TCH and/or FACCH */
|
2017-05-26 09:25:49 +00:00
|
|
|
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* check for FACCH alignment */
|
|
|
|
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
|
2017-12-02 15:29:15 +00:00
|
|
|
"even frames, please fix RTS!\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
msgb_free(msg_facch);
|
|
|
|
msg_facch = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BURST BYPASS */
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already,
|
2016-01-09 21:17:52 +00:00
|
|
|
* otherwise shift buffer by 2 bursts for interleaving */
|
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 696);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
memcpy(*bursts_p, *bursts_p + 232, 232);
|
|
|
|
if (chan_state->dl_ongoing_facch) {
|
|
|
|
memcpy(*bursts_p + 232, *bursts_p + 464, 232);
|
|
|
|
memset(*bursts_p + 464, 0, 232);
|
|
|
|
} else {
|
|
|
|
memset(*bursts_p + 232, 0, 232);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no message at all */
|
|
|
|
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
|
2016-01-09 21:17:52 +00:00
|
|
|
goto send_burst;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* encode bursts (prioritize FACCH) */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (msg_facch) {
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch));
|
2017-05-25 17:50:21 +00:00
|
|
|
chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */
|
|
|
|
} else if (chan_state->dl_ongoing_facch) /* second of two TCH frames */
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */
|
|
|
|
else if (tch_mode == GSM48_CMODE_SPEECH_AMR)
|
|
|
|
/* the first FN 4,13,21 or 5,14,22 defines that CMI is included
|
|
|
|
* in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
|
|
|
|
* included in frame. */
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
|
2017-05-26 09:25:49 +00:00
|
|
|
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec, chan_state->codecs,
|
|
|
|
chan_state->dl_ft,
|
|
|
|
chan_state->dl_cmr);
|
|
|
|
else
|
2017-05-19 12:21:00 +00:00
|
|
|
gsm0503_tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch));
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* free message */
|
|
|
|
if (msg_tch)
|
|
|
|
msgb_free(msg_tch);
|
|
|
|
if (msg_facch)
|
|
|
|
msgb_free(msg_facch);
|
|
|
|
|
|
|
|
send_burst:
|
|
|
|
/* compose burst */
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memset(bits, 0, 3);
|
|
|
|
memcpy(bits + 3, burst, 58);
|
|
|
|
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
|
|
|
memcpy(bits + 87, burst + 58, 58);
|
|
|
|
memset(bits + 145, 0, 3);
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits)
|
|
|
|
*nbits = GSM_BURST_LEN;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RX on uplink (indication to upper layer)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
|
2018-02-19 13:21:36 +00:00
|
|
|
int8_t rssi, int16_t toa256)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
uint8_t chan_nr;
|
|
|
|
struct osmo_phsap_prim l1sap;
|
2018-02-26 10:57:49 +00:00
|
|
|
int n_errors, n_bits_total;
|
2018-01-04 10:48:05 +00:00
|
|
|
bool is_11bit = true;
|
|
|
|
uint16_t ra11;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t ra;
|
2018-01-04 10:48:05 +00:00
|
|
|
int rc = 1;
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
|
|
|
|
2018-02-19 13:21:36 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received RACH toa=%d\n", toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2018-01-04 10:48:05 +00:00
|
|
|
if (chan == TRXC_RACH) /* Attempt to decode as extended (11-bit) RACH first */
|
|
|
|
rc = gsm0503_rach_ext_decode_ber(&ra11, bits + 8 + 41,
|
|
|
|
l1t->trx->bts->bsic, &n_errors, &n_bits_total);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (rc) {
|
2018-01-04 10:48:05 +00:00
|
|
|
/* Indicate non-extended RACH */
|
|
|
|
is_11bit = false;
|
|
|
|
|
|
|
|
/* Fall-back to the normal RACH decoding */
|
|
|
|
rc = gsm0503_rach_decode_ber(&ra, bits + 8 + 41,
|
|
|
|
l1t->trx->bts->bsic, &n_errors, &n_bits_total);
|
|
|
|
if (rc) {
|
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received bad AB frame\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* compose primitive */
|
|
|
|
/* generate prim */
|
|
|
|
memset(&l1sap, 0, sizeof(l1sap));
|
|
|
|
osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION,
|
|
|
|
NULL);
|
|
|
|
l1sap.u.rach_ind.chan_nr = chan_nr;
|
2018-02-19 13:21:36 +00:00
|
|
|
l1sap.u.rach_ind.acc_delay = (toa256 >= 0) ? toa256/256 : 0;
|
2016-01-09 21:17:52 +00:00
|
|
|
l1sap.u.rach_ind.fn = fn;
|
2018-02-26 10:57:49 +00:00
|
|
|
l1sap.u.rach_ind.rssi = rssi;
|
|
|
|
l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);
|
2018-02-19 13:21:36 +00:00
|
|
|
l1sap.u.rach_ind.acc_delay_256bits = toa256;
|
2016-11-08 06:26:08 +00:00
|
|
|
|
2018-01-04 10:48:05 +00:00
|
|
|
if (is_11bit) {
|
|
|
|
l1sap.u.rach_ind.is_11bit = 1;
|
|
|
|
l1sap.u.rach_ind.ra = ra11;
|
|
|
|
l1sap.u.rach_ind.burst_type = BSIC2BCC(l1t->trx->bts->bsic);
|
|
|
|
switch (l1sap.u.rach_ind.burst_type) {
|
|
|
|
case GSM_L1_BURST_TYPE_ACCESS_0:
|
|
|
|
case GSM_L1_BURST_TYPE_ACCESS_1:
|
|
|
|
case GSM_L1_BURST_TYPE_ACCESS_2:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,
|
|
|
|
"Received RACH frame with unexpected TSC %u, "
|
|
|
|
"forcing default %u\n", l1sap.u.rach_ind.burst_type,
|
|
|
|
GSM_L1_BURST_TYPE_ACCESS_0);
|
|
|
|
l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
l1sap.u.rach_ind.is_11bit = 0;
|
|
|
|
l1sap.u.rach_ind.ra = ra;
|
|
|
|
l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;
|
|
|
|
}
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
/* forward primitive */
|
|
|
|
l1sap_up(l1t->trx, &l1sap);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */
|
2016-01-09 21:17:52 +00:00
|
|
|
int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
|
2018-02-19 13:21:36 +00:00
|
|
|
int8_t rssi, int16_t toa256)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
|
|
|
uint32_t *first_fn = &chan_state->ul_first_fn;
|
|
|
|
uint8_t *mask = &chan_state->ul_mask;
|
|
|
|
float *rssi_sum = &chan_state->rssi_sum;
|
|
|
|
uint8_t *rssi_num = &chan_state->rssi_num;
|
2018-02-19 13:21:36 +00:00
|
|
|
int32_t *toa256_sum = &chan_state->toa256_sum;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t *toa_num = &chan_state->toa_num;
|
|
|
|
uint8_t l2[GSM_MACBLOCK_LEN], l2_len;
|
|
|
|
int n_errors, n_bits_total;
|
2017-05-25 17:56:27 +00:00
|
|
|
uint16_t ber10k;
|
2016-01-09 21:17:52 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* handle RACH, if handover RACH detection is turned on */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (chan_state->ho_rach_detect == 1)
|
2018-02-19 13:21:36 +00:00
|
|
|
return rx_rach_fn(l1t, tn, fn, chan, bid, bits, GSM_BURST_LEN, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received Data, bid=%u\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 464);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear burst & store frame number of first burst */
|
|
|
|
if (bid == 0) {
|
|
|
|
memset(*bursts_p, 0, 464);
|
|
|
|
*mask = 0x0;
|
|
|
|
*first_fn = fn;
|
|
|
|
*rssi_sum = 0;
|
|
|
|
*rssi_num = 0;
|
2018-02-19 13:21:36 +00:00
|
|
|
*toa256_sum = 0;
|
2016-01-09 21:17:52 +00:00
|
|
|
*toa_num = 0;
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* update mask + RSSI */
|
2016-01-09 21:17:52 +00:00
|
|
|
*mask |= (1 << bid);
|
|
|
|
*rssi_sum += rssi;
|
|
|
|
(*rssi_num)++;
|
2018-02-19 13:21:36 +00:00
|
|
|
*toa256_sum += toa256;
|
2016-01-09 21:17:52 +00:00
|
|
|
(*toa_num)++;
|
|
|
|
|
|
|
|
/* copy burst to buffer of 4 bursts */
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memcpy(burst, bits + 3, 58);
|
|
|
|
memcpy(burst + 58, bits + 87, 58);
|
|
|
|
|
|
|
|
/* send burst information to loops process */
|
|
|
|
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
|
|
|
|
trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | tn,
|
2018-02-19 13:21:36 +00:00
|
|
|
chan_state, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* wait until complete set of bursts */
|
|
|
|
if (bid != 3)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check for complete set of bursts */
|
|
|
|
if ((*mask & 0xf) != 0xf) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received incomplete data (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
*first_fn, (*first_fn) % l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* we require first burst to have correct FN */
|
|
|
|
if (!(*mask & 0x1)) {
|
|
|
|
*mask = 0x0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*mask = 0x0;
|
|
|
|
|
|
|
|
/* decode */
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (rc) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received bad data (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
*first_fn, (*first_fn) % l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
l2_len = 0;
|
|
|
|
} else
|
|
|
|
l2_len = GSM_MACBLOCK_LEN;
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* Send uplink measurement information to L2 */
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
l1if_process_meas_res(l1t->trx, tn, *first_fn, trx_chan_desc[chan].chan_nr | tn,
|
2018-02-19 13:21:36 +00:00
|
|
|
n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa256_sum / *toa_num);
|
2017-05-25 17:56:27 +00:00
|
|
|
ber10k = compute_ber10k(n_bits_total, n_errors);
|
2016-07-28 12:46:00 +00:00
|
|
|
return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len,
|
|
|
|
*rssi_sum / *rssi_num,
|
2019-01-26 13:02:49 +00:00
|
|
|
*toa256_sum / *toa_num, 0, ber10k,
|
2016-07-28 12:46:00 +00:00
|
|
|
PRES_INFO_UNKNOWN);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/*! \brief a single PDTCH burst was received by the PHY, process it */
|
2016-01-09 21:17:52 +00:00
|
|
|
int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
|
2018-02-19 13:21:36 +00:00
|
|
|
int8_t rssi, int16_t toa256)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
uint32_t *first_fn = &chan_state->ul_first_fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t *mask = &chan_state->ul_mask;
|
|
|
|
float *rssi_sum = &chan_state->rssi_sum;
|
|
|
|
uint8_t *rssi_num = &chan_state->rssi_num;
|
2018-02-19 13:21:36 +00:00
|
|
|
int32_t *toa256_sum = &chan_state->toa256_sum;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t *toa_num = &chan_state->toa_num;
|
2016-07-01 07:10:31 +00:00
|
|
|
uint8_t l2[EGPRS_0503_MAX_BYTES];
|
|
|
|
int n_errors, n_bursts_bits, n_bits_total;
|
2017-05-25 17:56:27 +00:00
|
|
|
uint16_t ber10k;
|
2016-01-09 21:17:52 +00:00
|
|
|
int rc;
|
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received PDTCH bid=%u\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
2016-07-01 07:10:31 +00:00
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx,
|
|
|
|
GSM0503_EGPRS_BURSTS_NBITS);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear burst */
|
|
|
|
if (bid == 0) {
|
2016-07-01 07:10:31 +00:00
|
|
|
memset(*bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS);
|
2016-01-09 21:17:52 +00:00
|
|
|
*mask = 0x0;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
*first_fn = fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
*rssi_sum = 0;
|
|
|
|
*rssi_num = 0;
|
2018-02-19 13:21:36 +00:00
|
|
|
*toa256_sum = 0;
|
2016-01-09 21:17:52 +00:00
|
|
|
*toa_num = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update mask + rssi */
|
|
|
|
*mask |= (1 << bid);
|
|
|
|
*rssi_sum += rssi;
|
|
|
|
(*rssi_num)++;
|
2018-02-19 13:21:36 +00:00
|
|
|
*toa256_sum += toa256;
|
2016-01-09 21:17:52 +00:00
|
|
|
(*toa_num)++;
|
|
|
|
|
|
|
|
/* copy burst to buffer of 4 bursts */
|
2016-07-01 07:10:31 +00:00
|
|
|
if (nbits == EGPRS_BURST_LEN) {
|
|
|
|
burst = *bursts_p + bid * 348;
|
|
|
|
memcpy(burst, bits + 9, 174);
|
|
|
|
memcpy(burst + 174, bits + 261, 174);
|
|
|
|
n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS;
|
|
|
|
} else {
|
|
|
|
burst = *bursts_p + bid * 116;
|
|
|
|
memcpy(burst, bits + 3, 58);
|
|
|
|
memcpy(burst + 58, bits + 87, 58);
|
|
|
|
n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;
|
|
|
|
}
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* wait until complete set of bursts */
|
|
|
|
if (bid != 3)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check for complete set of bursts */
|
|
|
|
if ((*mask & 0xf) != 0xf) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received incomplete frame (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
*mask = 0x0;
|
|
|
|
|
2016-07-01 07:10:31 +00:00
|
|
|
/*
|
|
|
|
* Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we
|
|
|
|
* do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS,
|
|
|
|
* then we incur decoding overhead of 31 bits on the Type 3 EGPRS
|
|
|
|
* header, which is tolerable.
|
|
|
|
*/
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_pdtch_egprs_decode(l2, *bursts_p, n_bursts_bits,
|
2016-07-01 07:10:31 +00:00
|
|
|
NULL, &n_errors, &n_bits_total);
|
|
|
|
|
|
|
|
if ((nbits == GSM_BURST_LEN) && (rc < 0)) {
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_pdtch_decode(l2, *bursts_p, NULL,
|
2016-07-01 07:10:31 +00:00
|
|
|
&n_errors, &n_bits_total);
|
|
|
|
}
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* Send uplink measurement information to L2 */
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
l1if_process_meas_res(l1t->trx, tn, *first_fn, trx_chan_desc[chan].chan_nr | tn,
|
2018-02-19 13:21:36 +00:00
|
|
|
n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa256_sum / *toa_num);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
if (rc <= 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received bad PDTCH (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-25 17:56:27 +00:00
|
|
|
ber10k = compute_ber10k(n_bits_total, n_errors);
|
2019-02-15 14:27:44 +00:00
|
|
|
return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan,
|
2019-01-26 13:02:49 +00:00
|
|
|
l2, rc, *rssi_sum / *rssi_num, *toa256_sum / *toa_num, 0,
|
2016-07-28 12:46:00 +00:00
|
|
|
ber10k, PRES_INFO_BOTH);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/*! \brief a single TCH/F burst was received by the PHY, process it */
|
2016-01-09 21:17:52 +00:00
|
|
|
int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
|
2018-02-19 13:21:36 +00:00
|
|
|
int8_t rssi, int16_t toa256)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
uint32_t *first_fn = &chan_state->ul_first_fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t *mask = &chan_state->ul_mask;
|
|
|
|
uint8_t rsl_cmode = chan_state->rsl_cmode;
|
|
|
|
uint8_t tch_mode = chan_state->tch_mode;
|
|
|
|
uint8_t tch_data[128]; /* just to be safe */
|
|
|
|
int rc, amr = 0;
|
|
|
|
int n_errors, n_bits_total;
|
2017-12-06 17:08:38 +00:00
|
|
|
bool bfi_flag = false;
|
2016-06-24 09:18:33 +00:00
|
|
|
struct gsm_lchan *lchan =
|
|
|
|
get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | tn);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* handle rach, if handover rach detection is turned on */
|
|
|
|
if (chan_state->ho_rach_detect == 1)
|
2018-02-19 13:21:36 +00:00
|
|
|
return rx_rach_fn(l1t, tn, fn, chan, bid, bits, GSM_BURST_LEN, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received TCH/F, bid=%u\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 928);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear burst */
|
|
|
|
if (bid == 0) {
|
|
|
|
memset(*bursts_p + 464, 0, 464);
|
|
|
|
*mask = 0x0;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
*first_fn = fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* update mask */
|
|
|
|
*mask |= (1 << bid);
|
|
|
|
|
|
|
|
/* copy burst to end of buffer of 8 bursts */
|
|
|
|
burst = *bursts_p + bid * 116 + 464;
|
|
|
|
memcpy(burst, bits + 3, 58);
|
|
|
|
memcpy(burst + 58, bits + 87, 58);
|
|
|
|
|
|
|
|
/* wait until complete set of bursts */
|
|
|
|
if (bid != 3)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check for complete set of bursts */
|
|
|
|
if ((*mask & 0xf) != 0xf) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received incomplete frame (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
*mask = 0x0;
|
|
|
|
|
|
|
|
/* decode
|
|
|
|
* also shift buffer by 4 bursts for interleaving */
|
|
|
|
switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
|
|
|
|
: tch_mode) {
|
|
|
|
case GSM48_CMODE_SPEECH_V1: /* FR */
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total);
|
2017-11-05 17:56:41 +00:00
|
|
|
if (rc >= 0)
|
|
|
|
lchan_set_marker(osmo_fr_check_sid(tch_data, rc), lchan); /* DTXu */
|
2016-01-09 21:17:52 +00:00
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total);
|
2016-01-09 21:17:52 +00:00
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
|
|
|
/* the first FN 0,8,17 defines that CMI is included in frame,
|
|
|
|
* the first FN 4,13,21 defines that CMR is included in frame.
|
|
|
|
* NOTE: A frame ends 7 FN after start.
|
|
|
|
*/
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_tch_afs_decode(tch_data + 2, *bursts_p,
|
2016-01-09 21:17:52 +00:00
|
|
|
(((fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,
|
|
|
|
chan_state->codecs, &chan_state->ul_ft,
|
|
|
|
&chan_state->ul_cmr, &n_errors, &n_bits_total);
|
|
|
|
if (rc)
|
|
|
|
trx_loop_amr_input(l1t,
|
|
|
|
trx_chan_desc[chan].chan_nr | tn, chan_state,
|
|
|
|
(float)n_errors/(float)n_bits_total);
|
|
|
|
amr = 2; /* we store tch_data + 2 header bytes */
|
|
|
|
/* only good speech frames get rtp header */
|
|
|
|
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
|
2016-06-21 11:14:27 +00:00
|
|
|
rc = osmo_amr_rtp_enc(tch_data,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec[chan_state->ul_cmr],
|
2016-06-21 11:14:27 +00:00
|
|
|
chan_state->codec[chan_state->ul_ft], AMR_GOOD);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode %u invalid, please fix!\n",
|
2016-01-09 21:17:52 +00:00
|
|
|
tch_mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
memcpy(*bursts_p, *bursts_p + 464, 464);
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* Send uplink measurement information to L2 */
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
l1if_process_meas_res(l1t->trx, tn, *first_fn, trx_chan_desc[chan].chan_nr|tn,
|
2018-02-19 13:21:36 +00:00
|
|
|
n_errors, n_bits_total, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* Check if the frame is bad */
|
|
|
|
if (rc < 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received bad data (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2017-12-06 17:08:38 +00:00
|
|
|
bfi_flag = true;
|
2016-01-09 21:17:52 +00:00
|
|
|
goto bfi;
|
|
|
|
}
|
|
|
|
if (rc < 4) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received bad data (%u/%u) "
|
2017-12-02 15:29:15 +00:00
|
|
|
"with invalid codec mode %d\n", fn % l1ts->mf_period, l1ts->mf_period, rc);
|
2017-12-06 17:08:38 +00:00
|
|
|
bfi_flag = true;
|
2016-01-09 21:17:52 +00:00
|
|
|
goto bfi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FACCH */
|
|
|
|
if (rc == GSM_MACBLOCK_LEN) {
|
2017-05-25 17:56:27 +00:00
|
|
|
uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
|
2016-01-09 21:17:52 +00:00
|
|
|
_sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
|
2019-01-26 13:02:49 +00:00
|
|
|
tch_data + amr, GSM_MACBLOCK_LEN, rssi, toa256, 0,
|
2016-07-28 12:46:00 +00:00
|
|
|
ber10k, PRES_INFO_UNKNOWN);
|
2016-01-09 21:17:52 +00:00
|
|
|
bfi:
|
|
|
|
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
|
|
|
|
/* indicate bad frame */
|
|
|
|
switch (tch_mode) {
|
|
|
|
case GSM48_CMODE_SPEECH_V1: /* FR */
|
2018-07-20 14:38:12 +00:00
|
|
|
if (lchan->tch.dtx.ul_sid) {
|
|
|
|
/* DTXu: pause in progress. Push empty payload to upper layers */
|
|
|
|
rc = 0;
|
|
|
|
goto compose_l1sap;
|
|
|
|
}
|
2017-12-06 17:08:38 +00:00
|
|
|
|
|
|
|
/* Perform error concealment if possible */
|
|
|
|
rc = osmo_ecu_fr_conceal(&lchan->ecu_state.fr, tch_data);
|
|
|
|
if (rc) {
|
|
|
|
memset(tch_data, 0, GSM_FR_BYTES);
|
|
|
|
tch_data[0] = 0xd0;
|
|
|
|
}
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
rc = GSM_FR_BYTES;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_EFR: /* EFR */
|
|
|
|
memset(tch_data, 0, GSM_EFR_BYTES);
|
2017-06-24 14:50:00 +00:00
|
|
|
tch_data[0] = 0xc0;
|
2016-01-09 21:17:52 +00:00
|
|
|
rc = GSM_EFR_BYTES;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
2016-06-21 11:14:27 +00:00
|
|
|
rc = osmo_amr_rtp_enc(tch_data,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec[chan_state->dl_cmr],
|
|
|
|
chan_state->codec[chan_state->dl_ft],
|
2016-06-21 11:14:27 +00:00
|
|
|
AMR_BAD);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (rc < 2)
|
|
|
|
break;
|
|
|
|
memset(tch_data + 2, 0, rc - 2);
|
|
|
|
break;
|
|
|
|
default:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"TCH mode %u invalid, please fix!\n", tch_mode);
|
2016-01-09 21:17:52 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
|
|
|
|
return 0;
|
|
|
|
|
2017-12-06 17:08:38 +00:00
|
|
|
/* Reset ECU with a good frame */
|
|
|
|
if (!bfi_flag && tch_mode == GSM48_CMODE_SPEECH_V1)
|
|
|
|
osmo_ecu_fr_reset(&lchan->ecu_state.fr, tch_data);
|
|
|
|
|
2016-01-09 21:17:52 +00:00
|
|
|
/* TCH or BFI */
|
2018-07-20 14:38:12 +00:00
|
|
|
compose_l1sap:
|
2016-01-09 21:17:52 +00:00
|
|
|
return _sched_compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
|
|
|
|
tch_data, rc);
|
|
|
|
}
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/*! \brief a single TCH/H burst was received by the PHY, process it */
|
2016-01-09 21:17:52 +00:00
|
|
|
int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
2016-07-01 07:10:31 +00:00
|
|
|
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
|
2018-02-19 13:21:36 +00:00
|
|
|
int8_t rssi, int16_t toa256)
|
2016-01-09 21:17:52 +00:00
|
|
|
{
|
|
|
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
|
|
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
|
|
|
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
uint32_t *first_fn = &chan_state->ul_first_fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
uint8_t *mask = &chan_state->ul_mask;
|
|
|
|
uint8_t rsl_cmode = chan_state->rsl_cmode;
|
|
|
|
uint8_t tch_mode = chan_state->tch_mode;
|
|
|
|
uint8_t tch_data[128]; /* just to be safe */
|
|
|
|
int rc, amr = 0;
|
|
|
|
int n_errors, n_bits_total;
|
2016-06-24 09:18:33 +00:00
|
|
|
struct gsm_lchan *lchan =
|
|
|
|
get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | tn);
|
2017-05-26 09:34:42 +00:00
|
|
|
/* Note on FN-10: If we are at FN 10, we decoded an even aligned
|
|
|
|
* TCH/FACCH frame, because our burst buffer carries 6 bursts.
|
|
|
|
* Even FN ending at: 10,11,19,20,2,3
|
|
|
|
*/
|
|
|
|
int fn_is_odd = (((fn + 26 - 10) % 26) >> 2) & 1;
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* handle RACH, if handover RACH detection is turned on */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (chan_state->ho_rach_detect == 1)
|
2018-02-19 13:21:36 +00:00
|
|
|
return rx_rach_fn(l1t, tn, fn, chan, bid, bits, GSM_BURST_LEN, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Received TCH/H, bid=%u\n", bid);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* allocate burst memory, if not already */
|
2016-01-09 21:17:52 +00:00
|
|
|
if (!*bursts_p) {
|
|
|
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 696);
|
|
|
|
if (!*bursts_p)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear burst */
|
|
|
|
if (bid == 0) {
|
|
|
|
memset(*bursts_p + 464, 0, 232);
|
|
|
|
*mask = 0x0;
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
*first_fn = fn;
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* update mask */
|
|
|
|
*mask |= (1 << bid);
|
|
|
|
|
|
|
|
/* copy burst to end of buffer of 6 bursts */
|
|
|
|
burst = *bursts_p + bid * 116 + 464;
|
|
|
|
memcpy(burst, bits + 3, 58);
|
|
|
|
memcpy(burst + 58, bits + 87, 58);
|
|
|
|
|
|
|
|
/* wait until complete set of bursts */
|
|
|
|
if (bid != 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check for complete set of bursts */
|
|
|
|
if ((*mask & 0x3) != 0x3) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received incomplete frame (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
*mask = 0x0;
|
|
|
|
|
|
|
|
/* skip second of two TCH frames of FACCH was received */
|
|
|
|
if (chan_state->ul_ongoing_facch) {
|
|
|
|
chan_state->ul_ongoing_facch = 0;
|
|
|
|
memcpy(*bursts_p, *bursts_p + 232, 232);
|
|
|
|
memcpy(*bursts_p + 232, *bursts_p + 464, 232);
|
|
|
|
goto bfi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decode
|
|
|
|
* also shift buffer by 4 bursts for interleaving */
|
|
|
|
switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
|
|
|
|
: tch_mode) {
|
|
|
|
case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
|
|
|
|
/* Note on FN-10: If we are at FN 10, we decoded an even aligned
|
|
|
|
* TCH/FACCH frame, because our burst buffer carries 6 bursts.
|
|
|
|
* Even FN ending at: 10,11,19,20,2,3
|
|
|
|
*/
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_tch_hr_decode(tch_data, *bursts_p,
|
2017-05-26 09:34:42 +00:00
|
|
|
fn_is_odd, &n_errors, &n_bits_total);
|
2017-03-06 13:09:22 +00:00
|
|
|
if (rc) /* DTXu */
|
|
|
|
lchan_set_marker(osmo_hr_check_sid(tch_data, rc), lchan);
|
2016-01-09 21:17:52 +00:00
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
|
|
|
/* the first FN 0,8,17 or 1,9,18 defines that CMI is included
|
|
|
|
* in frame, the first FN 4,13,21 or 5,14,22 defines that CMR
|
|
|
|
* is included in frame.
|
|
|
|
*/
|
2017-05-19 12:21:00 +00:00
|
|
|
rc = gsm0503_tch_ahs_decode(tch_data + 2, *bursts_p,
|
2017-05-26 09:34:42 +00:00
|
|
|
fn_is_odd, fn_is_odd, chan_state->codec,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codecs, &chan_state->ul_ft,
|
|
|
|
&chan_state->ul_cmr, &n_errors, &n_bits_total);
|
|
|
|
if (rc)
|
|
|
|
trx_loop_amr_input(l1t,
|
|
|
|
trx_chan_desc[chan].chan_nr | tn, chan_state,
|
|
|
|
(float)n_errors/(float)n_bits_total);
|
|
|
|
amr = 2; /* we store tch_data + 2 two */
|
|
|
|
/* only good speech frames get rtp header */
|
|
|
|
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
|
2016-06-21 11:14:27 +00:00
|
|
|
rc = osmo_amr_rtp_enc(tch_data,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec[chan_state->ul_cmr],
|
2016-06-21 11:14:27 +00:00
|
|
|
chan_state->codec[chan_state->ul_ft], AMR_GOOD);
|
2016-01-09 21:17:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode %u invalid, please fix!\n",
|
2016-01-09 21:17:52 +00:00
|
|
|
tch_mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
memcpy(*bursts_p, *bursts_p + 232, 232);
|
|
|
|
memcpy(*bursts_p + 232, *bursts_p + 464, 232);
|
|
|
|
|
2017-05-25 17:50:21 +00:00
|
|
|
/* Send uplink measurement information to L2 */
|
osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
The upper layers (L1SAP, the common part of L1) *always* require frame
numbers in the uplink direction to be reported as the frame number of
the *first* burst, not the last burst of a given block.
This is particularly important in the case of passing up measurement
information, as we use this frame number to detect if the measurement
interval for that specific timeslot has just ended (and hence we must
process the measurements and send an uplink measurement report to the
BSC.
Before this patch, the measurement results were reported with the *last*
frame number, which caused the common/measurement.c code never detect
the end of a measurement window.
On TS2, tons of the following log messages were observed:
<0004> measurement.c:199 (bts=0,trx=0,ts=2,ss=0) no space for uplink measurement, num_ul_meas=104
With this patch, it behves as expected: the measurements of 25 blocks
(= 100 bursts) are aggregated, after which point the report is computed
and sent. Subsequently, num_ul_meas is reset to 0 and the cycle
restarts.
Related: OS#2329
Change-Id: I1065ae9c400bb5240a63ab8213aee59aeb9ceeff
2017-12-02 20:34:33 +00:00
|
|
|
l1if_process_meas_res(l1t->trx, tn, *first_fn, trx_chan_desc[chan].chan_nr|tn,
|
2018-02-19 13:21:36 +00:00
|
|
|
n_errors, n_bits_total, rssi, toa256);
|
2016-01-09 21:17:52 +00:00
|
|
|
|
|
|
|
/* Check if the frame is bad */
|
|
|
|
if (rc < 0) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received bad data (%u/%u)\n",
|
2017-12-02 15:29:15 +00:00
|
|
|
fn % l1ts->mf_period, l1ts->mf_period);
|
2016-01-09 21:17:52 +00:00
|
|
|
goto bfi;
|
|
|
|
}
|
|
|
|
if (rc < 4) {
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Received bad data (%u/%u) "
|
2017-12-02 15:29:15 +00:00
|
|
|
"with invalid codec mode %d\n", fn % l1ts->mf_period, l1ts->mf_period, rc);
|
2016-01-09 21:17:52 +00:00
|
|
|
goto bfi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FACCH */
|
|
|
|
if (rc == GSM_MACBLOCK_LEN) {
|
|
|
|
chan_state->ul_ongoing_facch = 1;
|
2017-05-25 17:56:27 +00:00
|
|
|
uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
|
2016-01-09 21:17:52 +00:00
|
|
|
_sched_compose_ph_data_ind(l1t, tn,
|
|
|
|
(fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan,
|
2019-01-26 13:02:49 +00:00
|
|
|
tch_data + amr, GSM_MACBLOCK_LEN, rssi, toa256, 0,
|
2016-07-28 12:46:00 +00:00
|
|
|
ber10k, PRES_INFO_UNKNOWN);
|
2016-01-09 21:17:52 +00:00
|
|
|
bfi:
|
|
|
|
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
|
|
|
|
/* indicate bad frame */
|
|
|
|
switch (tch_mode) {
|
|
|
|
case GSM48_CMODE_SPEECH_V1: /* HR */
|
2018-07-20 14:38:12 +00:00
|
|
|
if (lchan->tch.dtx.ul_sid) {
|
|
|
|
/* DTXu: pause in progress. Push empty payload to upper layers */
|
|
|
|
rc = 0;
|
|
|
|
goto compose_l1sap;
|
|
|
|
}
|
2016-01-09 21:17:52 +00:00
|
|
|
tch_data[0] = 0x70; /* F = 0, FT = 111 */
|
|
|
|
memset(tch_data + 1, 0, 14);
|
|
|
|
rc = 15;
|
|
|
|
break;
|
|
|
|
case GSM48_CMODE_SPEECH_AMR: /* AMR */
|
2016-06-21 11:14:27 +00:00
|
|
|
rc = osmo_amr_rtp_enc(tch_data,
|
2016-01-09 21:17:52 +00:00
|
|
|
chan_state->codec[chan_state->dl_cmr],
|
|
|
|
chan_state->codec[chan_state->dl_ft],
|
2016-06-21 11:14:27 +00:00
|
|
|
AMR_BAD);
|
2016-01-09 21:17:52 +00:00
|
|
|
if (rc < 2)
|
|
|
|
break;
|
|
|
|
memset(tch_data + 2, 0, rc - 2);
|
|
|
|
break;
|
|
|
|
default:
|
2017-12-02 15:56:45 +00:00
|
|
|
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,
|
2017-12-02 15:29:15 +00:00
|
|
|
"TCH mode %u invalid, please fix!\n", tch_mode);
|
2016-01-09 21:17:52 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
|
|
|
|
return 0;
|
|
|
|
|
2018-07-20 14:38:12 +00:00
|
|
|
compose_l1sap:
|
2016-01-09 21:17:52 +00:00
|
|
|
/* TCH or BFI */
|
|
|
|
/* Note on FN 19 or 20: If we received the last burst of a frame,
|
|
|
|
* it actually starts at FN 8 or 9. A burst starting there, overlaps
|
2017-06-04 11:26:00 +00:00
|
|
|
* with the slot 12, so an extra FN must be subtracted to get correct
|
2016-01-09 21:17:52 +00:00
|
|
|
* start of frame.
|
|
|
|
*/
|
|
|
|
return _sched_compose_tch_ind(l1t, tn,
|
|
|
|
(fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME,
|
|
|
|
chan, tch_data, rc);
|
|
|
|
}
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* schedule all frames of all TRX for given FN */
|
|
|
|
static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
|
|
|
{
|
|
|
|
struct gsm_bts_trx *trx;
|
|
|
|
uint8_t tn;
|
|
|
|
const ubit_t *bits;
|
|
|
|
uint8_t gain;
|
2018-02-08 15:42:48 +00:00
|
|
|
uint16_t nbits = 0;
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* send time indication */
|
|
|
|
l1if_mph_time_ind(bts, fn);
|
|
|
|
|
|
|
|
/* process every TRX */
|
|
|
|
llist_for_each_entry(trx, &bts->trx_list, list) {
|
2016-01-09 12:13:37 +00:00
|
|
|
struct phy_instance *pinst = trx_phy_instance(trx);
|
|
|
|
struct phy_link *plink = pinst->phy_link;
|
|
|
|
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
|
|
|
struct l1sched_trx *l1t = &l1h->l1s;
|
|
|
|
|
|
|
|
/* advance frame number, so the transceiver has more
|
|
|
|
* time until it must be transmitted. */
|
|
|
|
fn = (fn + plink->u.osmotrx.clock_advance) % GSM_HYPERFRAME;
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* we don't schedule, if power is off */
|
|
|
|
if (!trx_if_powered(l1h))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* process every TS of TRX */
|
|
|
|
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
|
|
|
|
/* ready-to-send */
|
|
|
|
_sched_rts(l1t, tn,
|
2016-01-09 12:13:37 +00:00
|
|
|
(fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME);
|
2016-01-09 22:15:41 +00:00
|
|
|
/* get burst for FN */
|
2016-07-01 07:10:31 +00:00
|
|
|
bits = _sched_dl_burst(l1t, tn, fn, &nbits);
|
2016-01-09 22:15:41 +00:00
|
|
|
if (!bits) {
|
|
|
|
/* if no bits, send no burst */
|
|
|
|
continue;
|
|
|
|
} else
|
|
|
|
gain = 0;
|
2017-03-06 13:09:22 +00:00
|
|
|
if (nbits)
|
2017-06-24 16:02:42 +00:00
|
|
|
trx_if_send_burst(l1h, tn, fn, gain, bits, nbits);
|
2016-01-09 22:15:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-06-24 00:09:43 +00:00
|
|
|
* TRX frame clock handling
|
|
|
|
*
|
|
|
|
* In a "normal" synchronous PHY layer, we would be polled every time
|
|
|
|
* the PHY needs data for a given frame number. However, the
|
|
|
|
* OpenBTS-inherited TRX protocol works differently: We (L1) must
|
|
|
|
* autonomously send burst data based on our own clock, and every so
|
|
|
|
* often (currently every ~ 216 frames), we get a clock indication from
|
|
|
|
* the TRX.
|
|
|
|
*
|
|
|
|
* We're using a MONOTONIC timerfd interval timer for the 4.615ms frame
|
|
|
|
* intervals, and then compute + send the 8 bursts for that frame.
|
|
|
|
*
|
|
|
|
* Upon receiving a clock indication from the TRX, we compensate
|
|
|
|
* accordingly: If we were transmitting too fast, we're delaying the
|
|
|
|
* next interval timer accordingly. If we were too slow, we immediately
|
|
|
|
* send burst data for the missing frame numbers.
|
2016-01-09 22:15:41 +00:00
|
|
|
*/
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/*! clock state of a given TRX */
|
|
|
|
struct osmo_trx_clock_state {
|
|
|
|
/*! number of FN periods without TRX clock indication */
|
|
|
|
uint32_t fn_without_clock_ind;
|
|
|
|
struct {
|
|
|
|
/*! last FN we processed based on FN period timer */
|
|
|
|
uint32_t fn;
|
|
|
|
/*! time at which we last processed FN */
|
|
|
|
struct timespec tv;
|
|
|
|
} last_fn_timer;
|
|
|
|
struct {
|
|
|
|
/*! last FN we received a clock indication for */
|
|
|
|
uint32_t fn;
|
|
|
|
/*! time at which we received the last clock indication */
|
|
|
|
struct timespec tv;
|
|
|
|
} last_clk_ind;
|
|
|
|
/*! Osmocom FD wrapper for timerfd */
|
|
|
|
struct osmo_fd fn_timer_ofd;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* TODO: This must go and become part of the phy_link */
|
|
|
|
static struct osmo_trx_clock_state g_clk_s = { .fn_timer_ofd.fd = -1 };
|
|
|
|
|
|
|
|
/*! duration of a GSM frame in nano-seconds. (120ms/26) */
|
|
|
|
#define FRAME_DURATION_nS 4615384
|
|
|
|
/*! duration of a GSM frame in micro-seconds (120s/26) */
|
|
|
|
#define FRAME_DURATION_uS (FRAME_DURATION_nS/1000)
|
|
|
|
/*! maximum number of 'missed' frame periods we can tolerate of OS doesn't schedule us*/
|
2016-01-09 22:15:41 +00:00
|
|
|
#define MAX_FN_SKEW 50
|
2017-06-24 00:09:43 +00:00
|
|
|
/*! maximum number of frame periods we can tolerate without TRX Clock Indication*/
|
2016-01-09 22:15:41 +00:00
|
|
|
#define TRX_LOSS_FRAMES 400
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/*! compute the number of micro-seconds difference elapsed between \a last and \a now */
|
2018-08-17 12:25:30 +00:00
|
|
|
static inline int64_t compute_elapsed_us(const struct timespec *last, const struct timespec *now)
|
2017-06-24 00:09:43 +00:00
|
|
|
{
|
2018-08-17 12:25:30 +00:00
|
|
|
struct timespec elapsed;
|
2017-06-24 00:09:43 +00:00
|
|
|
|
2018-08-17 12:25:30 +00:00
|
|
|
timespecsub(now, last, &elapsed);
|
|
|
|
return (int64_t)(elapsed.tv_sec * 1000000) + (elapsed.tv_nsec / 1000);
|
2017-06-24 00:09:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*! compute the number of frame number intervals elapsed between \a last and \a now */
|
|
|
|
static inline int compute_elapsed_fn(const uint32_t last, const uint32_t now)
|
|
|
|
{
|
|
|
|
int elapsed_fn = (now + GSM_HYPERFRAME - last) % GSM_HYPERFRAME;
|
|
|
|
if (elapsed_fn >= 135774)
|
|
|
|
elapsed_fn -= GSM_HYPERFRAME;
|
|
|
|
return elapsed_fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! normalise given 'struct timespec', i.e. carry nanoseconds into seconds */
|
|
|
|
static inline void normalize_timespec(struct timespec *ts)
|
|
|
|
{
|
|
|
|
ts->tv_sec += ts->tv_nsec / 1000000000;
|
|
|
|
ts->tv_nsec = ts->tv_nsec % 1000000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Increment a GSM frame number modulo GSM_HYPERFRAME */
|
|
|
|
#define INCREMENT_FN(fn) (fn) = (((fn) + 1) % GSM_HYPERFRAME)
|
|
|
|
|
2016-01-09 22:15:41 +00:00
|
|
|
extern int quit;
|
2017-06-24 00:09:43 +00:00
|
|
|
|
|
|
|
/*! this is the timerfd-callback firing for every FN to be processed */
|
|
|
|
static int trx_fn_timer_cb(struct osmo_fd *ofd, unsigned int what)
|
2016-01-09 22:15:41 +00:00
|
|
|
{
|
2017-06-24 00:09:43 +00:00
|
|
|
struct gsm_bts *bts = ofd->data;
|
|
|
|
struct osmo_trx_clock_state *tcs = &g_clk_s;
|
|
|
|
struct timespec tv_now;
|
|
|
|
uint64_t expire_count;
|
2018-08-17 12:25:30 +00:00
|
|
|
int64_t elapsed_us, error_us;
|
2017-06-24 00:09:43 +00:00
|
|
|
int rc, i;
|
|
|
|
|
|
|
|
if (!(what & BSC_FD_READ))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* read from timerfd: number of expirations of periodic timer */
|
|
|
|
rc = read(ofd->fd, (void *) &expire_count, sizeof(expire_count));
|
|
|
|
if (rc < 0 && errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
OSMO_ASSERT(rc == sizeof(expire_count));
|
|
|
|
|
|
|
|
if (expire_count > 1) {
|
|
|
|
LOGP(DL1C, LOGL_NOTICE, "FN timer expire_count=%"PRIu64": We missed %"PRIu64" timers\n",
|
|
|
|
expire_count, expire_count-1);
|
|
|
|
}
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* check if transceiver is still alive */
|
2017-06-24 00:09:43 +00:00
|
|
|
if (tcs->fn_without_clock_ind++ == TRX_LOSS_FRAMES) {
|
2016-01-09 22:15:41 +00:00
|
|
|
LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n");
|
2017-07-04 11:49:18 +00:00
|
|
|
goto no_clock;
|
2016-01-09 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/* compute actual elapsed time and resulting OS scheduling error */
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tv_now);
|
|
|
|
elapsed_us = compute_elapsed_us(&tcs->last_fn_timer.tv, &tv_now);
|
|
|
|
error_us = elapsed_us - FRAME_DURATION_uS;
|
|
|
|
#ifdef DEBUG_CLOCK
|
2018-08-17 12:25:30 +00:00
|
|
|
printf("%s(): %09ld, elapsed_us=%05" PRId64 ", error_us=%-d: fn=%d\n", __func__,
|
2017-06-24 00:09:43 +00:00
|
|
|
tv_now.tv_nsec, elapsed_us, error_us, tcs->last_fn_timer.fn+1);
|
|
|
|
#endif
|
|
|
|
tcs->last_fn_timer.tv = tv_now;
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* if someone played with clock, or if the process stalled */
|
2017-06-24 00:09:43 +00:00
|
|
|
if (elapsed_us > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed_us < 0) {
|
2018-08-17 12:25:30 +00:00
|
|
|
LOGP(DL1C, LOGL_ERROR, "PC clock skew: elapsed_us=%" PRId64 ", error_us=%" PRId64 "\n",
|
2017-06-24 00:09:43 +00:00
|
|
|
elapsed_us, error_us);
|
2016-01-09 22:15:41 +00:00
|
|
|
goto no_clock;
|
|
|
|
}
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/* call trx_sched_fn() for all expired FN */
|
|
|
|
for (i = 0; i < expire_count; i++) {
|
|
|
|
INCREMENT_FN(tcs->last_fn_timer.fn);
|
|
|
|
trx_sched_fn(bts, tcs->last_fn_timer.fn);
|
2016-01-09 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
return 0;
|
2017-07-04 11:49:18 +00:00
|
|
|
|
|
|
|
no_clock:
|
2018-10-21 11:05:08 +00:00
|
|
|
osmo_timerfd_disable(&tcs->fn_timer_ofd);
|
2017-07-04 11:49:18 +00:00
|
|
|
transceiver_available = 0;
|
|
|
|
|
|
|
|
bts_shutdown(bts, "No clock from osmo-trx");
|
|
|
|
|
|
|
|
return -1;
|
2017-06-24 00:09:43 +00:00
|
|
|
}
|
2016-01-09 22:15:41 +00:00
|
|
|
|
2017-07-04 11:43:11 +00:00
|
|
|
/*! reset clock with current fn and schedule it. Called when trx becomes
|
|
|
|
* available or when max clock skew is reached */
|
|
|
|
static int trx_setup_clock(struct gsm_bts *bts, struct osmo_trx_clock_state *tcs,
|
|
|
|
struct timespec *tv_now, const struct timespec *interval, uint32_t fn)
|
|
|
|
{
|
|
|
|
tcs->last_fn_timer.fn = fn;
|
|
|
|
/* call trx cheduler function for new 'last' FN */
|
|
|
|
trx_sched_fn(bts, tcs->last_fn_timer.fn);
|
|
|
|
|
|
|
|
/* schedule first FN clock timer */
|
2018-10-21 11:05:08 +00:00
|
|
|
osmo_timerfd_setup(&tcs->fn_timer_ofd, trx_fn_timer_cb, bts);
|
|
|
|
osmo_timerfd_schedule(&tcs->fn_timer_ofd, NULL, interval);
|
2017-07-04 11:43:11 +00:00
|
|
|
|
|
|
|
tcs->last_fn_timer.tv = *tv_now;
|
|
|
|
tcs->last_clk_ind.tv = *tv_now;
|
|
|
|
tcs->last_clk_ind.fn = fn;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/*! called every time we receive a clock indication from TRX */
|
2016-01-09 22:15:41 +00:00
|
|
|
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
|
|
|
|
{
|
2017-06-24 00:09:43 +00:00
|
|
|
struct osmo_trx_clock_state *tcs = &g_clk_s;
|
|
|
|
struct timespec tv_now;
|
2018-08-17 12:25:30 +00:00
|
|
|
int elapsed_fn;
|
|
|
|
int64_t elapsed_us, elapsed_us_since_clk, elapsed_fn_since_clk, error_us_since_clk;
|
2017-06-24 00:09:43 +00:00
|
|
|
unsigned int fn_caught_up = 0;
|
|
|
|
const struct timespec interval = { .tv_sec = 0, .tv_nsec = FRAME_DURATION_nS };
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
if (quit)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* reset lost counter */
|
2017-06-24 00:09:43 +00:00
|
|
|
tcs->fn_without_clock_ind = 0;
|
2016-01-09 22:15:41 +00:00
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tv_now);
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* clock becomes valid */
|
|
|
|
if (!transceiver_available) {
|
2017-06-24 00:09:43 +00:00
|
|
|
LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", fn);
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
transceiver_available = 1;
|
|
|
|
|
|
|
|
/* start provisioning transceiver */
|
|
|
|
l1if_provision_transceiver(bts);
|
|
|
|
|
|
|
|
/* tell BSC */
|
|
|
|
check_transceiver_availability(bts, 1);
|
|
|
|
|
2017-07-04 11:43:11 +00:00
|
|
|
return trx_setup_clock(bts, tcs, &tv_now, &interval, fn);
|
2017-06-24 00:09:43 +00:00
|
|
|
}
|
2016-01-09 22:15:41 +00:00
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
/* calculate elapsed time +fn since last timer */
|
|
|
|
elapsed_us = compute_elapsed_us(&tcs->last_fn_timer.tv, &tv_now);
|
|
|
|
elapsed_fn = compute_elapsed_fn(tcs->last_fn_timer.fn, fn);
|
|
|
|
#ifdef DEBUG_CLOCK
|
|
|
|
printf("%s(): LAST_TIMER %9ld, elapsed_us=%7d, elapsed_fn=%+3d\n", __func__,
|
|
|
|
tv_now.tv_nsec, elapsed_us, elapsed_fn);
|
|
|
|
#endif
|
|
|
|
/* negative elapsed_fn values mean that we've already processed
|
|
|
|
* more FN based on the local interval timer than what the TRX
|
|
|
|
* now reports in the clock indication. Positive elapsed_fn
|
|
|
|
* values mean we still have a backlog to process */
|
|
|
|
|
|
|
|
/* calculate elapsed time +fn since last clk ind */
|
|
|
|
elapsed_us_since_clk = compute_elapsed_us(&tcs->last_clk_ind.tv, &tv_now);
|
|
|
|
elapsed_fn_since_clk = compute_elapsed_fn(tcs->last_clk_ind.fn, fn);
|
|
|
|
/* error (delta) between local clock since last CLK and CLK based on FN clock at TRX */
|
|
|
|
error_us_since_clk = elapsed_us_since_clk - (FRAME_DURATION_uS * elapsed_fn_since_clk);
|
2018-04-25 13:00:46 +00:00
|
|
|
LOGP(DL1C, LOGL_INFO, "TRX Clock Ind: elapsed_us=%7"PRId64", "
|
|
|
|
"elapsed_fn=%3"PRId64", error_us=%+5"PRId64"\n",
|
2017-06-24 00:09:43 +00:00
|
|
|
elapsed_us_since_clk, elapsed_fn_since_clk, error_us_since_clk);
|
|
|
|
|
|
|
|
/* TODO: put this computed error_us_since_clk into some filter
|
|
|
|
* function and use that to adjust our regular timer interval to
|
|
|
|
* compensate for clock drift between the PC clock and the
|
|
|
|
* TRX/SDR clock */
|
|
|
|
|
|
|
|
tcs->last_clk_ind.tv = tv_now;
|
|
|
|
tcs->last_clk_ind.fn = fn;
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* check for max clock skew */
|
|
|
|
if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) {
|
|
|
|
LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, "
|
2017-06-24 00:09:43 +00:00
|
|
|
"new fn=%u\n", tcs->last_fn_timer.fn, fn);
|
2017-07-04 11:43:11 +00:00
|
|
|
return trx_setup_clock(bts, tcs, &tv_now, &interval, fn);
|
2016-01-09 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2018-08-17 12:25:30 +00:00
|
|
|
LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %" PRId64 "us (elapsed_fn=%d)\n",
|
2017-06-24 00:09:43 +00:00
|
|
|
elapsed_fn * FRAME_DURATION_uS - elapsed_us, elapsed_fn);
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
/* too many frames have been processed already */
|
|
|
|
if (elapsed_fn < 0) {
|
2017-06-24 00:09:43 +00:00
|
|
|
struct timespec first = interval;
|
2016-01-09 22:15:41 +00:00
|
|
|
/* set clock to the time or last FN should have been
|
|
|
|
* transmitted. */
|
2017-06-24 00:09:43 +00:00
|
|
|
first.tv_nsec += (0 - elapsed_fn) * FRAME_DURATION_nS;
|
|
|
|
normalize_timespec(&first);
|
|
|
|
LOGP(DL1C, LOGL_NOTICE, "We were %d FN faster than TRX, compensating\n", -elapsed_fn);
|
2016-01-09 22:15:41 +00:00
|
|
|
/* set time to the time our next FN has to be transmitted */
|
2018-10-21 11:05:08 +00:00
|
|
|
osmo_timerfd_schedule(&tcs->fn_timer_ofd, &first, &interval);
|
2016-01-09 22:15:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* transmit what we still need to transmit */
|
2017-06-24 00:09:43 +00:00
|
|
|
while (fn != tcs->last_fn_timer.fn) {
|
|
|
|
INCREMENT_FN(tcs->last_fn_timer.fn);
|
|
|
|
trx_sched_fn(bts, tcs->last_fn_timer.fn);
|
|
|
|
fn_caught_up++;
|
2016-01-09 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2017-06-24 00:09:43 +00:00
|
|
|
if (fn_caught_up) {
|
|
|
|
LOGP(DL1C, LOGL_NOTICE, "We were %d FN slower than TRX, compensated\n", elapsed_fn);
|
|
|
|
tcs->last_fn_timer.tv = tv_now;
|
|
|
|
}
|
2016-01-09 22:15:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-09 22:21:00 +00:00
|
|
|
|
|
|
|
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
|
|
|
|
{
|
2016-01-09 12:13:37 +00:00
|
|
|
struct phy_instance *pinst = trx_phy_instance(l1t->trx);
|
|
|
|
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
2016-01-09 22:21:00 +00:00
|
|
|
|
|
|
|
if (activate)
|
|
|
|
trx_if_cmd_handover(l1h, tn, ss);
|
|
|
|
else
|
|
|
|
trx_if_cmd_nohandover(l1h, tn, ss);
|
|
|
|
}
|