Added timing advance support for up and downlink TBFs

The timing advance of any TBF is stored when it ends. Whenever a new TBF
with the same TLLI is created (downlink TBF), the stored TA is recalled.

This algorithm assumes that the mobile does not move too fast during
transfer. Also the mobile must start a connection in order to get correct
initial timing advance.

This algorithm does not implement the timing advance procedure as defined
in TS 04.60. To implement the standard timing advance procedure, the BTS
must decode RACH on certain bursts, the mobile is expected to send them.
This requires much more complexity to a transceiver like USRP/UmTRX or
Calypso BTS.

The algorithm was tested at TA >= 8 and works quite well.
This commit is contained in:
Andreas Eversberg 2013-05-13 16:45:21 +02:00
parent 783aa4bcb8
commit a004e6a823
7 changed files with 185 additions and 11 deletions

View File

@ -196,6 +196,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
uint8_t trx, ta, ss;
int8_t use_trx;
struct gprs_rlcmac_tbf *old_tbf;
int rc;
/* check for uplink data, so we copy our informations */
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
@ -207,7 +208,19 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
old_tbf = tbf;
} else {
use_trx = -1;
ta = 0; /* FIXME: initial TA */
/* we already have an uplink TBF, so we use that TA */
if (tbf)
ta = tbf->ta;
else {
/* recall TA */
rc = recall_timing_advance(tlli);
if (rc < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown"
", assuming 0\n");
ta = 0;
} else
ta = rc;
}
ss = 1; /* PCH assignment only allows one timeslot */
old_tbf = NULL;
}

View File

@ -1819,3 +1819,107 @@ int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
return 0;
}
/*
* timing advance memory
*/
/* enable to debug timing advance memory */
//#define DEBUG_TA
static LLIST_HEAD(gprs_rlcmac_ta_list);
static int gprs_rlcmac_ta_num = 0;
struct gprs_rlcmac_ta {
struct llist_head list;
uint32_t tlli;
uint8_t ta;
};
/* remember timing advance of a given TLLI */
int remember_timing_advance(uint32_t tlli, uint8_t ta)
{
struct gprs_rlcmac_ta *ta_entry;
/* check for existing entry */
llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
if (ta_entry->tlli == tlli) {
#ifdef DEBUG_TA
fprintf(stderr, "update %08x %d\n", tlli, ta);
#endif
ta_entry->ta = ta;
/* relink to end of list */
llist_del(&ta_entry->list);
llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
return 0;
}
}
#ifdef DEBUG_TA
fprintf(stderr, "remember %08x %d\n", tlli, ta);
#endif
/* if list is full, remove oldest entry */
if (gprs_rlcmac_ta_num == 30) {
ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
struct gprs_rlcmac_ta, list);
llist_del(&ta_entry->list);
talloc_free(ta_entry);
gprs_rlcmac_ta_num--;
}
/* create new TA entry */
ta_entry = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ta);
if (!ta_entry)
return -ENOMEM;
ta_entry->tlli = tlli;
ta_entry->ta = ta;
llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
gprs_rlcmac_ta_num++;
return 0;
}
int recall_timing_advance(uint32_t tlli)
{
struct gprs_rlcmac_ta *ta_entry;
uint8_t ta;
llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
if (ta_entry->tlli == tlli) {
ta = ta_entry->ta;
#ifdef DEBUG_TA
fprintf(stderr, "recall %08x %d\n", tlli, ta);
#endif
return ta;
}
}
#ifdef DEBUG_TA
fprintf(stderr, "no entry for %08x\n", tlli);
#endif
return -EINVAL;
}
int flush_timing_advance(void)
{
struct gprs_rlcmac_ta *ta_entry;
int count = 0;
while (!llist_empty(&gprs_rlcmac_ta_list)) {
ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
struct gprs_rlcmac_ta, list);
#ifdef DEBUG_TA
fprintf(stderr, "flush entry %08x %d\n", ta_entry->tlli,
ta_entry->ta);
#endif
llist_del(&ta_entry->list);
talloc_free(ta_entry);
count++;
}
gprs_rlcmac_ta_num = 0;
return count;
}

View File

