diff options
Diffstat (limited to 'src/common/scheduler.c')
-rw-r--r-- | src/common/scheduler.c | 209 |
1 files changed, 142 insertions, 67 deletions
diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 65ece7ff..f705ddf7 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -222,7 +222,6 @@ int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx) struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); l1ts->mf_index = 0; - l1ts->mf_last_fn = 0; INIT_LLIST_HEAD(&l1ts->dl_prims); for (i = 0; i < ARRAY_SIZE(l1ts->chan_state); i++) { struct l1sched_chan_state *chan_state; @@ -853,8 +852,115 @@ no_data: return bits; } +#define TDMA_FN_SUM(a, b) \ + ((a + GSM_HYPERFRAME + b) % GSM_HYPERFRAME) + +#define TDMA_FN_SUB(a, b) \ + ((a + GSM_HYPERFRAME - b) % GSM_HYPERFRAME) + +static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t, + struct l1sched_chan_state *l1cs, uint8_t tn, uint32_t fn) +{ + const struct trx_sched_frame *frame_head; + const struct trx_sched_frame *frame; + struct l1sched_ts *l1ts; + uint32_t elapsed_fs; + uint8_t offset, i; + uint32_t fn_i; + + /** + * When a channel is just activated, the MS needs some time + * to synchronize and start burst transmission, + * so let's wait until the first UL burst... + */ + if (l1cs->proc_tdma_fs == 0) + return 0; + + /* Get current TDMA frame info */ + l1ts = l1sched_trx_get_ts(l1t, tn); + offset = fn % l1ts->mf_period; + frame_head = l1ts->mf_frames + offset; + + /* Not applicable for some logical channels */ + switch (frame_head->ul_chan) { + case TRXC_IDLE: + case TRXC_RACH: + case TRXC_PDTCH: + case TRXC_PTCCH: + return 0; + default: + /* No applicable if we are waiting for handover RACH */ + if (l1cs->ho_rach_detect) + return 0; + } + + /* How many frames elapsed since the last one? */ + elapsed_fs = TDMA_FN_SUB(fn, l1cs->last_tdma_fn); + if (elapsed_fs > l1ts->mf_period) { /* Too many! */ + LOGL1S(DL1P, LOGL_ERROR, l1t, tn, frame_head->ul_chan, fn, + "Too many (>%u) contiguous TDMA frames=%u elapsed " + "since the last processed fn=%u\n", l1ts->mf_period, + elapsed_fs, l1cs->last_tdma_fn); + /* FIXME: how should this affect the measurements? */ + return -EINVAL; + } + + /** + * There are several TDMA frames between the last processed + * frame and currently received one. Let's walk through this + * path and count potentially lost frames, i.e. for which + * we didn't receive the corresponsing UL bursts. + * + * Start counting from the last_fn + 1. + */ + for (i = 1; i < elapsed_fs; i++) { + fn_i = TDMA_FN_SUM(l1cs->last_tdma_fn, i); + offset = fn_i % l1ts->mf_period; + frame = l1ts->mf_frames + offset; + + if (frame->ul_chan == frame_head->ul_chan) + l1cs->lost_tdma_fs++; + } + + if (l1cs->lost_tdma_fs > 0) { + LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, frame_head->ul_chan, fn, + "At least %u TDMA frames were lost since the last " + "processed fn=%u\n", l1cs->lost_tdma_fs, l1cs->last_tdma_fn); + + /** + * HACK: substitute lost bursts by zero-filled ones + * + * Instead of doing this, it makes sense to use the + * amount of lost frames in measurement calculations. + */ + static sbit_t zero_burst[GSM_BURST_LEN] = { 0 }; + trx_sched_ul_func *func; + + for (i = 1; i < elapsed_fs; i++) { + fn_i = TDMA_FN_SUM(l1cs->last_tdma_fn, i); + offset = fn_i % l1ts->mf_period; + frame = l1ts->mf_frames + offset; + func = trx_chan_desc[frame->ul_chan].ul_fn; + + if (frame->ul_chan != frame_head->ul_chan) + continue; + + LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, frame->ul_chan, fn, + "Substituting lost TDMA frame=%u by all-zero " + "dummy burst\n", fn_i); + + func(l1t, tn, fn_i, frame->ul_chan, frame->ul_bid, + zero_burst, GSM_BURST_LEN, -128, 0); + + l1cs->lost_tdma_fs--; + } + } + + return 0; +} + /* process uplink burst */ -int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn, +int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, sbit_t *bits, uint16_t nbits, int8_t rssi, int16_t toa256) { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); @@ -863,82 +969,51 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn, uint8_t offset, period, bid; trx_sched_ul_func *func; enum trx_chan_type chan; - uint32_t fn, elapsed; if (!l1ts->mf_index) return -EINVAL; - /* calculate how many frames have been elapsed */ - elapsed = (current_fn + GSM_HYPERFRAME - l1ts->mf_last_fn) % GSM_HYPERFRAME; - - /* start counting from last fn + 1, but only if not too many fn have - * been elapsed */ - if (elapsed < 10) { - fn = (l1ts->mf_last_fn + 1) % GSM_HYPERFRAME; - } else { - LOGPFN(DL1P, LOGL_NOTICE, current_fn, - "Too many contiguous elapsed fn, dropping %u\n", elapsed); - fn = current_fn; - } + /* get frame from multiframe */ + period = l1ts->mf_period; + offset = fn % period; + frame = l1ts->mf_frames + offset; - while (42) { - /* get frame from multiframe */ - period = l1ts->mf_period; - offset = fn % period; - frame = l1ts->mf_frames + offset; + chan = frame->ul_chan; + bid = frame->ul_bid; + l1cs = &l1ts->chan_state[chan]; + func = trx_chan_desc[chan].ul_fn; - chan = frame->ul_chan; - bid = frame->ul_bid; - func = trx_chan_desc[chan].ul_fn; - - l1cs = &l1ts->chan_state[chan]; - - /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active && !l1cs->active) - goto next_frame; - - /* omit bursts which have no handler, like IDLE bursts */ - if (!func) - goto next_frame; - - /* put burst to function */ - if (fn == current_fn) { - /* decrypt */ - if (bits && l1cs->ul_encr_algo) { - ubit_t ks[114]; - int i; - - osmo_a5(l1cs->ul_encr_algo, - l1cs->ul_encr_key, - fn, NULL, ks); - for (i = 0; i < 57; i++) { - if (ks[i]) - bits[i + 3] = - bits[i + 3]; - if (ks[i + 57]) - bits[i + 88] = - bits[i + 88]; - } - } + /* check if channel is active */ + if (!trx_chan_desc[chan].auto_active && !l1cs->active) + return -EINVAL; - func(l1t, tn, fn, chan, bid, bits, nbits, rssi, toa256); - } else if (chan != TRXC_RACH && !l1cs->ho_rach_detect) { - sbit_t spare[GSM_BURST_LEN]; - memset(spare, 0, GSM_BURST_LEN); - /* We missed a couple of frame numbers (system overload?) and are now - * substituting some zero-filled bursts for those bursts we missed */ - LOGPFN(DL1P, LOGL_ERROR, fn, "Substituting all-zero burst (current_fn=%u, " - "elapsed=%u\n", current_fn, elapsed); - func(l1t, tn, fn, chan, bid, spare, GSM_BURST_LEN, -128, 0); - } + /* omit bursts which have no handler, like IDLE bursts */ + if (!func) + return -EINVAL; -next_frame: - /* reached current fn */ - if (fn == current_fn) - break; + /* calculate how many TDMA frames were potentially lost */ + trx_sched_calc_frame_loss(l1t, l1cs, tn, fn); + + /* update TDMA frame counters */ + l1cs->last_tdma_fn = fn; + l1cs->proc_tdma_fs++; - fn = (fn + 1) % GSM_HYPERFRAME; + /* decrypt */ + if (bits && l1cs->ul_encr_algo) { + ubit_t ks[114]; + int i; + + osmo_a5(l1cs->ul_encr_algo, l1cs->ul_encr_key, fn, NULL, ks); + for (i = 0; i < 57; i++) { + if (ks[i]) + bits[i + 3] = - bits[i + 3]; + if (ks[i + 57]) + bits[i + 88] = - bits[i + 88]; + } } - l1ts->mf_last_fn = fn; + /* put burst to function */ + func(l1t, tn, fn, chan, bid, bits, nbits, rssi, toa256); return 0; } |