Inter-Layer intergration work
[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 #include <stdint.h>
24 #include <stdio.h>
25
26 #include <comm/msgb.h>
27 #include <comm/sercomm.h>
28
29 #include <layer1/sync.h>
30 #include <layer1/async.h>
31 #include <layer1/mframe_sched.h>
32
33 #include <l1a_l23_interface.h>
34
35 /* the size we will allocate struct msgb* for HDLC */
36 #define L3_MSG_SIZE (sizeof(struct l1ctl_data_ind) + 4)
37 #define L3_MSG_HEAD 4
38
39 void l1_queue_for_l2(struct msgb *msg)
40 {
41         /* forward via serial for now */
42         sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
43 }
44
45 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr)
46 {
47         struct l1ctl_info_dl *dl;
48         struct msgb *msg;
49
50         msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1_burst");
51         if (!msg) {
52                 while (1) {
53                         puts("OOPS. Out of buffers...\n");
54                 }
55
56                 return NULL;
57         }
58
59         dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
60         dl->msg_type = msg_type;
61         /* FIXME: we may want to compute T1/T2/T3 in L23 */
62         gsm_fn2gsmtime(&dl->time, fn);
63         dl->snr[0] = snr;
64
65         return msg;
66 }
67
68 /* callbakc from SERCOMM when L2 sends a message to L1 */
69 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
70 {
71         struct l1ctl_info_ul *ul = msg->data;
72         struct l1ctl_sync_new_ccch_req *sync_req;
73         struct l1ctl_rach_req *rach_req;
74         struct l1ctl_dedic_mode_est_req *est_req;
75         struct l1ctl_data_ind *data_ind;
76         struct llist_head *tx_queue;
77
78         if (sizeof(*ul) > msg->len) {
79                 printf("l1a_l23_cb: Short message. %u\n", msg->len);
80                 goto exit;
81         }
82
83         switch (ul->msg_type) {
84         case L1CTL_NEW_CCCH_REQ:
85                 if (sizeof(*ul) + sizeof(*sync_req) > msg->len) {
86                         printf("Short sync msg. %u\n", msg->len);
87                         break;
88                 }
89
90                 sync_req = (struct l1ctl_sync_new_ccch_req *) (&msg->data[0] + sizeof(*ul));
91                 printf("Asked to tune to frequency: %u\n", sync_req->band_arfcn);
92
93                 /* reset scheduler and hardware */
94                 tdma_sched_reset();
95                 l1s_dsp_abort();
96
97                 /* tune to specified frequency */
98                 trf6151_rx_window(0, sync_req->band_arfcn, 40, 0);
99                 tpu_end_scenario();
100
101                 puts("Starting FCCH Recognition\n");
102                 l1s_fb_test(1, 0);
103                 break;
104         case L1CTL_DM_EST_REQ:
105                 est_req = (struct l1ctl_dm_est_req *) ul->payload;
106                 /* FIXME: ARFCN */
107                 /* FIXME: Timeslot */
108                 /* figure out which MF tasks to enable, depending on channel number */
109                 l1s.mf_tasks = (1 << MF_TASK_SDCCH4_0);
110                 break;
111         case L1CTL_RACH_REQ:
112                 puts("CCCH_RACH_REQ\n");
113                 rach_req = (struct l1ctl_rach_req *) ul->payload;
114                 l1a_rach_req(27, rach_req->ra);
115                 break;
116         case L1CTL_DATA_REQ:
117                 puts("DEDIC_MODE_DATA_REQ\n");
118                 data_ind = (struct l1ctl_data_ind *) ul->payload;
119                 if (ul->link_id & 0x40)
120                         tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
121                 else
122                         tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
123                 msg->l3h = data_ind->data;
124                 l1a_txq_msgb_enq(tx_queue, msg);
125                 break;
126         }
127
128 exit:
129         msgb_free(msg);
130 }
131
132 void l1a_l23api_init(void)
133 {
134         sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
135 }