[layer1] Added frequency change control to layer 1 (L1CTL_FREQ_REQ)
authorAndreas.Eversberg <jolly@eversberg.eu>
Sat, 11 Sep 2010 18:10:14 +0000 (18:10 +0000)
committerAndreas.Eversberg <jolly@eversberg.eu>
Sat, 11 Sep 2010 18:10:14 +0000 (18:10 +0000)
The given new frequency set will be used at given frame number.
If the frame number is already reached, the frequency set will be changed
directly.

The functionality has been successfully tested.

src/target/firmware/include/layer1/async.h
src/target/firmware/include/layer1/sync.h
src/target/firmware/layer1/Makefile
src/target/firmware/layer1/l23_api.c
src/target/firmware/layer1/prim_freq.c [new file with mode: 0644]

index 7f8f971..42c3223 100644 (file)
@@ -23,6 +23,9 @@ void l1a_txq_msgb_enq(struct llist_head *queue, struct msgb *msg);
 /* request a RACH request at the next multiframe T3 = fn51 */
 void l1a_rach_req(uint8_t fn51, uint8_t mf_off, uint8_t ra);
 
+/* schedule frequency change */
+void l1a_freq_req(uint32_t fn_sched);
+
 /* Enable a repeating multiframe task */
 void l1a_mftask_enable(enum mframe_task task);
 
index 257244b..da9a5da 100644 (file)
@@ -41,6 +41,17 @@ typedef void l1_compl_cb(enum l1_compl c);
 #define L1S_NUM_COMPL          32
 #define L1S_NUM_NEIGH_CELL     6
 
+struct l1s_h0 {
+       uint16_t arfcn;
+};
+
+struct l1s_h1 {
+       uint8_t hsn;
+       uint8_t maio;
+       uint8_t n;
+       uint16_t ma[64];
+};
+
 struct l1s_state {
        struct gsm_time current_time;   /* current GSM time */
        struct gsm_time next_time;      /* GSM time at next TMDMA irq */
@@ -109,15 +120,17 @@ struct l1s_state {
                uint8_t h;
 
                union {
-                       struct {
-                               uint16_t arfcn;
-                       } h0;
-                       struct {
-                               uint8_t hsn;
-                               uint8_t maio;
-                               uint8_t n;
-                               uint16_t ma[64];
-                       } h1;
+                       struct l1s_h0 h0;
+                       struct l1s_h1 h1;
+               };
+
+               uint8_t st_tsc;
+               uint8_t st_tn;
+               uint8_t st_h;
+
+               union {
+                       struct l1s_h0 st_h0;
+                       struct l1s_h1 st_h1;
                };
        } dedicated;
 };
index dd3fcf1..fd0514c 100644 (file)
@@ -4,5 +4,6 @@ layer1_DIR=layer1
 layer1_SRCS=avg.c agc.c afc.c sync.c tdma_sched.c tpu_window.c init.c l23_api.c \
                mframe_sched.c sched_gsmtime.c async.c rfch.c
 
-layer1_SRCS += prim_pm.c prim_rach.c prim_tx_nb.c prim_rx_nb.c prim_fbsb.c
+layer1_SRCS += prim_pm.c prim_rach.c prim_tx_nb.c prim_rx_nb.c prim_fbsb.c \
+               prim_freq.c
 
index e103a78..5080463 100644 (file)
@@ -201,6 +201,35 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg)
        l1a_mftask_set(1 << chan_nr2mf_task(ul->chan_nr));
 }
 
+/* receive a L1CTL_DM_FREQ_REQ from L23 */
+static void l1ctl_rx_dm_freq_req(struct msgb *msg)
+{
+       struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+       struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+       struct l1ctl_dm_freq_req *freq_req =
+                       (struct l1ctl_dm_freq_req *) ul->payload;
+
+       printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
+               ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
+
+       /* configure dedicated channel state */
+       l1s.dedicated.st_tsc  = freq_req->tsc;
+       l1s.dedicated.st_h    = freq_req->h;
+
+       if (freq_req->h) {
+               int i;
+               l1s.dedicated.st_h1.hsn  = freq_req->h1.hsn;
+               l1s.dedicated.st_h1.maio = freq_req->h1.maio;
+               l1s.dedicated.st_h1.n    = freq_req->h1.n;
+               for (i=0; i<freq_req->h1.n; i++)
+                       l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
+       } else {
+               l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
+       }
+
+       l1a_freq_req(ntohs(freq_req->fn));
+}
+
 /* receive a L1CTL_CRYPTO_REQ from L23 */
 static void l1ctl_rx_crypto_req(struct msgb *msg)
 {
@@ -403,6 +432,9 @@ static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
        case L1CTL_PARAM_REQ:
                l1ctl_rx_param_req(msg);
                break;
+       case L1CTL_DM_FREQ_REQ:
+               l1ctl_rx_dm_freq_req(msg);
+               break;
        case L1CTL_CRYPTO_REQ:
                l1ctl_rx_crypto_req(msg);
                break;
diff --git a/src/target/firmware/layer1/prim_freq.c b/src/target/firmware/layer1/prim_freq.c
new file mode 100644 (file)
index 0000000..4b702ff
--- /dev/null
@@ -0,0 +1,110 @@
+/* Layer 1 Frequency redefinition at "starting time" */
+
+/* (C) 2010 by Andreas Eversverg <jolly@eversberg.eu>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocore/gsm_utils.h>
+#include <osmocore/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+
+#include <l1ctl_proto.h>
+
+struct {
+       uint32_t fn;
+       uint16_t band_arfcn;
+} last_rach;
+
+/* if the "starting time" is reached, use frequencies "after time" */
+static int l1s_freq_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
+{
+       putchart('F');
+
+       printf("Reached starting time, altering frequency set\n");
+
+       l1s.dedicated.tsc = l1s.dedicated.st_tsc;
+       l1s.dedicated.h = l1s.dedicated.st_h;
+       if (l1s.dedicated.h)
+               memcpy(&l1s.dedicated.h1, &l1s.dedicated.st_h1,
+                       sizeof(l1s.dedicated.h1));
+       else
+               memcpy(&l1s.dedicated.h0, &l1s.dedicated.st_h0,
+                       sizeof(l1s.dedicated.h0));
+
+       return 0;
+}
+
+/* sched set for frequency change */
+const struct tdma_sched_item freq_sched_set[] = {
+       SCHED_ITEM(l1s_freq_cmd, 1, 0),
+       SCHED_END_SET()
+};
+
+/* request a frequency change at the given frame number
+ * Note: The fn_sched parameter must be in range 0..42431. */
+void l1a_freq_req(uint32_t fn_sched)
+{
+       int32_t diff;
+
+       /* We must check here, if the time already elapsed.
+        * This is required, because we may have an undefined delay between
+        * layer 1 and layer 3.
+        */
+       diff = fn_sched - (l1s.current_time.fn % 42432);
+       if (diff < 0)
+               diff += 42432;
+       /* note: 5 is used to give scheduler some time */
+       if (diff == 5 || diff >= 32024) {
+               l1s_freq_cmd(0, 0, 0);
+               return;
+       }
+
+       /* calculate (full range) frame number */
+       fn_sched = l1s.current_time.fn + diff;
+       if (fn_sched >= GSM_MAX_FN)
+               fn_sched -= GSM_MAX_FN;
+       printf("Scheduling frequency change at fn=%u, currently fn=%u\n",
+               fn_sched, l1s.current_time.fn);
+
+       l1a_lock_sync();
+       sched_gsmtime(freq_sched_set, fn_sched, 0);
+       l1a_unlock_sync();
+}
+