diff options
-rw-r--r-- | src/target/firmware/include/layer1/sync.h | 4 | ||||
-rw-r--r-- | src/target/firmware/layer1/l23_api.c | 14 | ||||
-rw-r--r-- | src/target/firmware/layer1/mframe_sched.c | 22 | ||||
-rw-r--r-- | src/target/firmware/layer1/prim_rach.c | 4 | ||||
-rw-r--r-- | src/target/firmware/layer1/sync.c | 51 | ||||
-rw-r--r-- | src/target/firmware/layer1/tpu_window.c | 20 |
6 files changed, 88 insertions, 27 deletions
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h index 3565ee20..7ce87566 100644 --- a/src/target/firmware/include/layer1/sync.h +++ b/src/target/firmware/include/layer1/sync.h @@ -72,7 +72,9 @@ struct l1s_state { /* The current TPU offset register */ uint32_t tpu_offset; - int32_t tpu_offset_correction; + int32_t tpu_offset_correction; /* used for TOA adjustment */ + int32_t tpu_offset_shift; /* used for TS or sync change */ + int32_t tpu_offset_changed; /* offset changed at last fiq */ /* TX parameters */ int8_t ta; diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c index daffaf8b..c7849aeb 100644 --- a/src/target/firmware/layer1/l23_api.c +++ b/src/target/firmware/layer1/l23_api.c @@ -235,9 +235,11 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg) struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data; struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data; struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload; + uint8_t old_tn; - printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n", - ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc); + printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u tn=%u)\n", + ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc, + ul->chan_nr & 0x7); /* disable neighbour cell measurement of C0 TS 0 */ mframe_disable(MF_TASK_NEIGH_PM51_C0T0); @@ -245,6 +247,7 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg) /* configure dedicated channel state */ l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr); l1s.dedicated.tsc = est_req->tsc; + old_tn = l1s.dedicated.tn; l1s.dedicated.tn = ul->chan_nr & 0x7; l1s.dedicated.h = est_req->h; @@ -274,6 +277,13 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg) /* figure out which MF tasks to enable */ l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM)); + + /* shift TPU according to chnage in TN */ + if (l1s.dedicated.tn != old_tn) { + l1s.tpu_offset_shift += (l1s.dedicated.tn - old_tn) * 625; + printf("Shift TPU by %d TN (%d qbits)\n", + l1s.dedicated.tn - old_tn, l1s.tpu_offset_shift); + } } /* receive a L1CTL_DM_FREQ_REQ from L23 */ diff --git a/src/target/firmware/layer1/mframe_sched.c b/src/target/firmware/layer1/mframe_sched.c index 7fa38c13..089ca8ed 100644 --- a/src/target/firmware/layer1/mframe_sched.c +++ b/src/target/firmware/layer1/mframe_sched.c @@ -448,7 +448,7 @@ static void mframe_schedule_set(enum mframe_task task_id) unsigned int trigger = si->frame_nr % si->modulo; unsigned int current = (l1s.current_time.fn + SCHEDULE_AHEAD) % si->modulo; if (current == trigger) { - uint32_t fn; + uint32_t fn, fn_diff; int rv; /* Schedule the set */ @@ -459,8 +459,9 @@ static void mframe_schedule_set(enum mframe_task task_id) /* Compute the next safe time to queue a DSP command */ fn = l1s.current_time.fn; ADD_MODULO(fn, rv - 2, GSM_MAX_FN); /* -2 = worst case last dsp command */ - if ((fn > l1s.mframe_sched.safe_fn) || - (l1s.mframe_sched.safe_fn >= GSM_MAX_FN)) + fn_diff = (fn - l1s.mframe_sched.safe_fn + GSM_MAX_FN) % GSM_MAX_FN; + if (fn_diff < (GSM_MAX_FN >> 1) /* diff is equal or positive */ + || (l1s.mframe_sched.safe_fn >= GSM_MAX_FN)) /* or safe_fn not yet set */ l1s.mframe_sched.safe_fn = fn; } } @@ -488,12 +489,19 @@ void mframe_set(uint32_t tasks) void mframe_schedule(void) { unsigned int i; - int fn_diff; + uint32_t fn_diff; + + /* Do not schedule new tasks until TPU is shifted */ + if (l1s.tpu_offset_shift) +{ +puts("outstanding TPU shift, do not schedule!\n"); + return; +} /* Try to enable/disable task to meet target bitmap */ - fn_diff = l1s.mframe_sched.safe_fn - l1s.current_time.fn; - if ((fn_diff <= 0) || (fn_diff >= (GSM_MAX_FN>>1)) || - (l1s.mframe_sched.safe_fn >= GSM_MAX_FN)) + fn_diff = (l1s.mframe_sched.safe_fn - l1s.current_time.fn + GSM_MAX_FN) % GSM_MAX_FN; + if ((fn_diff == 0 || fn_diff >= (GSM_MAX_FN>>1)) /* safe_fn is now or already was */ + || (l1s.mframe_sched.safe_fn >= GSM_MAX_FN)) /* or safe_fn not yet set */ /* If nothing is in the way, enable new tasks */ l1s.mframe_sched.tasks = l1s.mframe_sched.tasks_tgt; else diff --git a/src/target/firmware/layer1/prim_rach.c b/src/target/firmware/layer1/prim_rach.c index e6ea6568..eeb0435f 100644 --- a/src/target/firmware/layer1/prim_rach.c +++ b/src/target/firmware/layer1/prim_rach.c @@ -138,6 +138,10 @@ void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra) unsigned long flags; offset += 3; + if (l1s.tpu_offset_shift) { + puts("RACH while TPU is not correct, delaying!\n"); + offset += 2; + } local_firq_save(flags); if (combined) { diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c index 36f42975..a9e51015 100644 --- a/src/target/firmware/layer1/sync.c +++ b/src/target/firmware/layer1/sync.c @@ -183,25 +183,56 @@ void l1s_reset_hw(void) /* Timer for detecting lost IRQ */ #define TIMER_TICKS_PER_TDMA 1875 -#define TIMER_TICK_JITTER 1 +#define TIMER_TICK_JITTER 2 static int last_timestamp; static inline void check_lost_frame(void) { - int diff, timestamp = hwtimer_read(1); + int diff, expected, timestamp = hwtimer_read(1); if (last_timestamp < timestamp) last_timestamp += (4*TIMER_TICKS_PER_TDMA); diff = last_timestamp - timestamp; + /* calculate expected diff */ + expected = (5000 + l1s.tpu_offset_changed) + * TIMER_TICKS_PER_TDMA / 5000; + /* allow for a bit of jitter */ - if (diff < TIMER_TICKS_PER_TDMA - TIMER_TICK_JITTER || - diff > TIMER_TICKS_PER_TDMA + TIMER_TICK_JITTER) - printf("LOST %d!\n", diff); + if (diff < expected - TIMER_TICK_JITTER || + diff > expected + TIMER_TICK_JITTER) + printf("LOST %d (expected %d)\n", diff, expected); + + /* check for lost frames */ + if ((diff - expected) > (TIMER_TICKS_PER_TDMA >> 1)) { + int frames_1000; + int fn_offset; + + frames_1000 = (diff - expected) * 1000 / TIMER_TICKS_PER_TDMA; + fn_offset = (frames_1000 + 500) / 1000; + + printf("%d.%03d frames lost, compensating GSM time\n", + frames_1000 / 1000, frames_1000 % 1000); + + l1s_time_inc(&l1s.current_time, fn_offset); + l1s.next_time = l1s.current_time; + l1s_time_inc(&l1s.next_time, 1); + if (l1s.mframe_sched.safe_fn < GSM_MAX_FN) + ADD_MODULO(l1s.mframe_sched.safe_fn, fn_offset, + GSM_MAX_FN); + } + + /* check for two FIQs in the same frame */ + if ((diff - expected) < -(TIMER_TICKS_PER_TDMA >> 1)) { + puts("double FIQ in TDMA frame, compensating GSM time\n"); + l1s.next_time = l1s.current_time; + l1s_time_inc(&l1s.current_time, GSM_MAX_FN - 1); + } last_timestamp = timestamp; + l1s.tpu_offset_changed = 0; } /* schedule a completion */ @@ -258,6 +289,10 @@ static void l1_sync(void) * TDMA frame (including setup/cleanup steps) */ sched_flags = tdma_sched_flag_scan(); + /* if tpu offset needs to be shifted, schedule tpu scenario */ + if (l1s.tpu_offset_shift) + sched_flags |= TDMA_IFLG_TPU; + if (sched_flags & TDMA_IFLG_TPU) l1s_win_init(); @@ -367,6 +402,12 @@ void l1s_reset(void) /* Leave dedicated mode */ l1s.dedicated.type = GSM_DCHAN_NONE; + l1s.dedicated.tn = 0; + + /* reset TPU offset shift/correction */ + l1s.tpu_offset_correction = 0; + l1s.tpu_offset_shift = 0; + l1s.tpu_offset_changed = 0; /* reset scheduler and hardware */ sched_gsmtime_reset(); diff --git a/src/target/firmware/layer1/tpu_window.c b/src/target/firmware/layer1/tpu_window.c index f4e76c16..abdad956 100644 --- a/src/target/firmware/layer1/tpu_window.c +++ b/src/target/firmware/layer1/tpu_window.c @@ -67,30 +67,26 @@ static const uint16_t tx_burst_duration[_NUM_L1_TXWIN] = { [L1_TXWIN_AB] = L1_TX_AB_DURATION_Q, }; - static int _win_setup(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3) { - uint8_t tn; - - rfch_get_params(&l1s.next_time, NULL, NULL, &tn); - - l1s.tpu_offset = (5000 + l1s.tpu_offset + l1s.tpu_offset_correction) % 5000; + l1s.tpu_offset = (l1s.tpu_offset + l1s.tpu_offset_correction + + l1s.tpu_offset_shift + L1_TDMA_LENGTH_Q + + L1_TDMA_LENGTH_Q) % L1_TDMA_LENGTH_Q; + l1s.tpu_offset_changed = l1s.tpu_offset_correction + + l1s.tpu_offset_shift; l1s.tpu_offset_correction = 0; + l1s.tpu_offset_shift = 0; tpu_enq_at(4740); - tpu_enq_sync((5000 + l1s.tpu_offset + (L1_BURST_LENGTH_Q * tn)) % 5000); + tpu_enq_sync(l1s.tpu_offset); return 0; } static int _win_cleanup(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3) { - uint8_t tn; - - rfch_get_params(&l1s.next_time, NULL, NULL, &tn); - /* restore offset */ - tpu_enq_offset((5000 + l1s.tpu_offset + (L1_BURST_LENGTH_Q * tn)) % 5000); + tpu_enq_offset(l1s.tpu_offset); return 0; } |