Layer1 Sync support for TX of Normal Burst and RACH burst
authorHarald Welte <laforge@gnumonks.org>
Sun, 28 Feb 2010 10:46:17 +0000 (11:46 +0100)
committerHarald Welte <laforge@gnumonks.org>
Mon, 1 Mar 2010 22:48:44 +0000 (23:48 +0100)
Using the new rach_sched_set_ul and nb_sched_set_ul TDMA scheduler
sets it is possible to transmit RACH bursts as well as sets of four
normal bursts, i.e. everything needed to get a SDCCH established
on a combined CCCH (with SDCCH/4).

Known Limitations:
* Uses constant transmit power (2 dBm)
* Only works on SDCCH/4 so far
* SACCH is received but cannot be transmitted yet
* TSC (traning sequence code) is hard-coded to '7'

src/target/firmware/layer1/sync.c

index 7b39685..d6921ec 100644 (file)
@@ -36,6 +36,9 @@
 #include <calypso/dsp.h>
 #include <calypso/timer.h>
 #include <comm/sercomm.h>
+#include <comm/msgb.h>
+
+#include <abb/twl3025.h>
 
 #include <layer1/sync.h>
 #include <layer1/afc.h>
@@ -889,8 +892,175 @@ const struct tdma_sched_item nb_sched_set[] = {
 };
 
 
