3 /* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
4 * (C) 2010 by Sylvain Munaut <tnt@246tnt.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <byteorder.h>
33 #include <osmocore/gsm_utils.h>
34 #include <osmocore/protocol/gsm_04_08.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>
45 #include <layer1/sync.h>
46 #include <layer1/afc.h>
47 #include <layer1/agc.h>
48 #include <layer1/tdma_sched.h>
49 #include <layer1/mframe_sched.h>
50 #include <layer1/tpu_window.h>
51 #include <layer1/l23_api.h>
52 #include <layer1/rfch.h>
53 #include <layer1/prim.h>
55 #include <l1ctl_proto.h>
58 /* This computes various parameters both for the DSP and for
59 * our logic. Not all are used all the time, but it's easier
60 * to build all in one place */
61 static void tch_get_params(struct gsm_time *time, uint8_t chan_nr,
62 uint32_t *fn_report, uint8_t *tch_f_hn,
63 uint8_t *tch_sub, uint8_t *tch_mode)
65 uint8_t tn = chan_nr & 0x07;
66 uint8_t cbits = chan_nr >> 3;
68 *tch_f_hn = (cbits & 2) ? 0 : 1;
71 *fn_report = (time->fn - (tn * 13) + 104) % 104;
74 uint8_t chan_sub = cbits & 1;
75 uint8_t tn_report = (tn & ~1) | chan_sub;
76 *fn_report = (time->fn - (tn_report * 13) + 104) % 104;
81 switch (l1s.tch_mode) {
82 case GSM48_CMODE_SPEECH_V1:
83 *tch_mode = *tch_f_hn ? TCH_FS_MODE : TCH_HS_MODE;
85 case GSM48_CMODE_SPEECH_EFR:
86 *tch_mode = *tch_f_hn ? TCH_EFR_MODE : SIG_ONLY_MODE;
89 *tch_mode = SIG_ONLY_MODE;
95 /* -------------------------------------------------------------------------
96 * Shared completion handler
97 * ------------------------------------------------------------------------- */
100 * FIXME We really need a better way to handle completion, where we can
101 * pass arguments and such ...
103 * Right now, we just 'hope' it gets processed before the next one ...
106 static uint16_t last_tx_tch_fn;
108 static void l1a_tx_tch_compl(__unused enum l1_compl c)
112 msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_tx_tch_fn, 0, 0);
113 l1_queue_for_l2(msg);
116 static __attribute__ ((constructor)) void prim_tch_init(void)
118 l1s.completion[L1_COMPL_TX_TCH] = &l1a_tx_tch_compl;
122 /* -------------------------------------------------------------------------
124 * ------------------------------------------------------------------------- */
127 * Voice and FACCH data are spread in various ways depending on a lot of
128 * factors. Trying to handle that with the mframe scheduler is just a mess,
129 * so we schedule it burst by burst and handle the complex logic inside the
130 * primitive task code itself.
134 #define FACCH_MEAS_HIST 8 /* Up to 8 bursts history */
135 struct l1s_rx_tch_state {
136 struct l1s_meas_hdr meas[FACCH_MEAS_HIST];
139 static struct l1s_rx_tch_state rx_tch;
142 static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
144 static uint8_t meas_id = 0;
145 uint8_t mf_task_id = p3 & 0xff;
146 struct gsm_time rx_time;
150 uint8_t tch_f_hn, tch_sub;
152 int facch_rx_now, traffic_rx_now;
154 /* Get/compute various parameters */
155 gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
156 rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
157 chan_nr = mframe_task2chan_nr(mf_task_id, tn);
158 tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
160 meas_id = (meas_id + 1) % FACCH_MEAS_HIST; /* absolute value doesn't matter */
162 /* Collect measurements */
163 rx_tch.meas[meas_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
164 rx_tch.meas[meas_id].pm_dbm8 =
165 agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
166 rx_tch.meas[meas_id].freq_err =
167 ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
168 rx_tch.meas[meas_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
170 /* feed computed frequency error into AFC loop */
171 if (rx_tch.meas[meas_id].snr > AFC_SNR_THRESHOLD)
172 afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 1);
174 afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 0);
176 /* Tell the RF frontend to set the gain appropriately */
177 rffe_set_gain(rx_tch.meas[meas_id].pm_dbm8 / 8, CAL_DSP_TGT_BB_LVL);
179 /* FACCH Block end ? */
181 /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13) */
182 facch_rx_now = ((rx_time.fn % 13) % 4) == 3;
184 /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
185 uint8_t t2_norm = rx_time.t2 - tch_sub;
186 facch_rx_now = (t2_norm == 15) ||
191 if (facch_rx_now && (dsp_api.ndb->a_fd[0] & (1<<B_BLUD))) {
193 struct l1ctl_info_dl *dl;
194 struct l1ctl_data_ind *di;
196 uint32_t avg_snr = 0;
197 int32_t avg_dbm8 = 0;
201 /* FIXME: we actually want all allocation out of L1S! */
202 msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
204 printf("TCH FACCH: unable to allocate msgb\n");
208 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
209 di = (struct l1ctl_data_ind *) msgb_put(msg, sizeof(*di));
211 /* Fill DL header (should be about the first burst ... here is the last) */
212 dl->chan_nr = chan_nr;
213 dl->link_id = 0x00; /* FACCH */
214 dl->band_arfcn = htons(arfcn);
215 dl->frame_nr = htonl(rx_time.fn);
217 /* Average SNR & RX level */
218 n = tch_f_hn ? 8 : 6;
219 for (i=0; i<n; i++) {
220 int j = (meas_id + FACCH_MEAS_HIST - i) % FACCH_MEAS_HIST;
221 avg_snr += rx_tch.meas[j].snr;
222 avg_dbm8 += rx_tch.meas[j].pm_dbm8;
225 dl->snr = avg_snr / n;
226 dl->rx_level = (avg_dbm8 / (8*n)) + 110;
228 /* Errors & CRC status */
229 num_biterr = dsp_api.ndb->a_fd[2] & 0xffff;
230 if (num_biterr > 0xff)
231 dl->num_biterr = 0xff;
233 dl->num_biterr = num_biterr;
235 dl->fire_crc = ((dsp_api.ndb->a_fd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
237 /* Update rx level for pm report */
238 pu_update_rx_level(dl->rx_level);
240 /* Copy actual data, skipping the information block [0,1,2] */
241 dsp_memcpy_from_api(di->data, &dsp_api.ndb->a_fd[3], 23, 0);
243 /* Give message to up layer */
244 l1_queue_for_l2(msg);
247 /* Reset A_FD header (needed by DSP) */
248 /* B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 */
249 dsp_api.ndb->a_fd[0] = (1<<B_FIRE1);
250 dsp_api.ndb->a_fd[2] = 0xffff;
252 /* Reset A_DD_0 header in NDB (needed by DSP) */
253 dsp_api.ndb->a_dd_0[0] = 0;
254 dsp_api.ndb->a_dd_0[2] = 0xffff;
256 /* Reset A_DD_1 header in NDB (needed by DSP) */
257 dsp_api.ndb->a_dd_1[0] = 0;
258 dsp_api.ndb->a_dd_1[2] = 0xffff;
263 /* TCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13)*/
264 traffic_rx_now = ((rx_time.fn % 13) % 4) == 3;
266 /* TCH/H0: B0(0,2,4,6),B1(4,6,8,10),B2(8,10,0,2) (mod 13) */
267 /* H1: B0(1,3,5,7),B1(5,7,9,11),B2(9,11,1,3) (mod 13) */
268 traffic_rx_now = (((rx_time.fn - tch_sub + 13) % 13) % 4) == 2;
271 if (traffic_rx_now) {
272 volatile uint16_t *traffic_buf;
274 traffic_buf = tch_sub ? dsp_api.ndb->a_dd_1 : dsp_api.ndb->a_dd_0;
276 if (traffic_buf[0] & (1<<B_BLUD)) {
277 /* Reset traffic buffer header in NDB (needed by DSP) */
279 traffic_buf[2] = 0xffff;
283 /* mark READ page as being used */
284 dsp_api.r_page_used = 1;
289 static int l1s_tch_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
291 uint8_t mf_task_id = p3 & 0xff;
295 uint8_t tch_f_hn, tch_sub, tch_mode;
301 /* Get/compute various parameters */
302 rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
303 chan_nr = mframe_task2chan_nr(mf_task_id, tn);
304 tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
306 /* Sync & FACCH delay */
311 } else if (icnt <= 26)
314 /* Load FACCH data if we start a new burst */
315 /* (the DSP wants the data on the CMD of the burst _preceding_ the
318 /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) */
319 facch_tx_now = ((l1s.next_time.fn % 13) % 4) == 3;
321 /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
322 uint8_t t2_norm = l1s.next_time.t2 - tch_sub;
323 facch_tx_now = (t2_norm == 23) ||
329 uint16_t *info_ptr = dsp_api.ndb->a_fu;
333 /* Pull FACCH data (if ready) */
335 msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]);
339 /* If TX is empty and we're signalling only, use dummy frame */
342 else if (tch_mode == SIG_ONLY_MODE)
343 data = pu_get_idle_frame();
347 /* Do we really send something ? */
349 /* Fill data block header */
350 info_ptr[0] = (1 << B_BLUD); /* 1st word: Set B_BLU bit. */
351 info_ptr[1] = 0; /* 2nd word: cleared. */
352 info_ptr[2] = 0; /* 3nd word: cleared. */
354 /* Copy the actual data after the header */
355 dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
358 /* Indicate completion (FIXME: early but easier this way for now) */
360 last_tx_tch_fn = l1s.next_time.fn;
361 l1s_compl_sched(L1_COMPL_TX_TCH);
364 /* Free msg now that we're done with it */
369 /* Configure DSP for TX/RX */
370 l1s_tx_apc_helper(arfcn);
374 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
378 dsp_load_rx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
379 l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
381 dsp_load_tx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
382 l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3);
388 const struct tdma_sched_item tch_sched_set[] = {
389 SCHED_ITEM_DT(l1s_tch_cmd, 0, 0, 0), SCHED_END_FRAME(),
391 SCHED_ITEM(l1s_tch_resp, 0, 0, -4), SCHED_END_FRAME(),
396 /* -------------------------------------------------------------------------
398 * ------------------------------------------------------------------------- */
400 /* This task is needed to perform some operation in the DSP when there is
401 * no data to be exchanged */
403 static int l1s_tch_d_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
405 /* mark READ page as being used */
406 dsp_api.r_page_used = 1;
411 static int l1s_tch_d_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
413 uint8_t mf_task_id = p3 & 0xff;
416 uint8_t tch_f_hn, tch_sub, tch_mode;
419 /* Get/compute various parameters */
420 rfch_get_params(&l1s.next_time, NULL, &tsc, &tn);
421 chan_nr = mframe_task2chan_nr(mf_task_id, tn);
422 tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
427 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
431 dsp_load_rx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
432 dsp_load_tx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
437 const struct tdma_sched_item tch_d_sched_set[] = {
438 SCHED_ITEM_DT(l1s_tch_d_cmd, 0, 0, 0), SCHED_END_FRAME(),
440 SCHED_ITEM(l1s_tch_d_resp, 0, 0, -4), SCHED_END_FRAME(),
445 /* -------------------------------------------------------------------------
447 * ------------------------------------------------------------------------- */
450 * SACCH data are spread over 4 bursts, however they are so far appart that
451 * we can't use the normal scheduler to schedule all them at once in a single
453 * Therefore, the task code itself decides in which burst it is, if it's the
454 * start/end, and act appropriately.
458 struct l1s_rx_tch_a_state {
459 struct l1s_meas_hdr meas[4];
462 struct l1ctl_info_dl *dl;
463 struct l1ctl_data_ind *di;
466 static struct l1s_rx_tch_a_state rx_tch_a;
469 static int l1s_tch_a_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
471 uint8_t mf_task_id = p3 & 0xff;
472 struct gsm_time rx_time;
476 uint8_t tch_f_hn, tch_sub;
480 /* It may happen we've never gone through cmd(0) yet, skip until then */
484 /* Get/compute various parameters */
485 gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
486 rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
487 chan_nr = mframe_task2chan_nr(mf_task_id, tn);
488 tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
489 burst_id = (fn_report - 12) / 26;
491 /* Collect measurements */
492 rx_tch_a.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
493 rx_tch_a.meas[burst_id].pm_dbm8 =
494 agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
495 rx_tch_a.meas[burst_id].freq_err =
496 ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
497 rx_tch_a.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
499 /* feed computed frequency error into AFC loop */
500 if (rx_tch_a.meas[burst_id].snr > AFC_SNR_THRESHOLD)
501 afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 1);
503 afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 0);
505 /* Tell the RF frontend to set the gain appropriately */
506 rffe_set_gain(rx_tch_a.meas[burst_id].pm_dbm8 / 8, CAL_DSP_TGT_BB_LVL);
508 /* Last burst, read data & send to the up layer */
509 if ((burst_id == 3) && (dsp_api.ndb->a_cd[0] & (1<<B_BLUD))) {
512 uint32_t avg_snr = 0;
513 int32_t avg_dbm8 = 0;
515 /* Average SNR & RX level + error & crc status */
516 for (i=0; i<4; i++) {
517 avg_snr += rx_tch_a.meas[i].snr;
518 avg_dbm8 += rx_tch_a.meas[i].pm_dbm8;
520 rx_tch_a.dl->snr = avg_snr / 4;
521 rx_tch_a.dl->rx_level = (avg_dbm8 / (8*4)) + 110;
523 num_biterr = dsp_api.ndb->a_cd[2];
524 if (num_biterr > 0xff)
525 rx_tch_a.dl->num_biterr = 0xff;
527 rx_tch_a.dl->num_biterr = num_biterr;
529 rx_tch_a.dl->fire_crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
531 /* Update rx level for pm report */
532 pu_update_rx_level(rx_tch_a.dl->rx_level);
534 /* Copy actual data, skipping the information block [0,1,2] */
535 dsp_memcpy_from_api(rx_tch_a.di->data, &dsp_api.ndb->a_cd[3], 23, 0);
537 /* Give message to up layer */
538 l1_queue_for_l2(rx_tch_a.msg);
539 rx_tch_a.msg = NULL; rx_tch_a.dl = NULL; rx_tch_a.di = NULL;
542 dsp_api.ndb->a_cd[0] = (1<<B_FIRE1);
543 dsp_api.ndb->a_cd[2] = 0xffff;
547 /* mark READ page as being used */
548 dsp_api.r_page_used = 1;
553 static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
555 uint8_t mf_task_id = p3 & 0xff;
559 uint8_t tch_f_hn, tch_sub, tch_mode;
563 /* Get/compute various parameters */
564 rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
565 chan_nr = mframe_task2chan_nr(mf_task_id, tn);
566 tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
567 burst_id = (fn_report - 12) / 26;
569 /* Load SACCH data if we start a new burst */
571 uint16_t *info_ptr = dsp_api.ndb->a_cu;
575 /* If the TX queue is empty, send dummy measurement */
576 msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_SACCH]);
577 data = msg ? msg->l3h : pu_get_meas_frame();
579 /* Fill data block header */
580 info_ptr[0] = (1 << B_BLUD); /* 1st word: Set B_BLU bit. */
581 info_ptr[1] = 0; /* 2nd word: cleared. */
582 info_ptr[2] = 0; /* 3nd word: cleared. */
584 /* Copy the actual data after the header */
585 dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
587 /* Indicate completion (FIXME: early but easier this way for now) */
589 last_tx_tch_fn = l1s.next_time.fn;
590 l1s_compl_sched(L1_COMPL_TX_TCH);
593 /* Free msg now that we're done with it */
598 /* Allocate RX burst */
600 /* Clear 'dangling' msgb */
602 /* Can happen if the task was shutdown in the middle of
604 msgb_free(rx_tch_a.msg);
608 /* FIXME: we actually want all allocation out of L1S! */
609 rx_tch_a.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
611 printf("tch_a_cmd(0): unable to allocate msgb\n");
613 rx_tch_a.dl = (struct l1ctl_info_dl *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.dl));
614 rx_tch_a.di = (struct l1ctl_data_ind *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.di));
616 /* Pre-fill DL header with some info about burst(0) */
617 rx_tch_a.dl->chan_nr = chan_nr;
618 rx_tch_a.dl->link_id = 0x40; /* SACCH */
619 rx_tch_a.dl->band_arfcn = htons(arfcn);
620 rx_tch_a.dl->frame_nr = htonl(l1s.next_time.fn);
623 /* Configure DSP for TX/RX */
624 l1s_tx_apc_helper(arfcn);
628 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
632 dsp_load_rx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
633 l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
635 dsp_load_tx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
636 l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3);
642 const struct tdma_sched_item tch_a_sched_set[] = {
643 SCHED_ITEM_DT(l1s_tch_a_cmd, 0, 0, 0), SCHED_END_FRAME(),
645 SCHED_ITEM(l1s_tch_a_resp, 0, 0, -4), SCHED_END_FRAME(),