4a06e04b39b99b476e3123123315997eff6f232a
[osmocom-bb.git] / src / target / firmware / layer1 / l23_api.c
1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
2
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #define DEBUG
24
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <debug.h>
30 #include <byteorder.h>
31
32 #include <osmocore/msgb.h>
33 #include <osmocore/protocol/gsm_04_08.h>
34 #include <comm/sercomm.h>
35
36 #include <layer1/sync.h>
37 #include <layer1/async.h>
38 #include <layer1/mframe_sched.h>
39 #include <layer1/prim.h>
40 #include <layer1/tpu_window.h>
41
42 #include <rf/trf6151.h>
43
44 #include <l1ctl_proto.h>
45
46 /* the size we will allocate struct msgb* for HDLC */
47 #define L3_MSG_HEAD 4
48 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
49
50 void l1_queue_for_l2(struct msgb *msg)
51 {
52         /* forward via serial for now */
53         sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
54 }
55
56 static enum mframe_task chan_nr2mf_task(uint8_t chan_nr)
57 {
58         uint8_t cbits = chan_nr >> 3;
59         uint8_t tn = chan_nr & 0x7;
60         uint8_t lch_idx;
61
62         if (cbits == 0x01) {
63                 lch_idx = 0;
64                 return (tn & 1) ? MF_TASK_TCH_F_ODD : MF_TASK_TCH_F_EVEN;
65         } else if ((cbits & 0x1e) == 0x02) {
66                 lch_idx = cbits & 0x1;
67                 return MF_TASK_TCH_H_0 + lch_idx;
68         } else if ((cbits & 0x1c) == 0x04) {
69                 lch_idx = cbits & 0x3;
70                 return MF_TASK_SDCCH4_0 + lch_idx;
71         } else if ((cbits & 0x18) == 0x08) {
72                 lch_idx = cbits & 0x7;
73                 return MF_TASK_SDCCH8_0 + lch_idx;
74 #if 0
75         } else if (cbits == 0x10) {
76                 /* FIXME: when to do extended BCCH? */
77                 return MF_TASK_BCCH_NORM;
78         } else if (cbits == 0x11 || cbits == 0x12) {
79                 /* FIXME: how to decide CCCH norm/extd? */
80                 return MF_TASK_BCCH_CCCH;
81 #endif
82         }
83         return 0;
84 }
85
86 static int  chan_nr2dchan_type(uint8_t chan_nr)
87 {
88         uint8_t cbits = chan_nr >> 3;
89
90         if (cbits == 0x01) {
91                 return GSM_DCHAN_TCH_F;
92         } else if ((cbits & 0x1e) == 0x02) {
93                 return GSM_DCHAN_TCH_H;
94         } else if ((cbits & 0x1c) == 0x04) {
95                 return GSM_DCHAN_SDCCH_4;
96         } else if ((cbits & 0x18) == 0x08) {
97                 return GSM_DCHAN_SDCCH_8;
98         }
99         return GSM_DCHAN_UNKNOWN;
100 }
101
102 static int chan_nr_is_tch(uint8_t chan_nr)
103 {
104         return ((chan_nr >> 3) == 0x01 ||               /* TCH/F */
105                 ((chan_nr >> 3) & 0x1e) == 0x02);       /* TCH/H */
106 }
107
108 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
109 {
110         struct msgb *msg;
111         struct l1ctl_hdr *l1h;
112
113         msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
114         if (!msg) {
115                 while (1) {
116                         puts("OOPS. Out of buffers...\n");
117                 }
118
119                 return NULL;
120         }
121         l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
122         l1h->msg_type = msg_type;
123         l1h->flags = 0;
124
125         msg->l1h = (uint8_t *)l1h;
126
127         return msg;
128 }
129
130 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
131                               uint16_t arfcn)
132 {
133         struct l1ctl_info_dl *dl;
134         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
135
136         dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
137         dl->frame_nr = htonl(fn);
138         dl->snr = snr;
139         dl->band_arfcn = htons(arfcn);
140
141         return msg;
142 }
143
144 /* receive a L1CTL_FBSB_REQ from L23 */
145 static void l1ctl_rx_fbsb_req(struct msgb *msg)
146 {
147         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
148         struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
149
150         if (sizeof(*sync_req) > msg->len) {
151                 printf("Short sync msg. %u\n", msg->len);
152                 return;
153         }
154
155         printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
156                 ntohs(sync_req->band_arfcn), sync_req->flags);
157
158         /* reset scheduler and hardware */
159         l1s_reset();
160
161         /* pre-set the CCCH mode */
162         l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
163
164         printd("Starting FCCH Recognition\n");
165         l1s_fbsb_req(1, sync_req);
166 }
167
168 /* receive a L1CTL_DM_EST_REQ from L23 */
169 static void l1ctl_rx_dm_est_req(struct msgb *msg)
170 {
171         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
172         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
173         struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
174
175         printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
176                 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
177
178         /* configure dedicated channel state */
179         l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
180         l1s.dedicated.tsc  = est_req->tsc;
181         l1s.dedicated.tn   = ul->chan_nr & 0x7;
182         l1s.dedicated.h    = est_req->h;
183
184         if (est_req->h) {
185                 int i;
186                 l1s.dedicated.h1.hsn  = est_req->h1.hsn;
187                 l1s.dedicated.h1.maio = est_req->h1.maio;
188                 l1s.dedicated.h1.n    = est_req->h1.n;
189                 for (i=0; i<est_req->h1.n; i++)
190                         l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
191         } else {
192                 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
193         }
194
195         /* TCH config */
196         if (chan_nr_is_tch(ul->chan_nr)) {
197                 /* Mode */
198                 l1a_tch_mode_set(est_req->tch_mode);
199
200                 /* Sync */
201                 l1s.tch_sync = 1;       /* can be set without locking */
202         }
203
204         /* figure out which MF tasks to enable */
205         l1a_mftask_set(1 << chan_nr2mf_task(ul->chan_nr));
206 }
207
208 /* receive a L1CTL_DM_FREQ_REQ from L23 */
209 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
210 {
211         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
212         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
213         struct l1ctl_dm_freq_req *freq_req =
214                         (struct l1ctl_dm_freq_req *) ul->payload;
215
216         printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
217                 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
218
219         /* configure dedicated channel state */
220         l1s.dedicated.st_tsc  = freq_req->tsc;
221         l1s.dedicated.st_h    = freq_req->h;
222
223         if (freq_req->h) {
224                 int i;
225                 l1s.dedicated.st_h1.hsn  = freq_req->h1.hsn;
226                 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
227                 l1s.dedicated.st_h1.n    = freq_req->h1.n;
228                 for (i=0; i<freq_req->h1.n; i++)
229                         l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
230         } else {
231                 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
232         }
233
234         l1a_freq_req(ntohs(freq_req->fn));
235 }
236
237 /* receive a L1CTL_CRYPTO_REQ from L23 */
238 static void l1ctl_rx_crypto_req(struct msgb *msg)
239 {
240         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
241         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
242         struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
243         uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
244
245         printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
246
247         if (cr->algo && key_len != 8) {
248                 printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
249                 return;
250         }
251
252         dsp_load_ciph_param(cr->algo, cr->key);
253 }
254
255 /* receive a L1CTL_DM_REL_REQ from L23 */
256 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
257 {
258         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
259         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
260
261         printd("L1CTL_DM_REL_REQ\n");
262         l1a_mftask_set(0);
263         l1s.dedicated.type = GSM_DCHAN_NONE;
264         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
265         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
266         l1a_meas_msgb_set(NULL);
267         dsp_load_ciph_param(0, NULL);
268         l1a_tch_mode_set(GSM48_CMODE_SIGN);
269 }
270
271 /* receive a L1CTL_PARAM_REQ from L23 */
272 static void l1ctl_rx_param_req(struct msgb *msg)
273 {
274         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
275         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
276         struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
277
278         printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
279                 par_req->tx_power);
280
281         l1s.ta = par_req->ta;
282         l1s.tx_power = par_req->tx_power;
283 }
284
285 /* receive a L1CTL_RACH_REQ from L23 */
286 static void l1ctl_rx_rach_req(struct msgb *msg)
287 {
288         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
289         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
290         struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
291
292         printd("L1CTL_RACH_REQ (ra=0x%02x, fn51=%d, mf_off=%d)\n", rach_req->ra, rach_req->fn51, rach_req->mf_off);
293
294         l1a_rach_req(rach_req->fn51, rach_req->mf_off, rach_req->ra);
295 }
296
297 /* receive a L1CTL_DATA_REQ from L23 */
298 static void l1ctl_rx_data_req(struct msgb *msg)
299 {
300         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
301         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
302         struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
303         struct llist_head *tx_queue;
304
305         printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
306
307         msg->l3h = data_ind->data;
308         if (ul->link_id & 0x40) {
309                 struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
310                 if (gh->proto_discr == GSM48_PDISC_RR
311                  && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
312                         printd("updating measurement report\n");
313                         l1a_meas_msgb_set(msg);
314                         return;
315                 }
316                 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
317         } else
318                 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
319
320         printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
321                 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
322
323         l1a_txq_msgb_enq(tx_queue, msg);
324 }
325
326 /* receive a L1CTL_PM_REQ from L23 */
327 static void l1ctl_rx_pm_req(struct msgb *msg)
328 {
329         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
330         struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
331
332         switch (pm_req->type) {
333         case 1:
334                 l1s.pm.mode = 1;
335                 l1s.pm.range.arfcn_start =
336                                 ntohs(pm_req->range.band_arfcn_from);
337                 l1s.pm.range.arfcn_next =
338                                 ntohs(pm_req->range.band_arfcn_from);
339                 l1s.pm.range.arfcn_end =
340                                 ntohs(pm_req->range.band_arfcn_to);
341                 printf("L1CTL_PM_REQ start=%u end=%u\n",
342                         l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
343                 break;
344         }
345
346         l1s_pm_test(1, l1s.pm.range.arfcn_next);
347 }
348
349 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
350 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
351 {
352         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
353         struct l1ctl_reset *reset_resp;
354         reset_resp = (struct l1ctl_reset *)
355                                 msgb_put(msg, sizeof(*reset_resp));
356         reset_resp->type = reset_type;
357
358         l1_queue_for_l2(msg);
359 }
360
361 /* receive a L1CTL_RESET_REQ from L23 */
362 static void l1ctl_rx_reset_req(struct msgb *msg)
363 {
364         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
365         struct l1ctl_reset *reset_req =
366                                 (struct l1ctl_reset *) l1h->data;
367
368         switch (reset_req->type) {
369         case L1CTL_RES_T_FULL:
370                 printf("L1CTL_RESET_REQ: FULL!\n");
371                 l1s_reset();
372                 l1s_reset_hw();
373                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
374                 break;
375         case L1CTL_RES_T_SCHED:
376                 printf("L1CTL_RESET_REQ: SCHED!\n");
377                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
378                 sched_gsmtime_reset();
379                 break;
380         default:
381                 printf("unknown L1CTL_RESET_REQ type\n");
382                 break;
383         }
384 }
385
386 /* Transmit a L1CTL_CCCH_MODE_CONF */
387 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
388 {
389         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
390         struct l1ctl_ccch_mode_conf *mode_conf;
391         mode_conf = (struct l1ctl_ccch_mode_conf *)
392                                 msgb_put(msg, sizeof(*mode_conf));
393         mode_conf->ccch_mode = ccch_mode;
394
395         l1_queue_for_l2(msg);
396 }
397
398 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
399 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
400 {
401         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
402         struct l1ctl_ccch_mode_req *ccch_mode_req =
403                 (struct l1ctl_ccch_mode_req *) l1h->data;
404         uint8_t ccch_mode = ccch_mode_req->ccch_mode;
405
406         /* pre-set the CCCH mode */
407         l1s.serving_cell.ccch_mode = ccch_mode;
408
409         /* Update task */
410         mframe_disable(MF_TASK_CCCH_COMB);
411         mframe_disable(MF_TASK_CCCH);
412
413         if (ccch_mode == CCCH_MODE_COMBINED)
414                 mframe_enable(MF_TASK_CCCH_COMB);
415         else if (ccch_mode == CCCH_MODE_NON_COMBINED)
416                 mframe_enable(MF_TASK_CCCH);
417
418         l1ctl_tx_ccch_mode_conf(ccch_mode);
419 }
420
421 /* Transmit a L1CTL_TCH_MODE_CONF */
422 static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode)
423 {
424         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
425         struct l1ctl_tch_mode_conf *mode_conf;
426         mode_conf = (struct l1ctl_tch_mode_conf *)
427                                 msgb_put(msg, sizeof(*mode_conf));
428         mode_conf->tch_mode = tch_mode;
429
430         l1_queue_for_l2(msg);
431 }
432
433 /* receive a L1CTL_TCH_MODE_REQ from L23 */
434 static void l1ctl_rx_tch_mode_req(struct msgb *msg)
435 {
436         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
437         struct l1ctl_tch_mode_req *tch_mode_req =
438                 (struct l1ctl_tch_mode_req *) l1h->data;
439         uint8_t tch_mode = tch_mode_req->tch_mode;
440
441         printd("L1CTL_TCH_MODE_REQ (mode=0x%02x)\n", tch_mode);
442         tch_mode = l1a_tch_mode_set(tch_mode);
443
444         l1ctl_tx_tch_mode_conf(tch_mode);
445 }
446
447 /* callback from SERCOMM when L2 sends a message to L1 */
448 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
449 {
450         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
451
452 #if 0
453         {
454                 int i;
455                 printf("l1a_l23_rx_cb (%u): ", msg->len);
456                 for (i = 0; i < msg->len; i++)
457                         printf("%02x ", msg->data[i]);
458                 puts("\n");
459         }
460 #endif
461
462         msg->l1h = msg->data;
463
464         if (sizeof(*l1h) > msg->len) {
465                 printf("l1a_l23_cb: Short message. %u\n", msg->len);
466                 goto exit_msgbfree;
467         }
468
469         switch (l1h->msg_type) {
470         case L1CTL_FBSB_REQ:
471                 l1ctl_rx_fbsb_req(msg);
472                 break;
473         case L1CTL_DM_EST_REQ:
474                 l1ctl_rx_dm_est_req(msg);
475                 break;
476         case L1CTL_DM_REL_REQ:
477                 l1ctl_rx_dm_rel_req(msg);
478                 break;
479         case L1CTL_PARAM_REQ:
480                 l1ctl_rx_param_req(msg);
481                 break;
482         case L1CTL_DM_FREQ_REQ:
483                 l1ctl_rx_dm_freq_req(msg);
484                 break;
485         case L1CTL_CRYPTO_REQ:
486                 l1ctl_rx_crypto_req(msg);
487                 break;
488         case L1CTL_RACH_REQ:
489                 l1ctl_rx_rach_req(msg);
490                 break;
491         case L1CTL_DATA_REQ:
492                 l1ctl_rx_data_req(msg);
493                 /* we have to keep the msgb, not free it! */
494                 goto exit_nofree;
495         case L1CTL_PM_REQ:
496                 l1ctl_rx_pm_req(msg);
497                 break;
498         case L1CTL_RESET_REQ:
499                 l1ctl_rx_reset_req(msg);
500                 break;
501         case L1CTL_CCCH_MODE_REQ:
502                 l1ctl_rx_ccch_mode_req(msg);
503                 break;
504         case L1CTL_TCH_MODE_REQ:
505                 l1ctl_rx_tch_mode_req(msg);
506                 break;
507         }
508
509 exit_msgbfree:
510         msgb_free(msg);
511 exit_nofree:
512         return;
513 }
514
515 void l1a_l23api_init(void)
516 {
517         sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
518 }