@ -374,6 +374,8 @@ void tbf_timer_cb(void *_tbf);
int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_sba_timeout(struct gprs_rlcmac_sba *sba);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
@ -421,6 +423,12 @@ struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
struct msgb *gprs_rlcmac_send_packet_paging_request(
struct gprs_rlcmac_pdch *pdch);
int remember_timing_advance(uint32_t tlli, uint8_t ta);
int recall_timing_advance(uint32_t tlli);
int flush_timing_advance(void);
extern "C" {
#endif
int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf,

View File

@ -206,6 +206,15 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
return 0;
}
int gprs_rlcmac_sba_timeout(struct gprs_rlcmac_sba *sba)
{
LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for SBA\n");
llist_del(&sba->list);
talloc_free(sba);
return 0;
}
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
int i;
@ -263,6 +272,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
int8_t tfi = 0; /* must be signed */
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_sba *sba;
int rc;
RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)talloc_zero(tall_pcu_ctx, RlcMacUplink_t);
@ -420,6 +430,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
if (!tbf) {
uint8_t ms_class = 0;
struct gprs_rlcmac_tbf *dl_tbf;
uint8_t ta;
if ((dl_tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
@ -431,12 +442,28 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
"in packet ressource request of single "
"block, so we provide one:\n");
sba = sba_find(trx, ts, fn);
if (!sba) {
LOGP(DRLCMAC, LOGL_NOTICE, "MS requests UL TBF "
"in packet ressource request of single "
"block, but there is no resource request "
"scheduled!\n");
rc = recall_timing_advance(tlli);
if (rc >= 0)
ta = rc;
else
ta = 0;
} else {
ta = sba->ta;
remember_timing_advance(tlli, ta);
llist_del(&sba->list);
talloc_free(sba);
}
if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability)
ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability);
if (!ms_class)
LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
tbf = alloc_ul_tbf(trx, ms_class, tlli, 0, NULL);
#warning FIXME TA!!!
tbf = alloc_ul_tbf(trx, ms_class, tlli, ta, NULL);
if (!tbf)
break;
/* set control ts to current MS's TS, until assignment complete */
@ -469,6 +496,17 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
LOGP(DRLCMAC, LOGL_ERROR, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x FIXME: Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli);
break;
case MT_PACKET_MEASUREMENT_REPORT:
sba = sba_find(trx, ts, fn);
if (!sba) {
LOGP(DRLCMAC, LOGL_NOTICE, "MS send measurement "
"in packet ressource request of single "
"block, but there is no resource request "
"scheduled!\n");
} else {
remember_timing_advance(ul_control_block->u.Packet_Measurement_Report.TLLI, sba->ta);
llist_del(&sba->list);
talloc_free(sba);
}
gprs_rlcmac_meas_rep(&ul_control_block->u.Packet_Measurement_Report);
break;
default:
@ -888,6 +926,8 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
}
/* mark TLLI valid now */
tbf->tlli_valid = 1;
/* store current timing advance */
remember_timing_advance(tbf->tlli, tbf->ta);
/* already have TLLI, but we stille get another one */
} else if (rh->ti) {
uint32_t tlli;

View File

@ -78,11 +78,8 @@ uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
sba_fn ++;
sba_fn = sba_fn % 2715648;
sba = sba_find(trx, ts, sba_fn);
if (sba) {
llist_del(&sba->list);
talloc_free(sba);
if (sba)
return sba_fn;
}
return 0xffffffff;
}

View File

@ -516,6 +516,7 @@ bssgp_failed:
static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
{
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_sba *sba, *sba2;
uint32_t elapsed;
uint8_t fn13 = time_ind->fn % 13;
@ -531,18 +532,27 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
/* check for poll timeout */
llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
elapsed = (frame_number - tbf->poll_fn) % 2715648;
if (elapsed >= 20 && elapsed < 200)
elapsed = (frame_number + 2715648 - tbf->poll_fn)
% 2715648;
if (elapsed >= 20 && elapsed < 2715400)
gprs_rlcmac_poll_timeout(tbf);
}
}
llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
elapsed = (frame_number - tbf->poll_fn) % 2715648;
if (elapsed >= 20 && elapsed < 200)
elapsed = (frame_number + 2715648 - tbf->poll_fn)
% 2715648;
if (elapsed >= 20 && elapsed < 2715400)
gprs_rlcmac_poll_timeout(tbf);
}
}
llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
elapsed = (frame_number + 2715648 - sba->fn) % 2715648;
if (elapsed >= 20 && elapsed < 2715400) {
/* sba will be freed here */
gprs_rlcmac_sba_timeout(sba);
}
}
return 0;
}

View File

@ -248,6 +248,8 @@ int main(int argc, char *argv[])
pcu_l1if_close();
flush_timing_advance();
talloc_free(gprs_rlcmac_bts);
talloc_report_full(tall_pcu_ctx, stderr);