add an actual Layer1 asynchronous (L1A) API that can be called from higher layers
authorHarald Welte <laforge@gnumonks.org>
Sun, 28 Feb 2010 13:31:06 +0000 (14:31 +0100)
committerHarald Welte <laforge@gnumonks.org>
Mon, 1 Mar 2010 22:48:45 +0000 (23:48 +0100)
include/l1a_l23_interface.h
src/target/firmware/apps/layer1/main.c
src/target/firmware/include/layer1/l23_api.h
src/target/firmware/include/layer1/sync.h
src/target/firmware/layer1/Makefile
src/target/firmware/layer1/async.c [new file with mode: 0644]
src/target/firmware/layer1/init.c
src/target/firmware/layer1/l23_api.c

index fc03d72..6e94ebc 100644 (file)
@@ -80,6 +80,7 @@ struct l1_info_ul {
        uint8_t tx_power;
        uint8_t channel_number;
        uint32_t tdma_frame;
+       uint8_t payload[0];
 } __attribute__((packed));
 
 /*
index 6e4d981..6247543 100644 (file)
@@ -78,7 +78,6 @@ static void l1s_signal_cb(struct l1_signal *sig)
 }
 
 static void key_handler(enum key_codes code, enum key_states state);
-static void la1_l23_rx_cb(uint8_t dlci, struct msgb *msg);
 
 int main(void)
 {
@@ -99,8 +98,6 @@ int main(void)
        st7558_set_attr(DISP_ATTR_INVERT);
        st7558_puts("layer1.bin");
 
-       sercomm_register_rx_cb(SC_DLCI_L1A_L23, la1_l23_rx_cb);
-
        layer1_init();
        l1s_set_handler(&l1s_signal_cb);
 
@@ -185,41 +182,4 @@ static void key_handler(enum key_codes code, enum key_states state)
        }
 }
 
-static void la1_l23_rx_cb(uint8_t dlci, struct msgb *msg)
-{
-       struct l1_info_ul *ul = msg->data;
-       struct l1_sync_new_ccch_req *sync_req;
-
-       if (sizeof(*ul) > msg->len) {
-               printf("la1_l23_cb: Short message. %u\n", msg->len);
-               goto exit;
-       }
-
-       switch (ul->msg_type) {
-       case SYNC_NEW_CCCH_REQ:
-               if (sizeof(*ul) + sizeof(*sync_req) > msg->len) {
-                       printf("Short sync msg. %u\n", msg->len);
-                       break;
-               }
-
-               sync_req = (struct l1_sync_new_ccch_req *) (&msg->data[0] + sizeof(*ul));
-               printf("Asked to tune to frequency: %u\n", sync_req->band_arfcn);
-
-               /* reset scheduler and hardware */
-               tdma_sched_reset();
-               l1s_dsp_abort();
 
-               /* tune to specified frequency */
-               trf6151_rx_window(0, sync_req->band_arfcn, 40, 0);
-               tpu_end_scenario();
-
-               puts("Starting FCCH Recognition\n");
-               l1s_fb_test(1, 0);
-               break;
-       case DEDIC_MODE_EST_REQ:
-               break;
-       }
-
-exit:
-       msgb_free(msg);
-}
index a03c59c..826f82e 100644 (file)
@@ -5,6 +5,7 @@
 #include <comm/msgb.h>
 #include <l1a_l23_interface.h>
 
+void l1a_l23api_init(void);
 void l1_queue_for_l2(struct msgb *msg);
 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr);
 
index a50969b..901ff9d 100644 (file)
@@ -36,6 +36,10 @@ struct l1s_state {
 
        /* bit-mask of multi-frame tasks that are currently active */
        uint32_t        mf_tasks;
+
+       struct {
+               uint8_t         ra;
+       } rach;
 };
 
 extern struct l1s_state l1s;
index d04573e..3963958 100644 (file)
@@ -3,7 +3,7 @@ INCLUDES=-I../include/ -I../../../../include
 
 LIBNAME=layer1
 OBJS=avg.o agc.o afc.o sync.o gsm.o tdma_sched.o tpu_window.o init.o l23_api.o \
-       mframe_sched.o sched_gsmtime.o
+       mframe_sched.o sched_gsmtime.o async.o
 
 LST=$(OBJS:.o=.lst)
 
