summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/target/firmware/include/layer1/sync.h4
-rw-r--r--src/target/firmware/layer1/l23_api.c14
-rw-r--r--src/target/firmware/layer1/mframe_sched.c22
-rw-r--r--src/target/firmware/layer1/prim_rach.c4
-rw-r--r--src/target/firmware/layer1/sync.c51
-rw-r--r--src/target/firmware/layer1/tpu_window.c20
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;
}