fw & layer23: Remove limitation about the SDCCH subchannel 4..8
[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 <comm/sercomm.h>
34
35 #include <layer1/sync.h>
36 #include <layer1/async.h>
37 #include <layer1/mframe_sched.h>
38 #include <layer1/tpu_window.h>
39
40 #include <rf/trf6151.h>
41
42 #include <l1ctl_proto.h>
43
44 /* the size we will allocate struct msgb* for HDLC */
45 #define L3_MSG_HEAD 4
46 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
47
48 void l1_queue_for_l2(struct msgb *msg)
49 {
50         /* forward via serial for now */
51         sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
52 }
53
54 static enum mframe_task chan_nr2mf_task(uint8_t chan_nr)
55 {
56         uint8_t cbits = chan_nr >> 3;
57         uint8_t lch_idx;
58
59         if (cbits == 0x01) {
60                 lch_idx = 0;
61                 /* FIXME: TCH/F */
62         } else if ((cbits & 0x1e) == 0x02) {
63                 lch_idx = cbits & 0x1;
64                 /* FIXME: TCH/H */
65         } else if ((cbits & 0x1c) == 0x04) {
66                 lch_idx = cbits & 0x3;
67                 return MF_TASK_SDCCH4_0 + lch_idx;
68         } else if ((cbits & 0x18) == 0x08) {
69                 lch_idx = cbits & 0x7;
70                 return MF_TASK_SDCCH8_0 + lch_idx;
71 #if 0
72         } else if (cbits == 0x10) {
73                 /* FIXME: when to do extended BCCH? */
74                 return MF_TASK_BCCH_NORM;
75         } else if (cbits == 0x11 || cbits == 0x12) {
76                 /* FIXME: how to decide CCCH norm/extd? */
77                 return MF_TASK_BCCH_CCCH;
78 #endif
79         }
80         return 0;
81 }
82
83 static int  chan_nr2dchan_type(uint8_t chan_nr)
84 {
85         uint8_t cbits = chan_nr >> 3;
86
87         if (cbits == 0x01) {
88                 return GSM_DCHAN_TCH_F;
89         } else if ((cbits & 0x1e) == 0x02) {
90                 return GSM_DCHAN_TCH_H;
91         } else if ((cbits & 0x1c) == 0x04) {
92                 return GSM_DCHAN_SDCCH_4;
93         } else if ((cbits & 0x18) == 0x08) {
94                 return GSM_DCHAN_SDCCH_8;
95         }
96         return GSM_DCHAN_UNKNOWN;
97 }
98
99 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
100 {
101         struct msgb *msg;
102         struct l1ctl_hdr *l1h;
103
104         msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
105         if (!msg) {
106                 while (1) {
107                         puts("OOPS. Out of buffers...\n");
108                 }
109
110                 return NULL;
111         }
112         l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
113         l1h->msg_type = msg_type;
114         l1h->flags = 0;
115
116         msg->l1h = (uint8_t *)l1h;
117
118         return msg;
119 }
120
121 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
122                               uint16_t arfcn)
123 {
124         struct l1ctl_info_dl *dl;
125         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
126
127         dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
128         dl->frame_nr = htonl(fn);
129         dl->snr = snr;
130         dl->band_arfcn = htons(arfcn);
131
132         return msg;
133 }
134
135 /* receive a L1CTL_FBSB_REQ from L23 */
136 static void l1ctl_rx_fbsb_req(struct msgb *msg)
137 {
138         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
139         struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
140
141         if (sizeof(*sync_req) > msg->len) {
142                 printf("Short sync msg. %u\n", msg->len);
143                 return;
144         }
145
146         printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
147                 ntohs(sync_req->band_arfcn), sync_req->flags);
148
149         /* reset scheduler and hardware */
150         l1s_reset();
151
152         /* pre-set the CCCH mode */
153         l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
154
155         printd("Starting FCCH Recognition\n");
156         l1s_fbsb_req(1, sync_req);
157 }
158
159 /* receive a L1CTL_DM_EST_REQ from L23 */
160 static void l1ctl_rx_dm_est_req(struct msgb *msg)
161 {
162         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
163         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
164         struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
165
166         printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
167                 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
168
169         /* Current limitations */
170         if ((ul->chan_nr & 0x7) > 4) {
171                 /* FIXME: Timeslot */
172                 puts("We don't support TS > 4 yet\n");
173                 return;
174         }
175
176         /* configure dedicated channel state */
177         l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
178         l1s.dedicated.tsc  = est_req->tsc;
179         l1s.dedicated.tn   = ul->chan_nr & 0x7;
180         l1s.dedicated.h    = est_req->h;
181
182         if (est_req->h) {
183                 int i;
184                 l1s.dedicated.h1.hsn  = est_req->h1.hsn;
185                 l1s.dedicated.h1.maio = est_req->h1.maio;
186                 l1s.dedicated.h1.n    = est_req->h1.n;
187                 for (i=0; i<est_req->h1.n; i++)
188                         l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
189         } else {
190                 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
191         }
192
193         /* figure out which MF tasks to enable */
194         l1a_mftask_set(1 << chan_nr2mf_task(ul->chan_nr));
195 }
196
197 /* receive a L1CTL_DM_FREQ_REQ from L23 */
198 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
199 {
200         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
201         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
202         struct l1ctl_dm_freq_req *freq_req =
203                         (struct l1ctl_dm_freq_req *) ul->payload;
204
205         printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
206                 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
207
208         /* configure dedicated channel state */
209         l1s.dedicated.st_tsc  = freq_req->tsc;
210         l1s.dedicated.st_h    = freq_req->h;
211
212         if (freq_req->h) {
213                 int i;
214                 l1s.dedicated.st_h1.hsn  = freq_req->h1.hsn;
215                 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
216                 l1s.dedicated.st_h1.n    = freq_req->h1.n;
217                 for (i=0; i<freq_req->h1.n; i++)
218                         l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
219         } else {
220                 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
221         }
222
223         l1a_freq_req(ntohs(freq_req->fn));
224 }
225
226 /* receive a L1CTL_CRYPTO_REQ from L23 */
227 static void l1ctl_rx_crypto_req(struct msgb *msg)
228 {
229         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
230         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
231         struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
232         uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
233
234         printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
235
236         // for dieter: (cr->alog, cr->key, key_len);
237
238 }
239
240 /* receive a L1CTL_DM_REL_REQ from L23 */
241 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
242 {
243         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
244         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
245
246         printd("L1CTL_DM_REL_REQ\n");
247         l1a_mftask_set(0);
248         l1s.dedicated.type = GSM_DCHAN_NONE;
249         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
250         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
251 }
252
253 /* receive a L1CTL_RACH_REQ from L23 */
254 static void l1ctl_rx_param_req(struct msgb *msg)
255 {
256         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
257         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
258         struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
259
260         printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
261                 par_req->tx_power);
262
263         l1s.ta = par_req->ta;
264         // FIXME: set power
265 }
266
267 /* receive a L1CTL_RACH_REQ from L23 */
268 static void l1ctl_rx_rach_req(struct msgb *msg)
269 {
270         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
271         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
272         struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
273
274         printd("L1CTL_RACH_REQ (ra=0x%02x, fn51=%d, mf_off=%d)\n", rach_req->ra, rach_req->fn51, rach_req->mf_off);
275
276         l1a_rach_req(rach_req->fn51, rach_req->mf_off, rach_req->ra);
277 }
278
279 /* receive a L1CTL_DATA_REQ from L23 */
280 static void l1ctl_rx_data_req(struct msgb *msg)
281 {
282         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
283         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
284         struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
285         struct llist_head *tx_queue;
286
287         printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
288
289         msg->l3h = data_ind->data;
290         tx_queue = (ul->link_id & 0x40) ?
291                         &l1s.tx_queue[L1S_CHAN_SACCH] :
292                         &l1s.tx_queue[L1S_CHAN_MAIN];
293
294         printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
295                 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
296
297         l1a_txq_msgb_enq(tx_queue, msg);
298 }
299
300 /* receive a L1CTL_PM_REQ from L23 */
301 static void l1ctl_rx_pm_req(struct msgb *msg)
302 {
303         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
304         struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
305
306         switch (pm_req->type) {
307         case 1:
308                 l1s.pm.mode = 1;
309                 l1s.pm.range.arfcn_start =
310                                 ntohs(pm_req->range.band_arfcn_from);
311                 l1s.pm.range.arfcn_next =
312                                 ntohs(pm_req->range.band_arfcn_from);
313                 l1s.pm.range.arfcn_end =
314                                 ntohs(pm_req->range.band_arfcn_to);
315                 printf("L1CTL_PM_REQ start=%u end=%u\n",
316                         l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
317                 break;
318         }
319
320         l1s_pm_test(1, l1s.pm.range.arfcn_next);
321 }
322
323 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
324 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
325 {
326         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
327         struct l1ctl_reset *reset_resp;
328         reset_resp = (struct l1ctl_reset *)
329                                 msgb_put(msg, sizeof(*reset_resp));
330         reset_resp->type = reset_type;
331
332         l1_queue_for_l2(msg);
333 }
334
335 /* receive a L1CTL_RESET_REQ from L23 */
336 static void l1ctl_rx_reset_req(struct msgb *msg)
337 {
338         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
339         struct l1ctl_reset *reset_req =
340                                 (struct l1ctl_reset *) l1h->data;
341
342         switch (reset_req->type) {
343         case L1CTL_RES_T_FULL:
344                 printf("L1CTL_RESET_REQ: FULL!\n");
345                 l1s_reset();
346                 l1s_reset_hw();
347                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
348                 break;
349         case L1CTL_RES_T_SCHED:
350                 printf("L1CTL_RESET_REQ: SCHED!\n");
351                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
352                 sched_gsmtime_reset();
353                 break;
354         default:
355                 printf("unknown L1CTL_RESET_REQ type\n");
356                 break;
357         }
358 }
359
360 /* Transmit a L1CTL_CCCH_MODE_CONF */
361 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
362 {
363         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
364         struct l1ctl_ccch_mode_conf *mode_conf;
365         mode_conf = (struct l1ctl_ccch_mode_conf *)
366                                 msgb_put(msg, sizeof(*mode_conf));
367         mode_conf->ccch_mode = ccch_mode;
368
369         l1_queue_for_l2(msg);
370 }
371
372 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
373 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
374 {
375         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
376         struct l1ctl_ccch_mode_req *ccch_mode_req =
377                 (struct l1ctl_ccch_mode_req *) l1h->data;
378         uint8_t ccch_mode = ccch_mode_req->ccch_mode;
379
380         /* pre-set the CCCH mode */
381         l1s.serving_cell.ccch_mode = ccch_mode;
382
383         /* Update task */
384         mframe_disable(MF_TASK_CCCH_COMB);
385         mframe_disable(MF_TASK_CCCH);
386
387         if (ccch_mode == CCCH_MODE_COMBINED)
388                 mframe_enable(MF_TASK_CCCH_COMB);
389         else if (ccch_mode == CCCH_MODE_NON_COMBINED)
390                 mframe_enable(MF_TASK_CCCH);
391
392         l1ctl_tx_ccch_mode_conf(ccch_mode);
393 }
394
395 /* callback from SERCOMM when L2 sends a message to L1 */
396 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
397 {
398         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
399
400 #if 0
401         {
402                 int i;
403                 printf("l1a_l23_rx_cb (%u): ", msg->len);
404                 for (i = 0; i < msg->len; i++)
405                         printf("%02x ", msg->data[i]);
406                 puts("\n");
407         }
408 #endif
409
410         msg->l1h = msg->data;
411
412         if (sizeof(*l1h) > msg->len) {
413                 printf("l1a_l23_cb: Short message. %u\n", msg->len);
414                 goto exit_msgbfree;
415         }
416
417         switch (l1h->msg_type) {
418         case L1CTL_FBSB_REQ:
419                 l1ctl_rx_fbsb_req(msg);
420                 break;
421         case L1CTL_DM_EST_REQ:
422                 l1ctl_rx_dm_est_req(msg);
423                 break;
424         case L1CTL_DM_REL_REQ:
425                 l1ctl_rx_dm_rel_req(msg);
426                 break;
427         case L1CTL_PARAM_REQ:
428                 l1ctl_rx_param_req(msg);
429                 break;
430         case L1CTL_DM_FREQ_REQ:
431                 l1ctl_rx_dm_freq_req(msg);
432                 break;
433         case L1CTL_CRYPTO_REQ:
434                 l1ctl_rx_crypto_req(msg);
435                 break;
436         case L1CTL_RACH_REQ:
437                 l1ctl_rx_rach_req(msg);
438                 break;
439         case L1CTL_DATA_REQ:
440                 l1ctl_rx_data_req(msg);
441                 /* we have to keep the msgb, not free it! */
442                 goto exit_nofree;
443         case L1CTL_PM_REQ:
444                 l1ctl_rx_pm_req(msg);
445                 break;
446         case L1CTL_RESET_REQ:
447                 l1ctl_rx_reset_req(msg);
448                 break;
449         case L1CTL_CCCH_MODE_REQ:
450                 l1ctl_rx_ccch_mode_req(msg);
451                 break;
452         }
453
454 exit_msgbfree:
455         msgb_free(msg);
456 exit_nofree:
457         return;
458 }
459
460 void l1a_l23api_init(void)
461 {
462         sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
463 }