-/* dummy sched set for uplink */
+/* Transmit Burst *************************************************************/
+
+const uint8_t ubUui[23]     = { 0x01, 0x03, 0x01, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b };
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
+static int l1s_tx_resp(uint16_t p1, uint16_t burst_id)
+{
+       putchart('t');
+
+       dsp_api.r_page_used = 1;
+
+       return 0;
+}
+
+/* Channel type definitions for DEDICATED mode */
+#define INVALID_CHANNEL    0
+#define TCH_F              1
+#define TCH_H              2
+#define SDCCH_4            3
+#define SDCCH_8            4
+
+/* Channel mode definitions for DEDICATED mode */
+#define SIG_ONLY_MODE      0    // signalling only
+#define TCH_FS_MODE        1    // speech full rate
+#define TCH_HS_MODE        2    // speech half rate
+#define TCH_96_MODE        3    // data 9,6 kb/s
+#define TCH_48F_MODE       4    // data 4,8 kb/s full rate
+#define TCH_48H_MODE       5    // data 4,8 kb/s half rate
+#define TCH_24F_MODE       6    // data 2,4 kb/s full rate
+#define TCH_24H_MODE       7    // data 2,4 kb/s half rate
+#define TCH_EFR_MODE       8    // enhanced full rate
+#define TCH_144_MODE       9    // data 14,4 kb/s half rate
+
+static uint8_t loc_cnt = 0;
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
+static int l1s_tx_cmd(uint16_t p1, uint16_t burst_id)
+{
+       int i;
+       uint8_t tsc;
+
+       putchart('T');
+
+       /* Load the ApcOffset into the DSP */
+       #define  MY_OFFSET      4
+       dsp_api.ndb->d_apcoff = ABB_VAL(APCOFF, (1 << 6) | MY_OFFSET) | 1; /* 2x slope for the GTA-02 ramp */
+
+       /* Load the TX Power into the DSP */
+       /*
+          If the power is too low (below 0 dBm) the ramp is not OK,
+          especially for GSM-1800. However an MS does not send below
+          0dBm anyway.
+       */
+       dsp_api.db_w->d_power_ctl = ABB_VAL(AUXAPC, 0xC0); /* 2 dBm pulse with offset 4 (GSM-1800) */
+
+       /* Update the ramp according to the PCL */
+       for (i = 0; i < 16; i++)
+               dsp_api.ndb->a_ramp[i] = ABB_VAL(APCRAM, twl3025_default_ramp[i]);
+
+       /* The Ramp Table is sent to ABB only once after RF init routine called */
+       dsp_api.db_w->d_ctrl_abb |= (1 << B_RAMP) | (1 << B_BULRAMPDEL);
+
+       if (p1 == 0) /* DUL_DSP_TASK, one normal burst */
+               dsp_load_tch_param(0, SIG_ONLY_MODE, INVALID_CHANNEL, 0, 0, 0);
+       else if (p1 == 2) /* DUL_DSP_TASK, four normal bursts */
+               dsp_load_tch_param(0, SIG_ONLY_MODE, SDCCH_4, 0, 0, 0);
+
+       /* before sending first of the four bursts, copy data to API ram */
+       if (burst_id == 0) {
+               if (p1 == 0 || p1 == 2) { // DUL_DSP_TASK
+                       uint16_t *info_ptr = dsp_api.ndb->a_cu;
+                       struct msgb *msg;
+                       uint8_t *data;
+                       uint8_t j;
+
+                       /* FIXME: distinguish between DCCH and ACCH */
+                       msg = msgb_dequeue(&l1s.tx_queue[0]);
+
+                       /* If the TX queue is empty, send idle pattern */
+                       if (!msg)
+                               data = ubUui;
+                       else
+                               data = msg->data;
+
+                       /* Fill data block Header */
+                       info_ptr[0] = (1 << B_BLUD);     // 1st word: Set B_BLU bit.
+                       info_ptr[1] = 0;                 // 2nd word: cleared.
+                       info_ptr[2] = 0;                 // 3rd word: cleared.
+
+                       /* Copy first 22 bytes in the first 11 words after header. */
+                       for (i=0, j=(3+0); j<(3+11); j++) {
+                               info_ptr[j] = ((uint16_t)(data[i])) | ((uint16_t)(data[i+1]) << 8);
+                               i += 2;
+                       }
+                       /* Copy last UWORD8 (23rd) in the 12th word after header. */
+                       info_ptr[14] = data[22];
+
+                       if (msg)
+                               msgb_free(msg);
+               } else if (p1 == 1) { // RACH_DSP_TASK
+                       uint16_t  *info_ptr;
+                       uint8_t data[2];
+
+                       data[0] = l1s.serving_cell.bsic << 2;
+                       data[1] = 0x00 + loc_cnt; // channel request, location update, loc_cnt as random reference
+                       loc_cnt++;
+                       if (loc_cnt > 16)
+                               loc_cnt = 0;
+
+                       info_ptr = &dsp_api.ndb->d_rach;
+                       info_ptr[0] = ((uint16_t)(data[0])) | ((uint16_t)(data[1])<<8);
+               }
+       }
+
+       if (p1 == 0 || p1 == 2) {
+               tsc = 7; // !!!!! nanoBTS configuration for SDCCH 0 !!!!!!!!
+
+               dsp_load_tx_task(DUL_DSP_TASK, burst_id, tsc);
+               dsp_end_scenario();
+
+               l1s_tx_win_ctrl(rf_arfcn, L1_TXWIN_NB, 0);
+               tpu_end_scenario();
+       } else if (p1 == 1) {
+               dsp_api.db_w->d_task_ra = RACH_DSP_TASK;
+               dsp_end_scenario();
+
+               l1s_tx_win_ctrl(rf_arfcn, L1_TXWIN_AB, 0);
+               tpu_end_scenario();
+       }
+
+       return 0;
+}
+
+void l1s_tx_test(uint8_t base_fn, uint8_t type)
+{
+       printf("Starting TX %d\n", type);
+
+       if (type == 0) {// one normal burst
+               tdma_schedule(base_fn, &l1s_tx_cmd, 0, 0);
+               tdma_schedule(base_fn + 2, &l1s_tx_resp, 0, 0);
+       } else if (type == 1) { // one RACH burst
+               tdma_schedule(base_fn, &l1s_tx_cmd, 1, 0);
+               tdma_schedule(base_fn + 2, &l1s_tx_resp, 1, 0);
+       } else if (type == 2) { // four normal burst
+               tdma_schedule(base_fn, &l1s_tx_cmd, 2, 0);
+               tdma_schedule(base_fn + 1, &l1s_tx_cmd, 2, 1);
+               tdma_schedule(base_fn + 2, &l1s_tx_resp, 2, 0);
+               tdma_schedule(base_fn + 2, &l1s_tx_cmd, 2, 2);
+               tdma_schedule(base_fn + 3, &l1s_tx_resp, 2, 1);
+               tdma_schedule(base_fn + 3, &l1s_tx_cmd, 2, 3);
+               tdma_schedule(base_fn + 4, &l1s_tx_resp, 2, 2);
+               tdma_schedule(base_fn + 5, &l1s_tx_resp, 2, 3);
+       }
+}
+
+/* sched sets for uplink */
+const struct tdma_sched_item rach_sched_set_ul[] = {
+       SCHED_ITEM(l1s_tx_cmd, 1, 0),                                   SCHED_END_FRAME(),
+                                                                       SCHED_END_FRAME(),
+       SCHED_ITEM(l1s_tx_resp, 1, 0),                                  SCHED_END_FRAME(),
+       SCHED_END_SET()
+};
 const struct tdma_sched_item nb_sched_set_ul[] = {
+       SCHED_ITEM(l1s_tx_cmd, 2, 0),                                   SCHED_END_FRAME(),
+       SCHED_ITEM(l1s_tx_cmd, 2, 1),                                   SCHED_END_FRAME(),
+       SCHED_ITEM(l1s_tx_resp, 2, 0), SCHED_ITEM(l1s_tx_cmd, 2, 2),    SCHED_END_FRAME(),
+       SCHED_ITEM(l1s_tx_resp, 2, 1), SCHED_ITEM(l1s_tx_cmd, 2, 3),    SCHED_END_FRAME(),
+                                      SCHED_ITEM(l1s_tx_resp, 2, 2),   SCHED_END_FRAME(),
+                                      SCHED_ITEM(l1s_tx_resp, 2, 3),   SCHED_END_FRAME(),
        SCHED_END_SET()
 };