uint8_t tx_power;
uint8_t channel_number;
uint32_t tdma_frame;
+ uint8_t payload[0];
} __attribute__((packed));
/*
}
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)
{
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);
}
}
-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);
-}
#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);
/* bit-mask of multi-frame tasks that are currently active */
uint32_t mf_tasks;
+
+ struct {
+ uint8_t ra;
+ } rach;
};
extern struct l1s_state l1s;
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)
--- /dev/null
+/* 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();
+}
#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 */
#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 */
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);
+}