fw/prim_tch: Add support for sending traffic frames to l23 (TRAFFIC_IND)
[osmocom-bb.git] / src / target / firmware / layer1 / prim_tch.c
1 /* Layer 1 - TCH */
2
3 /* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
4  * (C) 2010 by Sylvain Munaut <tnt@246tnt.com>
5  *
6  * All Rights Reserved
7  *
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.
12  *
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.
17  *
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.
21  *
22  */
23
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include <defines.h>
30 #include <debug.h>
31 #include <memory.h>
32 #include <byteorder.h>
33 #include <osmocom/gsm/gsm_utils.h>
34 #include <osmocom/gsm/protocol/gsm_04_08.h>
35 #include <osmocom/core/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>
43
44 #include <rffe.h>
45 #include <layer1/sync.h>
46 #include <layer1/afc.h>
47 #include <layer1/agc.h>
48 #include <layer1/toa.h>
49 #include <layer1/tdma_sched.h>
50 #include <layer1/mframe_sched.h>
51 #include <layer1/tpu_window.h>
52 #include <layer1/l23_api.h>
53 #include <layer1/rfch.h>
54 #include <layer1/prim.h>
55
56 #include <l1ctl_proto.h>
57
58
59 /* This computes various parameters both for the DSP and for
60  * our logic. Not all are used all the time, but it's easier
61  * to build all in one place */
62 static void tch_get_params(struct gsm_time *time, uint8_t chan_nr,
63                            uint32_t *fn_report, uint8_t *tch_f_hn,
64                            uint8_t *tch_sub, uint8_t *tch_mode)
65 {
66         uint8_t tn = chan_nr & 0x07;
67         uint8_t cbits = chan_nr >> 3;
68
69         *tch_f_hn = (cbits & 2) ? 0 : 1;
70
71         if (*tch_f_hn) {
72                 *fn_report = (time->fn - (tn * 13) + 104) % 104;
73                 *tch_sub = 0;
74         } else {
75                 uint8_t chan_sub = cbits & 1;
76                 uint8_t tn_report = (tn & ~1) | chan_sub;
77                 *fn_report = (time->fn - (tn_report * 13) + 104) % 104;
78                 *tch_sub = chan_sub;
79         }
80
81         if (tch_mode) {
82                 switch (l1s.tch_mode) {
83                 case GSM48_CMODE_SPEECH_V1:
84                         *tch_mode = *tch_f_hn ? TCH_FS_MODE : TCH_HS_MODE;
85                         break;
86                 case GSM48_CMODE_SPEECH_EFR:
87                         *tch_mode = *tch_f_hn ? TCH_EFR_MODE : SIG_ONLY_MODE;
88                         break;
89                 default:
90                         *tch_mode = SIG_ONLY_MODE;
91                 }
92         }
93 }
94
95
96 /* -------------------------------------------------------------------------
97  * Shared completion handler
98  * ------------------------------------------------------------------------- */
99
100 /*
101  * FIXME We really need a better way to handle completion, where we can
102  *       pass arguments and such ...
103  *
104  *       Right now, we just 'hope' it gets processed before the next one ...
105  */
106
107 static uint16_t last_tx_tch_fn;
108
109 static void l1a_tx_tch_compl(__unused enum l1_compl c)
110 {
111         struct msgb *msg;
112
113         msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_tx_tch_fn, 0, 0);
114         l1_queue_for_l2(msg);
115 }
116
117 static __attribute__ ((constructor)) void prim_tch_init(void)
118 {
119         l1s.completion[L1_COMPL_TX_TCH]  = &l1a_tx_tch_compl;
120 }
121
122
123 /* -------------------------------------------------------------------------
124  * TCH: Voice & FACCH
125  * ------------------------------------------------------------------------- */
126
127 /*
128  * Voice and FACCH data are spread in various ways depending on a lot of
129  * factors. Trying to handle that with the mframe scheduler is just a mess,
130  * so we schedule it burst by burst and handle the complex logic inside the
131  * primitive task code itself.
132  */
133
134
135 #define FACCH_MEAS_HIST 8       /* Up to 8 bursts history */
136 struct l1s_rx_tch_state {
137         struct l1s_meas_hdr meas[FACCH_MEAS_HIST];
138 };
139
140 static struct l1s_rx_tch_state rx_tch;
141
142
143 static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
144 {
145         static uint8_t meas_id = 0;
146         uint8_t mf_task_id = p3 & 0xff;
147         struct gsm_time rx_time;
148         uint8_t chan_nr;
149         uint16_t arfcn;
150         uint8_t tsc, tn;
151         uint8_t tch_f_hn, tch_sub;
152         uint32_t fn_report;
153         int facch_rx_now, traffic_rx_now;
154
155         /* Get/compute various parameters */
156         gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
157         rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
158         chan_nr = mframe_task2chan_nr(mf_task_id, tn);
159         tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
160
161         meas_id = (meas_id + 1) % FACCH_MEAS_HIST; /* absolute value doesn't matter */
162
163         /* Collect measurements */
164         rx_tch.meas[meas_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
165         rx_tch.meas[meas_id].pm_dbm8 =
166                 agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
167         rx_tch.meas[meas_id].freq_err =
168                 ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
169         rx_tch.meas[meas_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
170
171         /* feed computed frequency error into AFC loop */
172         if (rx_tch.meas[meas_id].snr > AFC_SNR_THRESHOLD)
173                 afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 1);
174         else
175                 afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 0);
176
177         /* feed computed TOA into TA loop */
178         toa_input(rx_tch.meas[meas_id].toa_qbit << 2, rx_tch.meas[meas_id].snr);
179
180         /* Tell the RF frontend to set the gain appropriately */
181         rffe_compute_gain(rx_tch.meas[meas_id].pm_dbm8 / 8,
182                 CAL_DSP_TGT_BB_LVL);
183
184         /* FACCH Block end ? */
185         if (tch_f_hn) {
186                 /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13) */
187                 facch_rx_now = ((rx_time.fn % 13) % 4) == 3;
188         } else {
189                 /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
190                 uint8_t t2_norm = rx_time.t2 - tch_sub;
191                 facch_rx_now = (t2_norm == 15) ||
192                                (t2_norm == 23) ||
193                                (t2_norm ==  6);
194         }
195
196         if (facch_rx_now && (dsp_api.ndb->a_fd[0] & (1<<B_BLUD))) {
197                 struct msgb *msg;
198                 struct l1ctl_info_dl *dl;
199                 struct l1ctl_data_ind *di;
200                 uint16_t num_biterr;
201                 uint32_t avg_snr = 0;
202                 int32_t avg_dbm8 = 0;
203                 int i, n;
204
205                 /* Allocate msgb */
206                         /* FIXME: we actually want all allocation out of L1S! */
207                 msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
208                 if(!msg) {
209                         printf("TCH FACCH: unable to allocate msgb\n");
210                         goto skip_rx_facch;
211                 }
212
213                 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
214                 di = (struct l1ctl_data_ind *) msgb_put(msg, sizeof(*di));
215
216                 /* Fill DL header (should be about the first burst ... here is the last) */
217                 dl->chan_nr = chan_nr;
218                 dl->link_id = 0x00;     /* FACCH */
219                 dl->band_arfcn = htons(arfcn);
220                 dl->frame_nr = htonl(rx_time.fn);
221
222                 /* Average SNR & RX level */
223                 n = tch_f_hn ? 8 : 6;
224                 for (i=0; i<n; i++) {
225                         int j = (meas_id + FACCH_MEAS_HIST - i) % FACCH_MEAS_HIST;
226                         avg_snr += rx_tch.meas[j].snr;
227                         avg_dbm8 += rx_tch.meas[j].pm_dbm8;
228                 }
229
230                 dl->snr = avg_snr / n;
231                 dl->rx_level = dbm2rxlev(avg_dbm8 / (8*n));
232
233                 /* Errors & CRC status */
234                 num_biterr = dsp_api.ndb->a_fd[2] & 0xffff;
235                 if (num_biterr > 0xff)
236                         dl->num_biterr = 0xff;
237                 else
238                         dl->num_biterr = num_biterr;
239
240                 dl->fire_crc = ((dsp_api.ndb->a_fd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
241
242                 /* Update rx level for pm report */
243                 pu_update_rx_level(dl->rx_level);
244
245                 /* Copy actual data, skipping the information block [0,1,2] */
246                 dsp_memcpy_from_api(di->data, &dsp_api.ndb->a_fd[3], 23, 0);
247
248                 /* Give message to up layer */
249                 l1_queue_for_l2(msg);
250
251         skip_rx_facch:
252                 /* Reset A_FD header (needed by DSP) */
253                 /* B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 */
254                 dsp_api.ndb->a_fd[0] = (1<<B_FIRE1);
255                 dsp_api.ndb->a_fd[2] = 0xffff;
256
257                 /* Reset A_DD_0 header in NDB (needed by DSP) */
258                 dsp_api.ndb->a_dd_0[0] = 0;
259                 dsp_api.ndb->a_dd_0[2] = 0xffff;
260
261                 /* Reset A_DD_1 header in NDB (needed by DSP) */
262                 dsp_api.ndb->a_dd_1[0] = 0;
263                 dsp_api.ndb->a_dd_1[2] = 0xffff;
264         }
265
266         /* Traffic now ? */
267         if (tch_f_hn) {
268                 /* TCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13)*/
269                 traffic_rx_now = ((rx_time.fn % 13) % 4) == 3;
270         } else {
271                 /* TCH/H0: B0(0,2,4,6),B1(4,6,8,10),B2(8,10,0,2) (mod 13) */
272                 /*     H1: B0(1,3,5,7),B1(5,7,9,11),B2(9,11,1,3) (mod 13) */
273                 traffic_rx_now = (((rx_time.fn - tch_sub + 13) % 13) % 4) == 2;
274         }
275
276         if (traffic_rx_now) {
277                 volatile uint16_t *traffic_buf;
278
279                 traffic_buf = tch_sub ? dsp_api.ndb->a_dd_1 : dsp_api.ndb->a_dd_0;
280
281                 if (traffic_buf[0] & (1<<B_BLUD)) {
282                         /* Send the data to upper layers (if interested and good frame) */
283                         if ((l1s.audio_mode & AUDIO_RX_TRAFFIC_IND) &&
284                             !(dsp_api.ndb->a_dd_0[0] & (1<<B_BFI))) {
285                                 struct msgb *msg;
286                                 struct l1ctl_info_dl *dl;
287                                 struct l1ctl_traffic_ind *ti;
288
289                                 /* Allocate msgb */
290                                 /* FIXME: we actually want all allocation out of L1S! */
291                                 msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND);
292                                 if(!msg) {
293                                         printf("TCH traffic: unable to allocate msgb\n");
294                                         goto skip_rx_traffic;
295                                 }
296
297                                 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
298                                 ti = (struct l1ctl_traffic_ind *) msgb_put(msg, sizeof(*ti));
299
300                                 /* Copy actual data, skipping the information block [0,1,2] */
301                                 dsp_memcpy_from_api(ti->data, &traffic_buf[3], 33, 1);
302
303                                 /* Give message to up layer */
304                                 l1_queue_for_l2(msg);
305                         }
306
307         skip_rx_traffic:
308                         /* Reset traffic buffer header in NDB (needed by DSP) */
309                         traffic_buf[0] = 0;
310                         traffic_buf[2] = 0xffff;
311                 }
312         }
313
314         /* mark READ page as being used */
315         dsp_api.r_page_used = 1;
316
317         return 0;
318 }
319
320 static int l1s_tch_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
321 {
322         uint8_t mf_task_id = p3 & 0xff;
323         uint8_t chan_nr;
324         uint16_t arfcn;
325         uint8_t tsc, tn;
326         uint8_t tch_f_hn, tch_sub, tch_mode;
327         uint32_t fn_report;
328         uint8_t sync = 0;
329         static int icnt;
330         int facch_tx_now;
331
332         /* Get/compute various parameters */
333         rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
334         chan_nr = mframe_task2chan_nr(mf_task_id, tn);
335         tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
336
337         /* Sync & FACCH delay */
338         if (l1s.tch_sync) {
339                 l1s.tch_sync = 0;
340                 sync = 1;
341                 icnt = 0;
342         } else if (icnt <= 26)
343                 icnt++;
344
345         /* Load FACCH data if we start a new burst */
346         /* (the DSP wants the data on the CMD of the burst _preceding_ the
347          * first burst) */
348         if (tch_f_hn) {
349                 /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) */
350                 facch_tx_now = ((l1s.next_time.fn % 13) % 4) == 3;
351         } else {
352                 /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
353                 uint8_t t2_norm = l1s.next_time.t2 - tch_sub;
354                 facch_tx_now = (t2_norm == 23) ||
355                                (t2_norm ==  6) ||
356                                (t2_norm == 15);
357         }
358
359         if (facch_tx_now) {
360                 uint16_t *info_ptr = dsp_api.ndb->a_fu;
361                 struct msgb *msg;
362                 const uint8_t *data;
363
364                 /* Pull FACCH data (if ready) */
365                 if (icnt > 26)
366                         msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]);
367                 else
368                         msg = NULL;
369
370                 /* If TX is empty and we're signalling only, use dummy frame */
371                 if (msg)
372                         data = msg->l3h;
373                 else if (tch_mode == SIG_ONLY_MODE)
374                         data = pu_get_idle_frame();
375                 else
376                         data = NULL;
377
378                 /* Do we really send something ? */
379                 if (data) {
380                         /* Fill data block header */
381                         info_ptr[0] = (1 << B_BLUD);    /* 1st word: Set B_BLU bit. */
382                         info_ptr[1] = 0;                /* 2nd word: cleared. */
383                         info_ptr[2] = 0;                /* 3nd word: cleared. */
384
385                         /* Copy the actual data after the header */
386                         dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
387                 }
388
389                 /* Indicate completion (FIXME: early but easier this way for now) */
390                 if (msg) {
391                         last_tx_tch_fn = l1s.next_time.fn;
392                         l1s_compl_sched(L1_COMPL_TX_TCH);
393                 }
394
395                 /* Free msg now that we're done with it */
396                 if (msg)
397                         msgb_free(msg);
398         }
399
400         /* Configure DSP for TX/RX */
401         l1s_tx_apc_helper(arfcn);
402
403         dsp_load_tch_param(
404                 &l1s.next_time,
405                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
406                 0, sync, tn
407         );
408
409         dsp_load_rx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
410         l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
411
412         dsp_load_tx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
413         l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3);
414
415         return 0;
416 }
417
418
419 const struct tdma_sched_item tch_sched_set[] = {
420         SCHED_ITEM_DT(l1s_tch_cmd, 0, 0, 0),    SCHED_END_FRAME(),
421                                                 SCHED_END_FRAME(),
422         SCHED_ITEM(l1s_tch_resp, 0, 0, -4),     SCHED_END_FRAME(),
423         SCHED_END_SET()
424 };
425
426
427 /* -------------------------------------------------------------------------
428  * TCH/H: Dummy
429  * ------------------------------------------------------------------------- */
430
431 /* This task is needed to perform some operation in the DSP when there is
432  * no data to be exchanged */
433
434 static int l1s_tch_d_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
435 {
436         /* mark READ page as being used */
437         dsp_api.r_page_used = 1;
438
439         return 0;
440 }
441
442 static int l1s_tch_d_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
443 {
444         uint8_t mf_task_id = p3 & 0xff;
445         uint8_t chan_nr;
446         uint8_t tsc, tn;
447         uint8_t tch_f_hn, tch_sub, tch_mode;
448         uint32_t fn_report;
449
450         /* Get/compute various parameters */
451         rfch_get_params(&l1s.next_time, NULL, &tsc, &tn);
452         chan_nr = mframe_task2chan_nr(mf_task_id, tn);
453         tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
454
455         /* Configure DSP */
456         dsp_load_tch_param(
457                 &l1s.next_time,
458                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
459                 0, 0, tn
460         );
461
462         dsp_load_rx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
463         dsp_load_tx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
464
465         return 0;
466 }
467
468 const struct tdma_sched_item tch_d_sched_set[] = {
469         SCHED_ITEM_DT(l1s_tch_d_cmd, 0, 0, 0),  SCHED_END_FRAME(),
470                                                 SCHED_END_FRAME(),
471         SCHED_ITEM(l1s_tch_d_resp, 0, 0, -4),   SCHED_END_FRAME(),
472         SCHED_END_SET()
473 };
474
475
476 /* -------------------------------------------------------------------------
477  * TCH: SACCH
478  * ------------------------------------------------------------------------- */
479
480 /*
481  * SACCH data are spread over 4 bursts, however they are so far appart that
482  * we can't use the normal scheduler to schedule all them at once in a single
483  * set.
484  * Therefore, the task code itself decides in which burst it is, if it's the
485  * start/end, and act appropriately.
486  */
487
488
489 struct l1s_rx_tch_a_state {
490         struct l1s_meas_hdr meas[4];
491
492         struct msgb *msg;
493         struct l1ctl_info_dl *dl;
494         struct l1ctl_data_ind *di;
495 };
496
497 static struct l1s_rx_tch_a_state rx_tch_a;
498
499
500 static int l1s_tch_a_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
501 {
502         uint8_t mf_task_id = p3 & 0xff;
503         struct gsm_time rx_time;
504         uint8_t chan_nr;
505         uint16_t arfcn;
506         uint8_t tsc, tn;
507         uint8_t tch_f_hn, tch_sub;
508         uint32_t fn_report;
509         uint8_t burst_id;
510
511         /* It may happen we've never gone through cmd(0) yet, skip until then */
512         if (!rx_tch_a.msg)
513                 goto skip;
514
515         /* Get/compute various parameters */
516         gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
517         rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
518         chan_nr = mframe_task2chan_nr(mf_task_id, tn);
519         tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
520         burst_id = (fn_report - 12) / 26;
521
522         /* Collect measurements */
523         rx_tch_a.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
524         rx_tch_a.meas[burst_id].pm_dbm8 =
525                 agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
526         rx_tch_a.meas[burst_id].freq_err =
527                 ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
528         rx_tch_a.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
529
530         /* feed computed frequency error into AFC loop */
531         if (rx_tch_a.meas[burst_id].snr > AFC_SNR_THRESHOLD)
532                 afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 1);
533         else
534                 afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 0);
535
536         /* feed computed TOA into TA loop */
537         toa_input(rx_tch_a.meas[burst_id].toa_qbit << 2, rx_tch_a.meas[burst_id].snr);
538
539         /* Tell the RF frontend to set the gain appropriately */
540         rffe_compute_gain(rx_tch_a.meas[burst_id].pm_dbm8 / 8,
541                 CAL_DSP_TGT_BB_LVL);
542
543         /* Last burst, read data & send to the up layer */
544         if ((burst_id == 3) && (dsp_api.ndb->a_cd[0] & (1<<B_BLUD))) {
545                 unsigned int i;
546                 uint16_t num_biterr;
547                 uint32_t avg_snr = 0;
548                 int32_t avg_dbm8 = 0;
549
550                 /* Average SNR & RX level + error & crc status */
551                 for (i=0; i<4; i++) {
552                         avg_snr += rx_tch_a.meas[i].snr;
553                         avg_dbm8 += rx_tch_a.meas[i].pm_dbm8;
554                 }
555                 rx_tch_a.dl->snr = avg_snr / 4;
556                 rx_tch_a.dl->rx_level = dbm2rxlev(avg_dbm8 / (8*4));
557
558                 num_biterr = dsp_api.ndb->a_cd[2];
559                 if (num_biterr > 0xff)
560                         rx_tch_a.dl->num_biterr = 0xff;
561                 else
562                         rx_tch_a.dl->num_biterr = num_biterr;
563
564                 rx_tch_a.dl->fire_crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
565
566                 /* Update rx level for pm report */
567                 pu_update_rx_level(rx_tch_a.dl->rx_level);
568
569                 /* Copy actual data, skipping the information block [0,1,2] */
570                 dsp_memcpy_from_api(rx_tch_a.di->data, &dsp_api.ndb->a_cd[3], 23, 0);
571
572                 /* Give message to up layer */
573                 l1_queue_for_l2(rx_tch_a.msg);
574                 rx_tch_a.msg = NULL; rx_tch_a.dl = NULL; rx_tch_a.di = NULL;
575
576                 /* Reset header */
577                 dsp_api.ndb->a_cd[0] = (1<<B_FIRE1);
578                 dsp_api.ndb->a_cd[2] = 0xffff;
579         }
580
581 skip:
582         /* mark READ page as being used */
583         dsp_api.r_page_used = 1;
584
585         return 0;
586 }
587
588 static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
589 {
590         uint8_t mf_task_id = p3 & 0xff;
591         uint8_t chan_nr;
592         uint16_t arfcn;
593         uint8_t tsc, tn;
594         uint8_t tch_f_hn, tch_sub, tch_mode;
595         uint32_t fn_report;
596         uint8_t burst_id;
597
598         /* Get/compute various parameters */
599         rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
600         chan_nr = mframe_task2chan_nr(mf_task_id, tn);
601         tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
602         burst_id = (fn_report - 12) / 26;
603
604         /* Load SACCH data if we start a new burst */
605         if (burst_id == 0) {
606                 uint16_t *info_ptr = dsp_api.ndb->a_cu;
607                 struct msgb *msg;
608                 const uint8_t *data;
609
610                 /* If the TX queue is empty, send dummy measurement */
611                 msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_SACCH]);
612                 data = msg ? msg->l3h : pu_get_meas_frame();
613
614                 /* Fill data block header */
615                 info_ptr[0] = (1 << B_BLUD);    /* 1st word: Set B_BLU bit. */
616                 info_ptr[1] = 0;                /* 2nd word: cleared. */
617                 info_ptr[2] = 0;                /* 3nd word: cleared. */
618
619                 /* Copy the actual data after the header */
620                 dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
621
622                 /* Indicate completion (FIXME: early but easier this way for now) */
623                 if (msg) {
624                         last_tx_tch_fn = l1s.next_time.fn;
625                         l1s_compl_sched(L1_COMPL_TX_TCH);
626                 }
627
628                 /* Free msg now that we're done with it */
629                 if (msg)
630                         msgb_free(msg);
631         }
632
633         /* Allocate RX burst */
634         if (burst_id == 0) {
635                 /* Clear 'dangling' msgb */
636                 if (rx_tch_a.msg) {
637                         /* Can happen if the task was shutdown in the middle of
638                          * 4 bursts ... */
639                         msgb_free(rx_tch_a.msg);
640                 }
641
642                 /* Allocate burst */
643                         /* FIXME: we actually want all allocation out of L1S! */
644                 rx_tch_a.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
645                 if (!rx_tch_a.msg)
646                         printf("tch_a_cmd(0): unable to allocate msgb\n");
647
648                 rx_tch_a.dl = (struct l1ctl_info_dl *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.dl));
649                 rx_tch_a.di = (struct l1ctl_data_ind *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.di));
650
651                 /* Pre-fill DL header with some info about burst(0) */
652                 rx_tch_a.dl->chan_nr = chan_nr;
653                 rx_tch_a.dl->link_id = 0x40;    /* SACCH */
654                 rx_tch_a.dl->band_arfcn = htons(arfcn);
655                 rx_tch_a.dl->frame_nr = htonl(l1s.next_time.fn);
656         }
657
658         /* Configure DSP for TX/RX */
659         l1s_tx_apc_helper(arfcn);
660
661         dsp_load_tch_param(
662                 &l1s.next_time,
663                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
664                 0, 0, tn
665         );
666
667         dsp_load_rx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
668         l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
669
670         dsp_load_tx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
671         l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3);
672
673         return 0;
674 }
675
676
677 const struct tdma_sched_item tch_a_sched_set[] = {
678         SCHED_ITEM_DT(l1s_tch_a_cmd, 0, 0, 0),  SCHED_END_FRAME(),
679                                                 SCHED_END_FRAME(),
680         SCHED_ITEM(l1s_tch_a_resp, 0, 0, -4),   SCHED_END_FRAME(),
681         SCHED_END_SET()
682 };