diff --git a/src/target/firmware/layer1/async.c b/src/target/firmware/layer1/async.c
new file mode 100644 (file)
index 0000000..c1a457e
--- /dev/null
@@ -0,0 +1,89 @@
+/* Asynchronous part of GSM Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <debug.h>
+#include <arm.h>
+
+#include <comm/msgb.h>
+
+#include <layer1/sync.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/sched_gsmtime.h>
+#include <layer1/l23_api.h>
+
+extern const struct tdma_sched_item rach_sched_set_ul[];
+
+/* When altering data structures used by L1 Sync part, we need to
+ * make sure to temporarily disable IRQ/FIQ to keep data consistent */
+static inline void l1a_lock_sync(void)
+{
+       arm_disable_interrupts();
+}
+
+static inline void l1a_unlock_sync(void)
+{
+       arm_enable_interrupts();
+}
+
+/* safely enable a message into the L1S TX queue */
+void l1a_txq_msgb_enq(struct llist_head *queue, struct msgb *msg)
+{
+       l1a_lock_sync();
+       msgb_enqueue(queue, msg);
+       l1a_unlock_sync();
+}
+
+/* request a RACH request at the next multiframe T3 = fn51 */
+void l1a_rach_req(uint8_t fn51, uint8_t ra)
+{
+       uint32_t fn_sched;
+
+       l1a_lock_sync();
+       l1s.rach.ra = ra;
+       /* TODO: can we wrap here? I don't think so */
+       fn_sched = l1s.current_time.fn - l1s.current_time.t3;
+       fn_sched += fn51;
+       sched_gsmtime(rach_sched_set_ul, fn_sched);
+       l1a_unlock_sync();
+}
+
+/* Enable a repeating multiframe task */
+void l1a_mftask_enable(enum mframe_task task)
+{
+       /* we don't need locking here as L1S only reads mf_tasks */
+       l1s.mf_tasks |= (1 << task);
+}
+
+/* Disable a repeating multiframe task */
+void l1a_mftask_disable(enum mframe_task task)
+{
+       /* we don't need locking here as L1S only reads mf_tasks */
+       l1s.mf_tasks &= ~(1 << task);
+}
+
+/* Initialize asynchronous part of Layer1 */
+void l1a_init(void)
+{
+       l1a_l23api_init();
+}
index 1c38777..317a126 100644 (file)
 #include <calypso/irq.h>
 
 #include <layer1/sync.h>
+#include <layer1/async.h>
 #include <layer1/l23_api.h>
 
 void layer1_init(void)
 {
        struct msgb *msg;
 
+       /* initialize asynchronous part of L1 */
+       l1a_init();
        /* initialize TDMA Frame IRQ driven synchronous L1 */
        l1s_init();
        /* power up the DSP */
index 85f73cd..4784c85 100644 (file)
@@ -27,6 +27,8 @@
 #include <comm/sercomm.h>
 
 #include <layer1/sync.h>
+#include <layer1/async.h>
+
 #include <l1a_l23_interface.h>
 
 /* the size we will allocate struct msgb* for HDLC */
@@ -61,3 +63,57 @@ struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr)
 
        return msg;
 }
+
+/* callbakc from SERCOMM when L2 sends a message to L1 */
+static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+       struct l1_info_ul *ul = msg->data;
+       struct l1_sync_new_ccch_req *sync_req;
+       struct l1_rach_req *rach_req;
+       struct l1_dedic_mode_est_req *est_req;
+
+       if (sizeof(*ul) > msg->len) {
+               printf("la1_l23_cb: Short message. %u\n", msg->len);
+               goto exit;
+       }
+
+       switch (ul->msg_type) {
+       case SYNC_NEW_CCCH_REQ:
+               if (sizeof(*ul) + sizeof(*sync_req) > msg->len) {
+                       printf("Short sync msg. %u\n", msg->len);
+                       break;
+               }
+
+               sync_req = (struct l1_sync_new_ccch_req *) (&msg->data[0] + sizeof(*ul));
+               printf("Asked to tune to frequency: %u\n", sync_req->band_arfcn);
+
+               /* reset scheduler and hardware */
+               tdma_sched_reset();
+               l1s_dsp_abort();
+
+               /* tune to specified frequency */
+               trf6151_rx_window(0, sync_req->band_arfcn, 40, 0);
+               tpu_end_scenario();
+
+               puts("Starting FCCH Recognition\n");
+               l1s_fb_test(1, 0);
+               break;
+       case DEDIC_MODE_EST_REQ:
+               est_req = (struct l1_dedic_mode_est_req *) ul->payload;
+               /* FIXME: ARFCN! */
+               /* figure out which MF tasks to enable, depending on channel number */
+               break;
+       case CCCH_RACH_REQ:
+               rach_req = (struct l1_rach_req *) ul->payload;
+               l1a_rach_req(27, rach_req->ra);
+               break;
+       }
+
+exit:
+       msgb_free(msg);
+}
+
+void l1a_l23api_init(void)
+{
+       sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
+}