Include channel number and link identifier in L1 DL info
authorHarald Welte <laforge@gnumonks.org>
Mon, 1 Mar 2010 10:08:38 +0000 (11:08 +0100)
committerHarald Welte <laforge@gnumonks.org>
Mon, 1 Mar 2010 22:48:45 +0000 (23:48 +0100)
This enables the layer2 to identify on which channel
(BCCH/CCCH/SDCCH/TCH/...) the respective message was received.
* Encode MFrame Task Number + SACCH info in 'p3' parameter
* Generate channel number and link identifier
* Decode channel number in layer2 program

include/l1a_l23_interface.h
src/host/layer2/src/osmocom_layer2.c
src/target/firmware/include/layer1/mframe_sched.h
src/target/firmware/layer1/mframe_sched.c
src/target/firmware/layer1/sync.c

index 6e94ebc..01fcf9f 100644 (file)
@@ -50,10 +50,16 @@ struct gsm_time {
  * downlink info ... down from the BTS..
  */
 struct l1_info_dl {
+       /* common header, should be its own struct */
        uint8_t msg_type;
        uint8_t padding;
-       /* the ARFCN and the band. */
+
+       /* the ARFCN and the band. FIXME: what about MAIO? */
        uint16_t band_arfcn;
+       /* GSM 08.58 channel number (9.3.1) */
+       uint8_t chan_nr;
+       /* GSM 08.58 link identifier (9.3.2) */
+       uint8_t link_id;
 
        struct gsm_time time;
        uint8_t rx_level;
index 66cb181..877ce4a 100644 (file)
@@ -53,6 +53,7 @@ static int osmo_make_band_arfcn(struct osmocom_ms *ms)
        return ms->arfcn;
 }
 
+static int l1_rach_req(struct osmocom_ms *ms);
 static int osmo_l2_ccch_resp(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct l1_info_dl *dl;
@@ -68,6 +69,7 @@ static int osmo_l2_ccch_resp(struct osmocom_ms *ms, struct msgb *msg)
 
        printf("Found sync burst: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
                dl->snr[0], dl->time.t1, dl->time.t2, dl->time.t3, sb->bsic);
+
        return 0;
 }
 
@@ -158,26 +160,55 @@ static void dump_bcch(u_int8_t tc, const uint8_t *data)
        fprintf(stderr, "\n");
 }
 
+char *chan_nr2string(uint8_t chan_nr)
+{
+       static char str[20];
+       uint8_t cbits = chan_nr >> 3;
+
+       str[0] = '\0';
+
+       if (cbits == 0x01)
+               sprintf(str, "TCH/F");
+       else if ((cbits & 0x1e) == 0x02)
+               sprintf(str, "TCH/H(%u)", cbits & 0x01);
+       else if ((cbits & 0x1c) == 0x04)
+               sprintf(str, "SDCCH/4(%u)", cbits & 0x03);
+       else if ((cbits & 0x18) == 0x08)
+               sprintf(str, "SDCCH/8(%u)", cbits & 0x07);
+       else if (cbits == 0x10)
+               sprintf(str, "BCCH");
+       else if (cbits == 0x11)
+               sprintf(str, "RACH");
+       else if (cbits == 0x12)
+               sprintf(str, "PCH/AGCH");
+       else
+               sprintf(str, "UNKNOWN");
+
+       return str;
+}
+
 static int osmo_l2_ccch_data(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct l1_info_dl *dl;
        struct l1_ccch_info_ind *ccch;
 
        if (msgb_l3len(msg) < sizeof(*ccch)) {
-               fprintf(stderr, "MSG too short CCCH Data Ind: %u\n", msgb_l3len(msg));
+               fprintf(stderr, "MSG too short DCCH Data Ind: %u\n", msgb_l3len(msg));
                return -1;
        }
 
        dl = (struct l1_info_dl *) msg->l2h;
        ccch = (struct l1_ccch_info_ind *) msg->l3h;
-       printf("Found CCCH burst(s): TDMA: (%.4u/%.2u/%.2u) tc:%d %s si: 0x%x\n",
-              dl->time.t1, dl->time.t2, dl->time.t3, dl->time.tc,
-              hexdump(ccch->data, sizeof(ccch->data)), ccch->data[2]);
+       printf("Found %s burst(s): TDMA: (%.4u/%.2u/%.2u) tc:%d %s si: 0x%x\n",
+               chan_nr2string(dl->chan_nr), dl->time.t1, dl->time.t2,
+               dl->time.t3, dl->time.tc, hexdump(ccch->data, sizeof(ccch->data)),
+               ccch->data[2]);
 
        dump_bcch(dl->time.tc, ccch->data);
        /* send CCCH data via GSMTAP */
-       gsmtap_sendmsg(0, dl->band_arfcn, dl->time.fn, ccch->data,
+       gsmtap_sendmsg(dl->chan_nr & 0x07, dl->band_arfcn, dl->time.fn, ccch->data,
                        sizeof(ccch->data));
+       //l1_rach_req(ms);
        return 0;
 }
 
@@ -197,6 +228,23 @@ static int osmo_l1_reset(struct osmocom_ms *ms)
        return osmo_send_l1(ms, msg);
 }
 
