Merge commit '7f6615a37df0dadbe86fdfc980e0a8a15013a80e'
[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 <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>
43
44 #include <rffe.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>
54
55 #include <l1ctl_proto.h>
56
57
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)
64 {
65         uint8_t tn = chan_nr & 0x07;
66         uint8_t cbits = chan_nr >> 3;
67
68         *tch_f_hn = (cbits & 2) ? 0 : 1;
69
70         if (*tch_f_hn) {
71                 *fn_report = (time->fn - (tn * 13) + 104) % 104;
72                 *tch_sub = 0;
73         } else {
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;
77                 *tch_sub = chan_sub;
78         }
79
80         if (tch_mode) {
81                 switch (l1s.tch_mode) {
82                 case GSM48_CMODE_SPEECH_V1:
83                         *tch_mode = *tch_f_hn ? TCH_FS_MODE : TCH_HS_MODE;
84                         break;
85                 case GSM48_CMODE_SPEECH_EFR:
86                         *tch_mode = *tch_f_hn ? TCH_EFR_MODE : SIG_ONLY_MODE;
87                         break;
88                 default:
89                         *tch_mode = SIG_ONLY_MODE;
90                 }
91         }
92 }
93
94
95 /* -------------------------------------------------------------------------
96  * Shared completion handler
97  * ------------------------------------------------------------------------- */
98
99 /*
100  * FIXME We really need a better way to handle completion, where we can
101  *       pass arguments and such ...
102  *
103  *       Right now, we just 'hope' it gets processed before the next one ...
104  */
105
106 static uint16_t last_tx_tch_fn;
107
108 static void l1a_tx_tch_compl(__unused enum l1_compl c)
109 {
110         struct msgb *msg;
111
112         msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_tx_tch_fn, 0, 0);
113         l1_queue_for_l2(msg);
114 }
115
116 static __attribute__ ((constructor)) void prim_tch_init(void)
117 {
118         l1s.completion[L1_COMPL_TX_TCH]  = &l1a_tx_tch_compl;
119 }
120
121
122 /* -------------------------------------------------------------------------
123  * TCH: Voice & FACCH
124  * ------------------------------------------------------------------------- */
125
126 /*
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.
131  */
132
133
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];
137 };
138
139 static struct l1s_rx_tch_state rx_tch;
140
141
142 static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
143 {
144         static uint8_t meas_id = 0;
145         uint8_t mf_task_id = p3 & 0xff;
146         struct gsm_time rx_time;
147         uint8_t chan_nr;
148         uint16_t arfcn;
149         uint8_t tsc, tn;
150         uint8_t tch_f_hn, tch_sub;
151         uint32_t fn_report;
152         int facch_rx_now, traffic_rx_now;
153
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);
159
160         meas_id = (meas_id + 1) % FACCH_MEAS_HIST; /* absolute value doesn't matter */
161
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];
169
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);
173         else
174                 afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 0);
175
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);
178
179         /* FACCH Block end ? */
180         if (tch_f_hn) {
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;
183         } else {
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) ||
187                                (t2_norm == 23) ||
188                                (t2_norm ==  6);
189         }
190
191         if (facch_rx_now && (dsp_api.ndb->a_fd[0] & (1<<B_BLUD))) {
192                 struct msgb *msg;
193                 struct l1ctl_info_dl *dl;
194                 struct l1ctl_data_ind *di;
195                 uint16_t num_biterr;
196                 uint32_t avg_snr = 0;
197                 int32_t avg_dbm8 = 0;
198                 int i, n;
199
200                 /* Allocate msgb */
201                         /* FIXME: we actually want all allocation out of L1S! */
202                 msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
203                 if(!msg) {
204                         printf("TCH FACCH: unable to allocate msgb\n");
205                         goto skip;
206                 }
207
208                 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
209                 di = (struct l1ctl_data_ind *) msgb_put(msg, sizeof(*di));
210
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);
216
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;
223                 }
224
225                 dl->snr = avg_snr / n;
226                 dl->rx_level = (avg_dbm8 / (8*n)) + 110;
227
228                 /* Errors & CRC status */
229                 num_biterr = dsp_api.ndb->a_fd[2] & 0xffff;
230                 if (num_biterr > 0xff)
231                         dl->num_biterr = 0xff;
232                 else
233                         dl->num_biterr = num_biterr;
234
235                 dl->fire_crc = ((dsp_api.ndb->a_fd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
236
237                 /* Update rx level for pm report */
238                 pu_update_rx_level(dl->rx_level);
239
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);
242
243                 /* Give message to up layer */
244                 l1_queue_for_l2(msg);
245
246         skip:
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;
251
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;
255
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;
259         }
260
261         /* Traffic now ? */
262         if (tch_f_hn) {
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;
265         } else {
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;
269         }
270
271         if (traffic_rx_now) {
272                 volatile uint16_t *traffic_buf;
273
274                 traffic_buf = tch_sub ? dsp_api.ndb->a_dd_1 : dsp_api.ndb->a_dd_0;
275
276                 if (traffic_buf[0] & (1<<B_BLUD)) {
277                         /* Reset traffic buffer header in NDB (needed by DSP) */
278                         traffic_buf[0] = 0;
279                         traffic_buf[2] = 0xffff;
280                 }
281         }
282
283         /* mark READ page as being used */
284         dsp_api.r_page_used = 1;
285
286         return 0;
287 }
288
289 static int l1s_tch_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
290 {
291         uint8_t mf_task_id = p3 & 0xff;
292         uint8_t chan_nr;
293         uint16_t arfcn;
294         uint8_t tsc, tn;
295         uint8_t tch_f_hn, tch_sub, tch_mode;
296         uint32_t fn_report;
297         uint8_t sync = 0;
298         static int icnt;
299         int facch_tx_now;
300
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);
305
306         /* Sync & FACCH delay */
307         if (l1s.tch_sync) {
308                 l1s.tch_sync = 0;
309                 sync = 1;
310                 icnt = 0;
311         } else if (icnt <= 26)
312                 icnt++;
313
314         /* Load FACCH data if we start a new burst */
315         /* (the DSP wants the data on the CMD of the burst _preceding_ the
316          * first burst) */
317         if (tch_f_hn) {
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;
320         } else {
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) ||
324                                (t2_norm ==  6) ||
325                                (t2_norm == 15);
326         }
327
328         if (facch_tx_now) {
329                 uint16_t *info_ptr = dsp_api.ndb->a_fu;
330                 struct msgb *msg;
331                 const uint8_t *data;
332
333                 /* Pull FACCH data (if ready) */
334                 if (icnt > 26)
335                         msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]);
336                 else
337                         msg = NULL;
338
339                 /* If TX is empty and we're signalling only, use dummy frame */
340                 if (msg)
341                         data = msg->l3h;
342                 else if (tch_mode == SIG_ONLY_MODE)
343                         data = pu_get_idle_frame();
344                 else
345                         data = NULL;
346
347                 /* Do we really send something ? */
348                 if (data) {
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. */
353
354                         /* Copy the actual data after the header */
355                         dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
356                 }
357
358                 /* Indicate completion (FIXME: early but easier this way for now) */
359                 if (msg) {
360                         last_tx_tch_fn = l1s.next_time.fn;
361                         l1s_compl_sched(L1_COMPL_TX_TCH);
362                 }
363
364                 /* Free msg now that we're done with it */
365                 if (msg)
366                         msgb_free(msg);
367         }
368
369         /* Configure DSP for TX/RX */
370         l1s_tx_apc_helper(arfcn);
371
372         dsp_load_tch_param(
373                 &l1s.next_time,
374                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
375                 0, sync, tn
376         );
377
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);
380
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);
383
384         return 0;
385 }
386
387
388 const struct tdma_sched_item tch_sched_set[] = {
389         SCHED_ITEM_DT(l1s_tch_cmd, 0, 0, 0),    SCHED_END_FRAME(),
390                                                 SCHED_END_FRAME(),
391         SCHED_ITEM(l1s_tch_resp, 0, 0, -4),     SCHED_END_FRAME(),
392         SCHED_END_SET()
393 };
394
395
396 /* -------------------------------------------------------------------------
397  * TCH/H: Dummy
398  * ------------------------------------------------------------------------- */
399
400 /* This task is needed to perform some operation in the DSP when there is
401  * no data to be exchanged */
402
403 static int l1s_tch_d_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
404 {
405         /* mark READ page as being used */
406         dsp_api.r_page_used = 1;
407
408         return 0;
409 }
410
411 static int l1s_tch_d_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
412 {
413         uint8_t mf_task_id = p3 & 0xff;
414         uint8_t chan_nr;
415         uint8_t tsc, tn;
416         uint8_t tch_f_hn, tch_sub, tch_mode;
417         uint32_t fn_report;
418
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);
423
424         /* Configure DSP */
425         dsp_load_tch_param(
426                 &l1s.next_time,
427                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
428                 0, 0, tn
429         );
430
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 */
433
434         return 0;
435 }
436
437 const struct tdma_sched_item tch_d_sched_set[] = {
438         SCHED_ITEM_DT(l1s_tch_d_cmd, 0, 0, 0),  SCHED_END_FRAME(),
439                                                 SCHED_END_FRAME(),
440         SCHED_ITEM(l1s_tch_d_resp, 0, 0, -4),   SCHED_END_FRAME(),
441         SCHED_END_SET()
442 };
443
444
445 /* -------------------------------------------------------------------------
446  * TCH: SACCH
447  * ------------------------------------------------------------------------- */
448
449 /*
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
452  * set.
453  * Therefore, the task code itself decides in which burst it is, if it's the
454  * start/end, and act appropriately.
455  */
456
457
458 struct l1s_rx_tch_a_state {
459         struct l1s_meas_hdr meas[4];
460
461         struct msgb *msg;
462         struct l1ctl_info_dl *dl;
463         struct l1ctl_data_ind *di;
464 };
465
466 static struct l1s_rx_tch_a_state rx_tch_a;
467
468
469 static int l1s_tch_a_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
470 {
471         uint8_t mf_task_id = p3 & 0xff;
472         struct gsm_time rx_time;
473         uint8_t chan_nr;
474         uint16_t arfcn;
475         uint8_t tsc, tn;
476         uint8_t tch_f_hn, tch_sub;
477         uint32_t fn_report;
478         uint8_t burst_id;
479
480         /* It may happen we've never gone through cmd(0) yet, skip until then */
481         if (!rx_tch_a.msg)
482                 goto skip;
483
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;
490
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];
498
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);
502         else
503                 afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 0);
504
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);
507
508         /* Last burst, read data & send to the up layer */
509         if ((burst_id == 3) && (dsp_api.ndb->a_cd[0] & (1<<B_BLUD))) {
510                 unsigned int i;
511                 uint16_t num_biterr;
512                 uint32_t avg_snr = 0;
513                 int32_t avg_dbm8 = 0;
514
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;
519                 }
520                 rx_tch_a.dl->snr = avg_snr / 4;
521                 rx_tch_a.dl->rx_level = (avg_dbm8 / (8*4)) + 110;
522
523                 num_biterr = dsp_api.ndb->a_cd[2];
524                 if (num_biterr > 0xff)
525                         rx_tch_a.dl->num_biterr = 0xff;
526                 else
527                         rx_tch_a.dl->num_biterr = num_biterr;
528
529                 rx_tch_a.dl->fire_crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
530
531                 /* Update rx level for pm report */
532                 pu_update_rx_level(rx_tch_a.dl->rx_level);
533
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);
536
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;
540
541                 /* Reset header */
542                 dsp_api.ndb->a_cd[0] = (1<<B_FIRE1);
543                 dsp_api.ndb->a_cd[2] = 0xffff;
544         }
545
546 skip:
547         /* mark READ page as being used */
548         dsp_api.r_page_used = 1;
549
550         return 0;
551 }
552
553 static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
554 {
555         uint8_t mf_task_id = p3 & 0xff;
556         uint8_t chan_nr;
557         uint16_t arfcn;
558         uint8_t tsc, tn;
559         uint8_t tch_f_hn, tch_sub, tch_mode;
560         uint32_t fn_report;
561         uint8_t burst_id;
562
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;
568
569         /* Load SACCH data if we start a new burst */
570         if (burst_id == 0) {
571                 uint16_t *info_ptr = dsp_api.ndb->a_cu;
572                 struct msgb *msg;
573                 const uint8_t *data;
574
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();
578
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. */
583
584                 /* Copy the actual data after the header */
585                 dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
586
587                 /* Indicate completion (FIXME: early but easier this way for now) */
588                 if (msg) {
589                         last_tx_tch_fn = l1s.next_time.fn;
590                         l1s_compl_sched(L1_COMPL_TX_TCH);
591                 }
592
593                 /* Free msg now that we're done with it */
594                 if (msg)
595                         msgb_free(msg);
596         }
597
598         /* Allocate RX burst */
599         if (burst_id == 0) {
600                 /* Clear 'dangling' msgb */
601                 if (rx_tch_a.msg) {
602                         /* Can happen if the task was shutdown in the middle of
603                          * 4 bursts ... */
604                         msgb_free(rx_tch_a.msg);
605                 }
606
607                 /* Allocate burst */
608                         /* FIXME: we actually want all allocation out of L1S! */
609                 rx_tch_a.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
610                 if (!rx_tch_a.msg)
611                         printf("tch_a_cmd(0): unable to allocate msgb\n");
612
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));
615
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);
621         }
622
623         /* Configure DSP for TX/RX */
624         l1s_tx_apc_helper(arfcn);
625
626         dsp_load_tch_param(
627                 &l1s.next_time,
628                 tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
629                 0, 0, tn
630         );
631
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);
634
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);
637
638         return 0;
639 }
640
641
642 const struct tdma_sched_item tch_a_sched_set[] = {
643         SCHED_ITEM_DT(l1s_tch_a_cmd, 0, 0, 0),  SCHED_END_FRAME(),
644                                                 SCHED_END_FRAME(),
645         SCHED_ITEM(l1s_tch_a_resp, 0, 0, -4),   SCHED_END_FRAME(),
646         SCHED_END_SET()
647 };