1 /* Synchronous part of GSM Layer 1 */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
5 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <byteorder.h>
34 #include <osmocore/gsm_utils.h>
35 #include <osmocore/msgb.h>
36 #include <calypso/dsp_api.h>
37 #include <calypso/irq.h>
38 #include <calypso/tpu.h>
39 #include <calypso/tsp.h>
40 #include <calypso/dsp.h>
41 #include <calypso/timer.h>
42 #include <comm/sercomm.h>
44 #include <abb/twl3025.h>
46 #include <layer1/sync.h>
47 #include <layer1/afc.h>
48 #include <layer1/agc.h>
49 #include <layer1/tdma_sched.h>
50 #include <layer1/mframe_sched.h>
51 #include <layer1/sched_gsmtime.h>
52 #include <layer1/tpu_window.h>
53 #include <layer1/l23_api.h>
55 #include <l1a_l23_interface.h>
57 //#define DEBUG_EVERY_TDMA
59 /* A debug macro to print every TDMA frame */
60 #ifdef DEBUG_EVERY_TDMA
61 #define putchart(x) putchar(x)
68 static l1s_cb_t l1s_cb = NULL;
70 void l1s_set_handler(l1s_cb_t cb)
75 #define ADD_MODULO(sum, delta, modulo) do { \
76 if ((sum += delta) >= modulo) \
80 #define GSM_MAX_FN (26*51*2048)
82 static void l1s_time_inc(struct gsm_time *time, uint32_t delta_fn)
84 ADD_MODULO(time->fn, delta_fn, GSM_MAX_FN);
87 ADD_MODULO(time->t2, 1, 26);
88 ADD_MODULO(time->t3, 1, 51);
90 /* if the new frame number is a multiple of 51 */
92 ADD_MODULO(time->tc, 1, 8);
94 /* if new FN is multiple of 51 and 26 */
96 ADD_MODULO(time->t1, 1, 2048);
99 gsm_fn2gsmtime(time, time->fn);
102 static void l1s_time_dump(const struct gsm_time *time)
104 printf("fn=%u(%u/%2u/%2u)", time->fn, time->t1, time->t2, time->t3);
107 /* determine the GSM time and BSIC from a Sync Burst */
108 static uint8_t l1s_decode_sb(struct gsm_time *time, uint32_t sb)
110 uint8_t bsic = (sb >> 2) & 0x3f;
113 memset(time, 0, sizeof(*time));
115 /* TS 05.02 Chapter 3.3.2.2.1 SCH Frame Numbers */
116 time->t1 = ((sb >> 23) & 1) | ((sb >> 7) & 0x1fe) | ((sb << 9) & 0x600);
117 time->t2 = (sb >> 18) & 0x1f;
118 t3p = ((sb >> 24) & 1) | ((sb >> 15) & 6);
119 time->t3 = t3p*10 + 1;
121 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
122 time->fn = gsm_gsmtime2fn(time);
124 time->tc = (time->fn / 51) % 8;
129 extern uint16_t rf_arfcn; // TODO
131 /* clip a signed 16bit value at a certain limit */
132 int16_t clip_int16(int16_t angle, int16_t clip_at)
136 else if (angle < -clip_at)
142 int16_t l1s_snr_int(uint16_t snr)
147 uint16_t l1s_snr_fract(uint16_t snr)
149 uint32_t fract = snr & 0x3ff;
150 fract = fract * 1000 / (2 << 10);
152 return fract & 0xffff;
155 static void l1ddsp_meas_read(uint8_t nbmeas, uint16_t *pm)
159 for (i = 0; i < nbmeas; i++)
160 pm[i] = (uint16_t) ((dsp_api.db_r->a_pm[i] & 0xffff) >> 3);
161 dsp_api.r_page_used = 1;
164 /* Convert an angle in fx1.15 notatinon into Hz */
165 #define BITFREQ_DIV_2PI 43104 /* 270kHz / 2 * pi */
166 #define BITFREQ_DIV_PI 86208 /* 270kHz / pi */
167 #define ANG2FREQ_SCALING (2<<15) /* 2^15 scaling factor for fx1.15 */
168 #define ANGLE_TO_FREQ(angle) ((int16_t)angle * BITFREQ_DIV_PI / ANG2FREQ_SCALING)
170 #define AFC_MAX_ANGLE 328 /* 0.01 radian in fx1.15 */
171 #define AFC_SNR_THRESHOLD 2560 /* 2.5 dB in fx6.10 */
173 #define BITS_PER_TDMA 1250
174 #define QBITS_PER_TDMA (BITS_PER_TDMA * 4) /* 5000 */
175 #define TPU_RANGE QBITS_PER_TDMA
176 #define SWITCH_TIME (TPU_RANGE-10)
179 /* synchronize the L1S to a new timebase (typically a new cell */
180 static void synchronize_tdma(struct l1_cell_info *cinfo)
183 uint32_t tpu_shift = cinfo->time_alignment;
185 /* NB detection only works if the TOA of the SB
186 * is within 0...8. We have to add 75 to get an SB TOA of 4. */
189 tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
191 fn_offset = cinfo->fn_offset - 1;
193 /* if we're already very close to the end of the TPU frame,
194 * the next interrupt will basically occur now and we need to compensate */
195 if (tpu_shift < SWITCH_TIME)
198 #if 0 /* probably wrong as we already added "offset" and "shift" above */
199 /* increment the TPU quarter-bit offset */
200 l1s.tpu_offset = (l1s.tpu_offset + tpu_shift) % TPU_RANGE;
202 l1s.tpu_offset = tpu_shift;
205 puts("Synchronize_TDMA\n");
206 /* request the TPU to adjust the SYNCHRO and OFFSET registers */
207 tpu_enq_at(SWITCH_TIME);
208 tpu_enq_sync(l1s.tpu_offset);
210 /* FIXME: properly end the TPU window at the emd of l1_sync() */
214 /* Change the current time to reflect the new value */
215 l1s_time_inc(&l1s.current_time, fn_offset);
216 l1s.next_time = l1s.current_time;
217 l1s_time_inc(&l1s.next_time, 1);
219 /* The serving cell now no longer has a frame or bit offset */
220 cinfo->fn_offset = 0;
221 cinfo->time_alignment = 0;
224 static void l1s_reset_hw(void)
228 dsp_api.r_page_used = 0;
229 dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
230 dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
231 dsp_api.ndb->d_dsp_page = 0;
233 /* we have to really reset the TPU, otherwise FB detection
234 * somtimes returns wrong TOA values. */
238 tpu_enq_wait(5); /* really needed ? */
239 tpu_enq_offset(l1s.tpu_offset);
244 uint32_t fnr_report; /* frame number when DSP reported it */
245 int attempt; /* which attempt was this ? */
252 /* computed values */
256 static void dump_mon_state(struct mon_state *fb)
259 printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz, "
260 "SNR=%04x(%d.%u) OFFSET=%u SYNCHRO=%u\n", fb->fnr_report, fb->attempt,
261 fb->toa, agc_inp_dbm8_by_pm(fb->pm)/8,
262 ANGLE_TO_FREQ(fb->angle), fb->snr, l1s_snr_int(fb->snr),
263 l1s_snr_fract(fb->snr), tpu_get_offset(), tpu_get_synchro());
265 printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz ", fb->fnr_report, fb->attempt,
266 fb->toa, agc_inp_dbm8_by_pm(fb->pm)/8,
267 ANGLE_TO_FREQ(fb->angle));
271 static struct mon_state _last_fb, *last_fb = &_last_fb;
273 static int read_fb_result(int attempt)
275 last_fb->toa = dsp_api.ndb->a_sync_demod[D_TOA];
276 last_fb->pm = dsp_api.ndb->a_sync_demod[D_PM]>>3;
277 last_fb->angle = dsp_api.ndb->a_sync_demod[D_ANGLE];
278 last_fb->snr = dsp_api.ndb->a_sync_demod[D_SNR];
280 //last_fb->angle = clip_int16(last_fb->angle, AFC_MAX_ANGLE);
281 last_fb->freq_diff = ANGLE_TO_FREQ(last_fb->angle);
282 last_fb->fnr_report = l1s.current_time.fn;
283 last_fb->attempt = attempt;
285 dump_mon_state(last_fb);
287 dsp_api.ndb->d_fb_det = 0;
288 dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */
290 /* Update AFC with current frequency offset */
291 afc_correct(last_fb->freq_diff, rf_arfcn);
293 //tpu_dsp_frameirq_enable();
297 static void read_sb_result(int attempt)
299 last_fb->toa = dsp_api.db_r->a_serv_demod[D_TOA];
300 last_fb->pm = dsp_api.db_r->a_serv_demod[D_PM]>>3;
301 last_fb->angle = dsp_api.db_r->a_serv_demod[D_ANGLE];
302 last_fb->snr = dsp_api.db_r->a_serv_demod[D_SNR];
304 last_fb->freq_diff = ANGLE_TO_FREQ(last_fb->angle);
305 last_fb->fnr_report = l1s.current_time.fn;
306 last_fb->attempt = attempt;
308 dump_mon_state(last_fb);
310 if (last_fb->snr > AFC_SNR_THRESHOLD)
311 afc_input(last_fb->freq_diff, rf_arfcn, 1);
313 afc_input(last_fb->freq_diff, rf_arfcn, 0);
315 dsp_api.r_page_used = 1;
318 #define TIMER_TICKS_PER_TDMA 1875
320 static int last_timestamp;
322 static inline void check_lost_frame(void)
324 int diff, timestamp = hwtimer_read(1);
326 if (last_timestamp < timestamp)
327 last_timestamp += (4*TIMER_TICKS_PER_TDMA);
329 diff = last_timestamp - timestamp;
333 last_timestamp = timestamp;
336 /* main routine for synchronous part of layer 1, called by frame interrupt
337 * generated by TPU once every TDMA frame */
338 static void l1_sync(void)
345 l1s.current_time = l1s.next_time;
346 l1s_time_inc(&l1s.next_time, 1);
347 //l1s_time_dump(&l1s.current_time); putchar(' ');
350 dsp_api.r_page_used = 0;
352 /* Update pointers */
353 if (dsp_api.w_page == 0)
354 dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
356 dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_1;
358 if (dsp_api.r_page == 0)
359 dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
361 dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_1;
363 /* Reset MCU->DSP page */
364 dsp_api_memset((uint16_t *) dsp_api.db_w, sizeof(*dsp_api.db_w));
369 if (dsp_api.ndb->d_error_status) {
370 printf("DSP Error Status: %u\n", dsp_api.ndb->d_error_status);
371 dsp_api.ndb->d_error_status = 0;
374 /* execute the sched_items that have been scheduled for this TDMA frame */
375 tdma_sched_execute();
377 if (dsp_api.r_page_used) {
378 /* clear and switch the read page */
379 dsp_api_memset((uint16_t *) dsp_api.db_r, sizeof(*dsp_api.db_r));
381 /* TSM30 does it (really needed ?):
382 * Set crc result as "SB not found". */
383 dsp_api.db_r->a_sch[0] = (1<<B_SCH_CRC); /* B_SCH_CRC =1, BLUD =0 */
388 //dsp_end_scenario();
390 /* schedule new / upcoming TDMA items */
391 mframe_schedule(l1s.mf_tasks);
392 /* schedule new / upcoming one-shot events */
393 sched_gsmtime_execute(l1s.current_time.fn);
395 tdma_sched_advance();
398 /* ABORT command ********************************************************/
400 static int l1s_abort_cmd(__unused uint8_t p1, __unused uint8_t p2,
401 __unused uint16_t p3)
405 /* similar to l1s_reset_hw() without touching the TPU */
409 dsp_api.r_page_used = 0;
410 dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
411 dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
413 /* Reset task commands. */
414 dsp_api.db_w->d_task_d = NO_DSP_TASK; /* Init. RX task to NO TASK */
415 dsp_api.db_w->d_task_u = NO_DSP_TASK; /* Init. TX task to NO TASK */
416 dsp_api.db_w->d_task_ra = NO_DSP_TASK; /* Init. RA task to NO TASK */
417 dsp_api.db_w->d_task_md = NO_DSP_TASK; /* Init. MONITORING task to NO TASK */
418 dsp_api.ndb->d_dsp_page = 0;
420 /* Set "b_abort" to TRUE, dsp will reset current and pending tasks */
421 dsp_api.db_w->d_ctrl_system |= (1 << B_TASK_ABORT);
425 void l1s_dsp_abort(void)
427 /* abort right now */
428 tdma_schedule(0, &l1s_abort_cmd, 0, 0, 0);
431 /* FCCH Burst *****************************************************************/
433 /* scheduler callback to issue a FB detection task to the DSP */
434 static int l1s_fbdet_cmd(__unused uint8_t p1, __unused uint8_t fb_mode,
435 __unused uint16_t p3)
444 dsp_api.db_w->d_task_md = FB_DSP_TASK; /* maybe with I/Q swap? */
445 dsp_api.ndb->d_fb_mode = fb_mode;
449 l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_FB);
456 /* scheduler callback to check for a FB detection response */
457 static int l1s_fbdet_resp(__unused uint8_t p1, uint8_t attempt,
458 __unused uint16_t p3)
460 int ntdma, qbits, fn_offset;
464 if (!dsp_api.ndb->d_fb_det) {
465 /* we did not detect a FB, fall back to mode 0! */
467 /* If we don't reset here, we get DSP DMA errors */
470 /* if we are already synchronized initially,
471 * code below has set l1s.fb.mode to 1 and
472 * we switch to the more narrow mode 1 */
473 l1s_fb_test(1, l1s.fb.mode);
478 printf("FB%u ", dsp_api.ndb->d_fb_mode);
479 read_fb_result(attempt);
483 if (last_fb->toa < 0) {
484 qbits = (last_fb->toa + BITS_PER_TDMA) * 4;
487 ntdma = (last_fb->toa) / BITS_PER_TDMA;
488 qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4;
492 fn_offset = l1s.current_time.fn - attempt + ntdma;
493 int fnr_delta = last_fb->fnr_report - attempt;
494 int bits_delta = fnr_delta * BITS_PER_TDMA;
496 struct l1_cell_info *cinfo = &l1s.serving_cell;
498 cinfo->fn_offset = fnr_delta;
499 cinfo->time_alignment = qbits;
500 cinfo->arfcn = rf_arfcn;
502 if (last_fb->toa > bits_delta)
503 printf("=> DSP reports FB in bit that is %d bits in the future?!?\n",
504 last_fb->toa - bits_delta);
506 int fb_fnr = (last_fb->fnr_report - last_fb->attempt)
507 + last_fb->toa/BITS_PER_TDMA;
508 printf("=>FB @ FNR %u fn_offset=%d qbits=%u\n",
509 fb_fnr, fn_offset, qbits);
513 /* We found a frequency burst, reset everything and start next task */
517 if (dsp_api.frame_ctr > 500 && l1s.fb.mode == 0) {
518 /* We've done more than 500 rounds of FB detection, so
519 * the AGC should be synchronized and we switch to the
520 * more narrow FB detection mode 1 */
522 /* Don't synchronize_tdma() yet, it does probably not work
523 * reliable due to the TPU reset) */
527 /* restart a SB or new FB detection task */
528 if (dsp_api.frame_ctr > 1000 && l1s.fb.mode == 1 &&
529 abs(last_fb->freq_diff) < 1000) {
532 /* synchronize before reading SB */
533 synchronize_tdma(&l1s.serving_cell);
535 delay = fn_offset + 11 - l1s.current_time.fn - 1;
536 dsp_api.ndb->d_fb_det = 0;
537 dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */
543 /* If we don't reset here, we get DSP DMA errors */
545 /* use FB_MODE_1 if we are within certain limits */
546 if (abs(last_fb->freq_diff < 2000))
547 l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 1);
549 l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 0);
555 /* we don't really use this because we need to configure the fb_mode! */
556 static const struct tdma_sched_item fb_sched_set[] = {
557 SCHED_ITEM(l1s_fbdet_cmd, 0, 0), SCHED_END_FRAME(),
559 SCHED_ITEM(l1s_fbdet_resp, 0, 1), SCHED_END_FRAME(),
560 SCHED_ITEM(l1s_fbdet_resp, 0, 2), SCHED_END_FRAME(),
561 SCHED_ITEM(l1s_fbdet_resp, 0, 3), SCHED_END_FRAME(),
562 SCHED_ITEM(l1s_fbdet_resp, 0, 4), SCHED_END_FRAME(),
563 SCHED_ITEM(l1s_fbdet_resp, 0, 5), SCHED_END_FRAME(),
564 SCHED_ITEM(l1s_fbdet_resp, 0, 6), SCHED_END_FRAME(),
565 SCHED_ITEM(l1s_fbdet_resp, 0, 7), SCHED_END_FRAME(),
566 SCHED_ITEM(l1s_fbdet_resp, 0, 8), SCHED_END_FRAME(),
567 SCHED_ITEM(l1s_fbdet_resp, 0, 9), SCHED_END_FRAME(),
568 SCHED_ITEM(l1s_fbdet_resp, 0, 10), SCHED_END_FRAME(),
569 SCHED_ITEM(l1s_fbdet_resp, 0, 11), SCHED_END_FRAME(),
570 SCHED_ITEM(l1s_fbdet_resp, 0, 12), SCHED_END_FRAME(),
574 void l1s_fb_test(uint8_t base_fn, uint8_t fb_mode)
578 /* schedule the FB detection command */
579 tdma_schedule(base_fn, &l1s_fbdet_cmd, 0, fb_mode, 0);
581 /* schedule 12 attempts to read the result */
582 for (i = 1; i <= 12; i++) {
583 uint8_t fn = base_fn + 1 + i;
584 tdma_schedule(fn, &l1s_fbdet_resp, 0, i, 0);
587 /* use the new scheduler 'set' and simply schedule the whole set */
588 /* WARNING: we cannot set FB_MODE_1 this way !!! */
589 tdma_schedule_set(base_fn, fb_sched_set, 0);
593 /* SCH Burst Detection ********************************************************/
595 /* Note: When we get the SB response, it is 2 TDMA frames after the SB
596 * actually happened, as it is a "C W W R" task */
597 #define SB2_LATENCY 2
599 extern const struct tdma_sched_item rach_sched_set_ul[];
601 static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
602 __unused uint16_t p3)
606 static struct gsm_time sb_time;
607 int qbits, fn_offset;
608 struct l1_cell_info *cinfo = &l1s.serving_cell;
609 int fnr_delta, bits_delta;
610 struct l1ctl_sync_new_ccch_resp *l1;
615 if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
616 /* after 2nd attempt, restart */
620 /* mark READ page as being used */
621 dsp_api.r_page_used = 1;
628 printf("SB%d ", attempt);
629 read_sb_result(dsp_api.frame_ctr);
631 sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16;
632 bsic = l1s_decode_sb(&sb_time, sb);
633 printf("=> SB 0x%08x: BSIC=%u ", sb, bsic);
634 l1s_time_dump(&sb_time);
636 l1s.serving_cell.bsic = bsic;
638 /* calculate synchronisation value (TODO: only complete for qbits) */
640 qbits = last_fb->toa * 4;
641 fn_offset = l1s.current_time.fn; // TODO
643 if (qbits > QBITS_PER_TDMA) {
644 qbits -= QBITS_PER_TDMA;
646 } else if (qbits < 0) {
647 qbits += QBITS_PER_TDMA;
651 fnr_delta = last_fb->fnr_report - attempt;
652 bits_delta = fnr_delta * BITS_PER_TDMA;
654 cinfo->fn_offset = fnr_delta;
655 cinfo->time_alignment = qbits;
656 cinfo->arfcn = rf_arfcn;
658 if (last_fb->toa > bits_delta)
659 printf("=> DSP reports SB in bit that is %d bits in the future?!?\n",
660 last_fb->toa - bits_delta);
662 printf(" qbits=%u\n", qbits);
664 if (l1s.sb.count > 5 && l1s.sb.synced == 0) {
665 synchronize_tdma(&l1s.serving_cell);
669 /* if we have recived a SYNC burst, update our local GSM time */
670 gsm_fn2gsmtime(&l1s.current_time, sb_time.fn + SB2_LATENCY);
671 /* compute next time from new current time */
672 l1s.next_time = l1s.current_time;
673 l1s_time_inc(&l1s.next_time, 1);
675 /* place it in the queue for the layer2 */
676 msg = l1_create_l2_msg(L1CTL_NEW_CCCH_RESP, sb_time.fn, last_fb->snr, rf_arfcn);
677 l1 = (struct l1ctl_sync_new_ccch_resp *) msgb_put(msg, sizeof(*l1));
679 l1_queue_for_l2(msg);
685 If we call tdma_sched_reset(), which is only needed if there are
686 further l1s_sbdet_resp() scheduled, we will bring dsp_api.db_r and
687 dsp_api.db_w out of sync because we changed dsp_api.db_w for l1s_sbdet_cmd()
688 and canceled l1s_sbdet_resp() which would change dsp_api.db_r. The DSP
689 however expects dsp_api.db_w and dsp_api.db_r to be in sync (either
690 "0 - 0" or "1 - 1"). So we have to bring dsp_api.db_w and dsp_api.db_r
691 into sync again, otherwise NB reading will complain. We probably don't
692 need the Abort command and could just bring dsp_api.db_w and dsp_api.db_r
700 if (l1s.sb.count > 10 && sb_time.t3 == 41) {
702 /* enable the MF Task for BCCH reading */
703 l1s.mf_tasks |= (1 << MF_TASK_BCCH_NORM);
704 l1s.mf_tasks |= (1 << MF_TASK_CCCH_COMB);
706 /* We have just seen a SCH burst, we know the next one is not in
707 * less than 7 TDMA frames from now */
714 static int l1s_sbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
715 __unused uint16_t p3)
719 dsp_api.db_w->d_task_md = SB_DSP_TASK;
720 dsp_api.ndb->d_fb_mode = 0; /* wideband search */
724 l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_SB);
730 void l1s_sb_test(uint8_t base_fn)
733 /* This is how it is done by the TSM30 */
734 tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1, 0);
735 tdma_schedule(base_fn + 1, &l1s_sbdet_cmd, 0, 2, 0);
736 tdma_schedule(base_fn + 3, &l1s_sbdet_resp, 0, 1, 0);
737 tdma_schedule(base_fn + 4, &l1s_sbdet_resp, 0, 2, 0);
739 tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1, 0);
740 tdma_schedule(base_fn + 1, &l1s_sbdet_resp, 0, 1, 0);
741 tdma_schedule(base_fn + 2, &l1s_sbdet_resp, 0, 2, 0);
745 /* Power Measurement **********************************************************/
747 /* scheduler callback to issue a power measurement task to the DSP */
748 static int l1s_pm_cmd(__unused uint8_t p1,
749 __unused uint8_t p2, uint16_t arfcn)
753 dsp_api.db_w->d_task_md = 2;
754 dsp_api.ndb->d_fb_mode = 0; /* wideband search */
758 //l1s_rx_win_ctrl(arfcn, L1_RXWIN_PW);
759 l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB);
765 /* scheduler callback to read power measurement resposnse from the DSP */
766 static int l1s_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
769 struct l1ctl_pm_resp *pmr;
770 uint16_t pm_level[2];
771 struct l1_signal sig;
775 l1ddsp_meas_read(2, pm_level);
777 printf("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
778 agc_inp_dbm8_by_pm(pm_level[0])/8,
779 agc_inp_dbm8_by_pm(pm_level[1])/8, arfcn);
781 /* build and deliver signal */
782 sig.signum = L1_SIG_PM;
784 sig.pm.dbm8[0] = agc_inp_dbm8_by_pm(pm_level[0]);
785 sig.pm.dbm8[1] = agc_inp_dbm8_by_pm(pm_level[1]);
791 l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_RESP);
793 if (msgb_tailroom(l1s.pm.msg) < sizeof(*pmr)) {
794 /* flush current msgb */
795 l1_queue_for_l2(l1s.pm.msg);
796 /* allocate a new msgb and initialize header */
797 l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_RESP);
800 pmr = msgb_put(l1s.pm.msg, sizeof(*pmr));
801 pmr->band_arfcn = htons(arfcn);
802 /* FIXME: do this as RxLev rather than DBM8 ? */
803 pmr->pm[0] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[0])/8);
804 pmr->pm[1] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[1])/8);
806 if (l1s.pm.mode == 1) {
807 if (l1s.pm.range.arfcn_next <= l1s.pm.range.arfcn_end) {
808 /* schedule PM for next ARFCN in range */
809 l1s_pm_test(1, l1s.pm.range.arfcn_next);
810 l1s.pm.range.arfcn_next++;
812 /* we have finished, flush the msgb to L2 */
813 struct l1ctl_hdr *l1h = l1s.pm.msg->l1h;
814 l1h->flags |= L1CTL_F_DONE;
815 l1_queue_for_l2(l1s.pm.msg);
823 void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
825 printf("l1s_pm_test(%u, %u)\n", base_fn, arfcn);
826 tdma_schedule(base_fn, &l1s_pm_cmd, 0, 0, arfcn);
827 tdma_schedule(base_fn + 2, &l1s_pm_resp, 0, 0, arfcn);
830 /* Normal Burst ***************************************************************/
832 static int l1s_nb_resp(__unused uint8_t p1, uint8_t burst_id, uint16_t p3)
834 static struct l1_signal _nb_sig, *sig = &_nb_sig;
835 uint8_t mf_task_id = p3 & 0xff;
836 uint8_t mf_task_flags = p3 >> 8;
841 /* just for debugging, d_task_d should not be 0 */
842 if (dsp_api.db_r->d_task_d == 0) {
847 /* DSP burst ID needs to corespond with what we expect */
848 if (dsp_api.db_r->d_burst_d != burst_id) {
849 printf("BURST ID %u!=%u\n", dsp_api.db_r->d_burst_d, burst_id);
853 sig->nb.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
854 sig->nb.meas[burst_id].pm_dbm8 = dsp_api.db_r->a_serv_demod[D_PM] >> 3;
855 sig->nb.meas[burst_id].freq_err = ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
856 sig->nb.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
858 /* feed computed frequency error into AFC loop */
859 if (sig->nb.meas[burst_id].snr > AFC_SNR_THRESHOLD)
860 afc_input(sig->nb.meas[burst_id].freq_err, rf_arfcn, 1);
862 afc_input(sig->nb.meas[burst_id].freq_err, rf_arfcn, 0);
864 /* 4th burst, get frame data */
865 if (dsp_api.db_r->d_burst_d == 3) {
866 struct l1ctl_hdr *l1h;
867 struct l1ctl_info_dl *dl;
868 struct l1ctl_data_ind *di;
869 uint32_t avg_snr = 0;
870 int32_t avg_dbm8 = 0;
873 sig->signum = L1_SIG_NB;
874 sig->nb.num_biterr = dsp_api.ndb->a_cd[2] & 0xffff;
875 sig->nb.crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
876 sig->nb.fire = ((dsp_api.ndb->a_cd[0] & 0xffff) & (1 << B_FIRE1)) >> B_FIRE1;
878 /* copy actual data, skipping the information block [0,1,2] */
879 for (j = 0,i = 3; i < 15; i++) {
880 sig->nb.frame[j++] = dsp_api.ndb->a_cd[i] & 0xFF;
881 sig->nb.frame[j++] = (dsp_api.ndb->a_cd[i] >> 8) & 0xFF;
884 /* actually issue the signal */
888 /* place it in the queue for the layer2 */
889 msg = l1_create_l2_msg(L1CTL_DATA_IND, l1s.current_time.fn-4, last_fb->snr, rf_arfcn);
890 l1h = (struct l1ctl_hdr *) msg->l1h;
891 dl = (struct l1ctl_info_dl *) l1h->data;
892 di = (struct l1ctl_data_ind *) msgb_put(msg, sizeof(*di));
894 /* Set Channel Number depending on MFrame Task ID */
895 dl->chan_nr = mframe_task2chan_nr(mf_task_id, 0); /* FIXME: TS */
897 /* Set SACCH indication in Link IDentifier */
898 if (mf_task_flags & MF_F_SACCH)
903 /* compute average snr and rx level */
904 for (i = 0; i < 4; ++i) {
905 avg_snr += sig->nb.meas[i].snr;
906 avg_dbm8 += sig->nb.meas[i].pm_dbm8;
908 dl->snr = avg_snr / 4;
909 dl->rx_level = (avg_dbm8 / (8*4)) + 110;
911 /* copy the actual payload data */
912 for (i = 0; i < 23; ++i)
913 di->data[i] = sig->nb.frame[i];
914 l1_queue_for_l2(msg);
916 /* clear downlink task */
917 dsp_api.db_w->d_task_d = 0;
920 /* mark READ page as being used */
921 dsp_api.r_page_used = 1;
926 static int l1s_nb_cmd(__unused uint8_t p1, uint8_t burst_id,
927 __unused uint16_t p3)
929 uint8_t tsc = l1s.serving_cell.bsic & 0x7;
932 dsp_load_rx_task(ALLC_DSP_TASK, burst_id, tsc);
935 l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_NB);
941 const struct tdma_sched_item nb_sched_set[] = {
942 SCHED_ITEM(l1s_nb_cmd, 0, 0), SCHED_END_FRAME(),
943 SCHED_ITEM(l1s_nb_cmd, 0, 1), SCHED_END_FRAME(),
944 SCHED_ITEM(l1s_nb_resp, 0, 0), SCHED_ITEM(l1s_nb_cmd, 0, 2), SCHED_END_FRAME(),
945 SCHED_ITEM(l1s_nb_resp, 0, 1), SCHED_ITEM(l1s_nb_cmd, 0, 3), SCHED_END_FRAME(),
946 SCHED_ITEM(l1s_nb_resp, 0, 2), SCHED_END_FRAME(),
947 SCHED_ITEM(l1s_nb_resp, 0, 3), SCHED_END_FRAME(),
952 /* Transmit Burst *************************************************************/
954 const uint8_t ubUui[23] = { 0x01, 0x03, 0x01, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b };
956 /* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
957 static int l1s_tx_resp(__unused uint8_t p1, __unused uint8_t burst_id,
958 __unused uint16_t p3)
962 dsp_api.r_page_used = 1;
967 /* Channel type definitions for DEDICATED mode */
968 #define INVALID_CHANNEL 0
974 /* Channel mode definitions for DEDICATED mode */
975 #define SIG_ONLY_MODE 0 // signalling only
976 #define TCH_FS_MODE 1 // speech full rate
977 #define TCH_HS_MODE 2 // speech half rate
978 #define TCH_96_MODE 3 // data 9,6 kb/s
979 #define TCH_48F_MODE 4 // data 4,8 kb/s full rate
980 #define TCH_48H_MODE 5 // data 4,8 kb/s half rate
981 #define TCH_24F_MODE 6 // data 2,4 kb/s full rate
982 #define TCH_24H_MODE 7 // data 2,4 kb/s half rate
983 #define TCH_EFR_MODE 8 // enhanced full rate
984 #define TCH_144_MODE 9 // data 14,4 kb/s half rate
986 static uint8_t loc_cnt = 0;
988 /* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
989 static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3)
993 uint8_t mf_task_id = p3 & 0xff;
994 uint8_t mf_task_flags = p3 >> 8;
998 /* Load the ApcOffset into the DSP */
1000 dsp_api.ndb->d_apcoff = ABB_VAL(APCOFF, (1 << 6) | MY_OFFSET) | 1; /* 2x slope for the GTA-02 ramp */
1002 /* Load the TX Power into the DSP */
1004 If the power is too low (below 0 dBm) the ramp is not OK,
1005 especially for GSM-1800. However an MS does not send below
1008 dsp_api.db_w->d_power_ctl = ABB_VAL(AUXAPC, 0xC0); /* 2 dBm pulse with offset 4 (GSM-1800) */
1010 /* Update the ramp according to the PCL */
1011 for (i = 0; i < 16; i++)
1012 dsp_api.ndb->a_ramp[i] = ABB_VAL(APCRAM, twl3025_default_ramp[i]);
1014 /* The Ramp Table is sent to ABB only once after RF init routine called */
1015 dsp_api.db_w->d_ctrl_abb |= (1 << B_RAMP) | (1 << B_BULRAMPDEL);
1017 if (p1 == 0) /* DUL_DSP_TASK, one normal burst */
1018 dsp_load_tch_param(0, SIG_ONLY_MODE, INVALID_CHANNEL, 0, 0, 0);
1019 else if (p1 == 2) /* DUL_DSP_TASK, four normal bursts */
1020 dsp_load_tch_param(0, SIG_ONLY_MODE, SDCCH_4, 0, 0, 0);
1022 /* before sending first of the four bursts, copy data to API ram */
1023 if (burst_id == 0) {
1024 if (p1 == 0 || p1 == 2) { // DUL_DSP_TASK
1025 uint16_t *info_ptr = dsp_api.ndb->a_cu;
1026 struct llist_head *tx_queue;
1028 const uint8_t *data;
1031 /* distinguish between DCCH and ACCH */
1032 if (mf_task_flags & MF_F_SACCH) {
1033 puts("SACCH queue ");
1034 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
1036 puts("SDCCH queue ");
1037 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
1039 msg = msgb_dequeue(tx_queue);
1041 /* If the TX queue is empty, send idle pattern */
1043 puts("TX idle pattern\n");
1046 puts("TX uplink msg\n");
1050 /* Fill data block Header */
1051 info_ptr[0] = (1 << B_BLUD); // 1st word: Set B_BLU bit.
1052 info_ptr[1] = 0; // 2nd word: cleared.
1053 info_ptr[2] = 0; // 3rd word: cleared.
1055 /* Copy first 22 bytes in the first 11 words after header. */
1056 for (i=0, j=(3+0); j<(3+11); j++) {
1057 info_ptr[j] = ((uint16_t)(data[i])) | ((uint16_t)(data[i+1]) << 8);
1058 printf("%02x %02x ", data[i], data[i+1]);
1061 /* Copy last UWORD8 (23rd) in the 12th word after header. */
1062 info_ptr[14] = data[22];
1063 printf("%02x\n", data[22]);
1067 } else if (p1 == 1) { // RACH_DSP_TASK
1071 data[0] = l1s.serving_cell.bsic << 2;
1072 data[1] = 0x00 + loc_cnt; // channel request, location update, loc_cnt as random reference
1077 info_ptr = &dsp_api.ndb->d_rach;
1078 info_ptr[0] = ((uint16_t)(data[0])) | ((uint16_t)(data[1])<<8);
1082 if (p1 == 0 || p1 == 2) {
1083 tsc = 7; // !!!!! nanoBTS configuration for SDCCH 0 !!!!!!!!
1085 dsp_load_tx_task(DUL_DSP_TASK, burst_id, tsc);
1088 l1s_tx_win_ctrl(rf_arfcn, L1_TXWIN_NB, 0);
1090 } else if (p1 == 1) {
1091 dsp_api.db_w->d_task_ra = RACH_DSP_TASK;
1094 l1s_tx_win_ctrl(rf_arfcn, L1_TXWIN_AB, 0);
1101 void l1s_tx_test(uint8_t base_fn, uint8_t type)
1103 printf("Starting TX %d\n", type);
1105 if (type == 0) {// one normal burst
1106 tdma_schedule(base_fn, &l1s_tx_cmd, 0, 0, 0);
1107 tdma_schedule(base_fn + 2, &l1s_tx_resp, 0, 0, 0);
1108 } else if (type == 1) { // one RACH burst
1109 tdma_schedule(base_fn, &l1s_tx_cmd, 1, 0, 0);
1110 tdma_schedule(base_fn + 2, &l1s_tx_resp, 1, 0, 0);
1111 } else if (type == 2) { // four normal burst
1112 tdma_schedule(base_fn, &l1s_tx_cmd, 2, 0, 0);
1113 tdma_schedule(base_fn + 1, &l1s_tx_cmd, 2, 1, 0);
1114 tdma_schedule(base_fn + 2, &l1s_tx_resp, 2, 0, 0);
1115 tdma_schedule(base_fn + 2, &l1s_tx_cmd, 2, 2, 0);
1116 tdma_schedule(base_fn + 3, &l1s_tx_resp, 2, 1, 0);
1117 tdma_schedule(base_fn + 3, &l1s_tx_cmd, 2, 3, 0);
1118 tdma_schedule(base_fn + 4, &l1s_tx_resp, 2, 2, 0);
1119 tdma_schedule(base_fn + 5, &l1s_tx_resp, 2, 3, 0);
1123 /* sched sets for uplink */
1124 const struct tdma_sched_item rach_sched_set_ul[] = {
1125 SCHED_ITEM(l1s_tx_cmd, 1, 0), SCHED_END_FRAME(),
1127 SCHED_ITEM(l1s_tx_resp, 1, 0), SCHED_END_FRAME(),
1130 const struct tdma_sched_item nb_sched_set_ul[] = {
1131 SCHED_ITEM(l1s_tx_cmd, 2, 0), SCHED_END_FRAME(),
1132 SCHED_ITEM(l1s_tx_cmd, 2, 1), SCHED_END_FRAME(),
1133 SCHED_ITEM(l1s_tx_resp, 2, 0), SCHED_ITEM(l1s_tx_cmd, 2, 2), SCHED_END_FRAME(),
1134 SCHED_ITEM(l1s_tx_resp, 2, 1), SCHED_ITEM(l1s_tx_cmd, 2, 3), SCHED_END_FRAME(),
1135 SCHED_ITEM(l1s_tx_resp, 2, 2), SCHED_END_FRAME(),
1136 SCHED_ITEM(l1s_tx_resp, 2, 3), SCHED_END_FRAME(),
1141 /* Interrupt handler */
1142 static void frame_irq(__unused enum irq_nr nr)
1147 /* reset the layer1 as part of synchronizing to a new cell */
1148 void l1s_reset(void)
1153 /* reset scheduler and hardware */
1163 for (i = 0; i < ARRAY_SIZE(l1s.tx_queue); i++)
1164 INIT_LLIST_HEAD(&l1s.tx_queue[i]);
1166 sched_gsmtime_init();
1168 /* register FRAME interrupt as FIQ so it can interrupt normal IRQs */
1169 irq_register_handler(IRQ_TPU_FRAME, &frame_irq);
1170 irq_config(IRQ_TPU_FRAME, 1, 1, 0);
1171 irq_enable(IRQ_TPU_FRAME);
1173 /* configure timer 1 to be auto-reload and have a prescale of 12 (13MHz/12 == qbit clock) */
1174 hwtimer_enable(1, 1);
1175 hwtimer_load(1, (1875*4)-1);
1176 hwtimer_config(1, 0, 1);
1177 hwtimer_enable(1, 1);