+static int l1_rach_req(struct osmocom_ms *ms)
+{
+       struct msgb *msg;
+       struct l1_rach_req *req;
+       static uint8_t i = 0;
+
+       msg = osmo_l1_alloc(CCCH_RACH_REQ);
+       if (!msg)
+               return -1;
+
+       printf("RACH Req.\n");
+       req = (struct l1_rach_req *) msgb_put(msg, sizeof(*req));
+       req->ra = i++;
+
+       return osmo_send_l1(ms, msg);
+}
+
 
 int osmo_recv(struct osmocom_ms *ms, struct msgb *msg)
 {
index 019d31b..bd75254 100644 (file)
@@ -25,5 +25,11 @@ enum mframe_task {
        MF_TASK_UL_ALL_NB,
 };
 
+enum mf_sched_item_flag {
+       MF_F_SACCH      = (1 << 0),
+};
+
+uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts);
+
 /* Schedule mframe_sched_items according to current MF TASK list */
 void mframe_schedule(uint32_t task_bitmask);
index 502d102..61fbe48 100644 (file)
 #include <layer1/tdma_sched.h>
 #include <layer1/mframe_sched.h>
 
-enum mf_sched_item_flag {
-       MF_F_SACCH,
-       //MF_F_UL_OFFS_15,      /* uplink 15 frames after downlink */
-};
-
 /* A multiframe operation which can be scheduled for a multiframe */
 struct mframe_sched_item {
        /* The TDMA scheduler item that shall be scheduled */
@@ -230,6 +225,61 @@ static const struct mframe_sched_item *sched_set_for_task[32] = {
        [MF_TASK_UL_ALL_NB] = mf_tx_all_nb,
 };
 
+/* encodes a channel number according to 08.58 Chapter 9.3.1 */
+uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts)
+{
+       uint8_t cbits;
+
+       switch (mft) {
+       case MF_TASK_BCCH_NORM:
+       case MF_TASK_BCCH_EXT:
+               cbits = 0x10;
+               break;
+       case MF_TASK_CCCH:
+       case MF_TASK_CCCH_COMB:
+               cbits = 0x12;
+               break;
+       case MF_TASK_SDCCH4_0:
+               cbits = 0x04 + 0;
+               break;
+       case MF_TASK_SDCCH4_1:
+               cbits = 0x04 + 1;
+               break;
+       case MF_TASK_SDCCH4_2:
+               cbits = 0x04 + 2;
+               break;
+       case MF_TASK_SDCCH4_3:
+               cbits = 0x04 + 3;
+               break;
+       case MF_TASK_SDCCH8_0:
+               cbits = 0x08 + 0;
+               break;
+       case MF_TASK_SDCCH8_1:
+               cbits = 0x08 + 1;
+               break;
+       case MF_TASK_SDCCH8_2:
+               cbits = 0x08 + 2;
+               break;
+       case MF_TASK_SDCCH8_3:
+               cbits = 0x08 + 3;
+               break;
+       case MF_TASK_SDCCH8_4:
+               cbits = 0x08 + 4;
+               break;
+       case MF_TASK_SDCCH8_5:
+               cbits = 0x08 + 5;
+               break;
+       case MF_TASK_SDCCH8_6:
+               cbits = 0x08 + 6;
+               break;
+       case MF_TASK_SDCCH8_7:
+               cbits = 0x08 + 7;
+               break;
+       }
+
+       return (cbits << 3) | (ts & 0x7);
+}
+
 /* how many TDMA frame ticks should we schedule events ahead? */
 #define SCHEDULE_AHEAD 2
 
