summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-02-28 14:31:06 +0100
committerHarald Welte <laforge@gnumonks.org>2010-03-01 23:48:45 +0100
commit146619933bdcdf4ce42f591c3aee7dc66fa16574 (patch)
treea5369771ad5db8326e3b954786517f797d595a14
parent3e7861e937fc63da9a261c76b8468d996112143b (diff)
add an actual Layer1 asynchronous (L1A) API that can be called from higher layers
-rw-r--r--include/l1a_l23_interface.h1
-rw-r--r--src/target/firmware/apps/layer1/main.c40
-rw-r--r--src/target/firmware/include/layer1/l23_api.h1
-rw-r--r--src/target/firmware/include/layer1/sync.h4
-rw-r--r--src/target/firmware/layer1/Makefile2
-rw-r--r--src/target/firmware/layer1/async.c89
-rw-r--r--src/target/firmware/layer1/init.c3
-rw-r--r--src/target/firmware/layer1/l23_api.c56
8 files changed, 155 insertions, 41 deletions
diff --git a/include/l1a_l23_interface.h b/include/l1a_l23_interface.h
index fc03d720..6e94ebc1 100644
--- a/include/l1a_l23_interface.h
+++ b/include/l1a_l23_interface.h
@@ -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));
/*
diff --git a/src/target/firmware/apps/layer1/main.c b/src/target/firmware/apps/layer1/main.c
index 6e4d9817..62475433 100644
--- a/src/target/firmware/apps/layer1/main.c
+++ b/src/target/firmware/apps/layer1/main.c
@@ -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);
-}
diff --git a/src/target/firmware/include/layer1/l23_api.h b/src/target/firmware/include/layer1/l23_api.h
index a03c59c8..826f82ea 100644
--- a/src/target/firmware/include/layer1/l23_api.h
+++ b/src/target/firmware/include/layer1/l23_api.h
@@ -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);
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h
index a50969b8..901ff9db 100644
--- a/src/target/firmware/include/layer1/sync.h
+++ b/src/target/firmware/include/layer1/sync.h
@@ -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;
diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile
index d04573ed..39639581 100644
--- a/src/target/firmware/layer1/Makefile
+++ b/src/target/firmware/layer1/Makefile
@@ -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
index 00000000..c1a457e4
--- /dev/null
+++ b/src/target/firmware/layer1/async.c
@@ -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();
+}
diff --git a/src/target/firmware/layer1/init.c b/src/target/firmware/layer1/init.c
index 1c387772..317a1266 100644
--- a/src/target/firmware/layer1/init.c
+++ b/src/target/firmware/layer1/init.c
@@ -33,12 +33,15 @@
#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 */
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index 85f73cde..4784c857 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -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);
+}