@@ -237,8 +287,9 @@ static const struct mframe_sched_item *sched_set_for_task[32] = {
 #define SCHEDULE_LATENCY       1
 
 /* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
-static void mframe_schedule_set(const struct mframe_sched_item *set)
+static void mframe_schedule_set(enum mframe_task task_id)
 {
+       const struct mframe_sched_item *set = sched_set_for_task[task_id];
        const struct mframe_sched_item *si;
 
        for (si = set; si->sched_set != NULL; si++) {
@@ -247,7 +298,7 @@ static void mframe_schedule_set(const struct mframe_sched_item *set)
                if (current == trigger) {
                        /* FIXME: what to do with SACCH Flag etc? */
                        tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
-                                         si->sched_set, si->flags);
+                                         si->sched_set, task_id | (si->flags<<8));
                }
        }
 }
@@ -259,6 +310,6 @@ void mframe_schedule(uint32_t tasks_enabled)
 
        for (i = 0; i < 32; i++) {
                if (tasks_enabled & (1 << i))
-                       mframe_schedule_set(sched_set_for_task[i]);
+                       mframe_schedule_set(i);
        }
 }
index 1f01158..c71caaf 100644 (file)
@@ -802,6 +802,8 @@ void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
 static int l1s_nb_resp(uint8_t p1, uint8_t burst_id, uint16_t p3)
 {
        static struct l1_signal _nb_sig, *sig = &_nb_sig;
+       uint8_t mf_task_id = p3 & 0xff;
+       uint8_t mf_task_flags = p3 >> 8;
        struct msgb *msg;
 
        putchart('n');
@@ -855,6 +857,15 @@ static int l1s_nb_resp(uint8_t p1, uint8_t burst_id, uint16_t p3)
                dl = (struct l1_info_dl *) msg->data;
                l1 = (struct l1_ccch_info_ind *) msgb_put(msg, sizeof(*l1));
 
+               /* Set Channel Number depending on MFrame Task ID */
+               dl->chan_nr = mframe_task2chan_nr(mf_task_id, 0); /* FIXME: TS */
+
+               /* Set SACCH indication in Link IDentifier */
+               if (mf_task_flags & MF_F_SACCH)
+                       dl->link_id = 0x40;
+               else
+                       dl->link_id = 0x00;
+
                /* copy the snr and data */
                for (i = 0; i < 3; ++i)
                        dl->snr[i] = sig->nb.meas[i].snr;
@@ -937,6 +948,8 @@ static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3)
 {
        int i;
        uint8_t tsc;
+       uint8_t mf_task_id = p3 & 0xff;
+       uint8_t mf_task_flags = p3 >> 8;
 
        putchart('T');
 
@@ -968,12 +981,18 @@ static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3)
        if (burst_id == 0) {
                if (p1 == 0 || p1 == 2) { // DUL_DSP_TASK
                        uint16_t *info_ptr = dsp_api.ndb->a_cu;
+                       struct llist_head *tx_queue;
                        struct msgb *msg;
                        uint8_t *data;
                        uint8_t j;
 
-                       /* FIXME: distinguish between DCCH and ACCH */
-                       msg = msgb_dequeue(&l1s.tx_queue[0]);
+                       /* distinguish between DCCH and ACCH */
+                       if (mf_task_flags & MF_F_SACCH)
+                               tx_queue = &l1s.tx_queue[0];
+                       else
+                               tx_queue = &l1s.tx_queue[1];
+
+                       msg = msgb_dequeue(tx_queue);
 
                        /* If the TX queue is empty, send idle pattern */
                        if (!msg)