Added process of link control in idle mode.
authorAndreas Eversberg <jolly@eversberg.eu>
Sat, 27 Mar 2010 10:05:16 +0000 (11:05 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Sat, 27 Mar 2010 10:08:47 +0000 (11:08 +0100)
The process is described in GSM 05.08 and will search and select BCCH.
The process is partly complete.

src/host/gsm48-andreas/gsm58.c [new file with mode: 0644]
src/host/gsm48-andreas/gsm58.h [new file with mode: 0644]

diff --git a/src/host/gsm48-andreas/gsm58.c b/src/host/gsm48-andreas/gsm58.c
new file mode 100644 (file)
index 0000000..168ef3f
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * (C) 2010 by Andreas Eversberg <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.
+ *
+ */
+
+todo: cell selection and reselection criteria
+todo: path loss
+todo: downlink signal failure
+
+/* allocate a 05.08 event message */
+struct msgb *gsm58_msgb_alloc(int msg_type)
+{
+       struct msgb *msg;
+       struct gsm58_msg *gm;
+
+       msg = msgb_alloc_headroom(GSM58_ALLOC_SIZE, GSM58_ALLOC_HEADROOM,
+               "GSM 05.08");
+       if (!msg)
+               return NULL;
+
+       gm = (struct gsm58_msg *)msgb_put(msg, sizeof(*gm));
+       gm->msg_type = msg_type;
+       return msg;
+}
+
+/* select first/next frequency */
+static int gsm58_select_bcch(struct osmocom_ms *ms)
+{
+       struct gsm_support *s = &ms->support;
+       struct gsm58_selproc *sp = &ms->selproc;
+       int i, j = 0;
+
+next:
+       for (i = 0, i < 1024, i++) {
+               if ((sp->ba[i >> 3] & (1 << (i & 7)))) {
+                       if (j == sp->cur_freq)
+                               break;
+                       j++;
+               }
+       }
+       if (i == 1024) {
+               struct msgb *nmsg;
+
+               DEBUGP(DRR, "Cycled through all %d frequencies in list.\n", j);
+               nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_F);
+               if (!nmsg)
+                       return -ENOMEM;
+               gsm322_sendmsg(ms, nmsg);
+       }
+
+       /* if frequency not supported */
+       if (!(s->freq_map[i >> 3] & (1 << (i & 7)))) {
+               DEBUGP(DRR, "Frequency %d in list, but not supported.\n", i);
+               sp->cur_freq++;
+               goto next;
+       }
+
+       /* set current BCCH frequency */
+       sp->arfcn = i;
+       DEBUGP(DRR, "Frequency %d selected, wait for sync.\n", sp->arfcn);
+       tx_ph_bcch_req(ms, sp->arfcn);
+
+       /* start timer for synchronizanation */
+       gsm58_timer_start(sp, 0, 500000);
+
+       sp->mode = GSM58_MODE_SYNC;
+
+       return 0;
+}
+
+
+/* start normal cell selection: search any channel for given PLMN */
+static int gsm58_start_normal_sel(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+       struct gsm_support *s = &ms->support;
+       struct gsm58_msg *gm = msgb->data;
+
+       /* reset process */
+       memset(sp, 0, sizeof(*sp));
+
+       /* use all frequencies from supported frequency map */
+       memcpy(sp->ba, s->freq_map, sizeof(sp->ba));
+
+       /* limit process to given PLMN */
+       sp->mcc = gm->mcc;
+       sp->mnc = gm->mnc;
+
+       /* select first channel */
+       gsm58_select_bcch(ms);
+}
+
+/* start stored cell selection: search given channels for given PLMN */
+static int gsm58_start_stored_sel(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+       struct gsm_support *s = &ms->support;
+       struct gsm58_msg *gm = msgb->data;
+
+       /* reset process */
+       memset(sp, 0, sizeof(*sp));
+
+       /* use all frequencies from given frequency map */
+       memcpy(sp->ba, sp->ba, sizeof(sp->ba));
+
+       /* limit process to given PLMN */
+       sp->mcc = gm->mcc;
+       sp->mnc = gm->mnc;
+
+       /* select first channel */
+       gsm58_select_bcch(ms);
+}
+
+/* start any cell selection: search any channel for any PLMN */
+static int gsm58_start_any_sel(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+       struct gsm_support *s = &ms->support;
+       struct gsm58_msg *gm = msgb->data;
+
+       /* reset process */
+       memset(sp, 0, sizeof(*sp));
+
+       /* allow any cell not barred */
+       sp->any = 1;
+
+       /* use all frequencies from supported frequency map */
+       memcpy(sp->ba, s->freq_map, sizeof(sp->ba));
+
+       /* select first channel */
+       gsm58_select_bcch(ms);
+}
+
+/* timeout while selecting BCCH */
+static int gsm58_sel_timeout(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+
+       switch(sp->mode) {
+       case GSM58_MODE_SYNC:
+               /* if no sync is received from radio withing sync time */
+               DEBUGP(DRR, "Syncronization failed, selecting next frq.\n");
+               break;
+       case GSM58_MODE_READ:
+               /* timeout while reading BCCH */
+               DEBUGP(DRR, "BCC reading failed, selecting next frq.\n");
+               break;
+       default:
+               DEBUGP(DRR, "Timeout in wrong mode, please fix!\n");
+       }
+
+       sp->cur_freq++;
+       gsm58_select_bcch(ms);
+
+       return 0;
+}
+
+/* we are synchronized to selecting BCCH */
+static int gsm58_sel_sync(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+       struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
+
+       /* if we got a sync while already selecting a new frequency */
+       if (gm->arfcn != sp->arfcn) {
+               DEBUGP(DRR, "Requested frq %d, but synced to %d, ignoring.\n"
+                       sp->arfcn, gm->arfcn);
+               return 0;
+       }
+
+       DEBUGP(DRR, "Synced to %d, waiting for relevant data.\n", sp->arfcn);
+
+       /* set timer for reading BCCH */
+       gsm58_timer_start(sp, 4, 0); // TODO: timer depends on BCCH configur.
+
+       /* reset sysinfo and wait for relevant data */
+       gsm_sysinfo_init(ms);
+       sp->mode = GSM58_MODE_READ;
+
+       return 0;
+}
+
+/* we are getting sysinfo from BCCH */
+static int gsm58_sel_sysinfo(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_selproc *sp = &ms->selproc;
+       struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
+       struct msgb *nmsg;
+       int barred = 0, i;
+
+       /* ignore system info, if not synced */
+       if (sp->mode != GSM58_MODE_DATA && sp->mode != GSM58_MODE_CAMP)
+               return 0;
+
+       /* check if cell is barred for us */
+       if (!subscr->barred_access && s->cell_barred)
+               barred = 1;
+       if (sp->any) {
+               if (s->class_barr[10])
+                       barred = 1;
+       } else {
+               for (i = 0, i <= 15, i++)
+                       if (subscr->class_access[i] && !s->class_barr[i])
+                               break;
+               if (i > 15)
+                       barred = 1;
+       }
+
+
+       /* cell has become barred */
+       if (sp->mode == GSM58_MODE_CAMP) {
+               if (barred) {
+                       DEBUGP(DRR, "Cell has become barred, starting "
+                               "reselection.\n");
+
+                       sp->mode = GSM58_MODE_IDLE;
+
+                       nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_RESEL);
+                       if (!nmsg)
+                               return -ENOMEM;
+                       gsm322_sendmsg(ms, nmsg);
+
+                       return 0;
+               }
+
+               return 0;
+       }
+
+       /* can't use barred cell */
+       if (barred) {
+               DEBUGP(DRR, "Selected cell is barred, select next.\n");
+               gsm58_timer_stop(sp);
+               sp->cur_freq++;
+               gsm58_select_bcch(ms);
+
+               return 0;
+       }
+
+       /* if PLMN not yet indicated */
+       if (!s->mcc && !s->mnc)
+               return 0;
+
+       // todo: what else do we need until we can camp?
+
+       /* all relevant informations received */
+       gsm58_timer_stop(sp);
+       sp->mode = GSM58_MODE_CAMP;
+
+       DEBUGP(DRR, "Cell with freq %d, mcc = %d, mnc = %d selected.\n",
+               sp->arfcn, s->mcc, s->mnc);
+
+       nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_FOUND);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm322_sendmsg(ms, nmsg);
+
+       return 0;
+}
+
+/* receive events for GSM 05.08 processes */
+static int gsm58_event(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
+       int msg_type = gm->msg_type;
+
+       DEBUGP(DRR, "(ms %s) Message '%s' for link control "
+               "%s\n", ms->name, gsm58_event_names[msg_type],
+               plmn_a_state_names[plmn->state]);
+
+       switch(msg_type) {
+       case GSM58_EVENT_START_NORMAL:
+               gsm58_start_normal_sel(ms, msg);
+               break;
+       case GSM58_EVENT_START_STORED:
+               gsm58_start_stored_sel(ms, msg);
+               break;
+       case GSM58_EVENT_START_ANY:
+               gsm58_start_any_sel(ms, msg);
+               break;
+       case GSM58_EVENT_TIMEOUT:
+               gsm58_sel_timeout(ms, msg);
+               break;
+       case GSM58_EVENT_SYNC:
+               gsm58_sel_sync(ms, msg);
+               break;
+       case GSM58_EVENT_SYSINFO:
+               gsm58_sel_sysinfo(ms, msg);
+               break;
+       default:
+               DEBUGP(DRR, "Message unhandled.\n");
+       }
+
+       free_msgb(msg);
+
+       return 0;
+}
+
+
+static void gsm58_timer_timeout(void *arg)
+{
+       struct gsm322_58_selproc *sp = arg;
+       struct msgb *nmsg;
+
+       /* indicate BCCH selection T timeout */
+       nmsg = gsm58_msgb_alloc(GSM58_EVENT_TIMEOUT);
+       if (!nmsg)
+               return -ENOMEM;
+       gsm58_sendmsg(ms, nmsg);
+}
+
+static void gsm58_timer_start(struct gsm58_selproc *sp, int secs, int micro)
+{
+       DEBUGP(DRR, "starting FREQUENCY search timer\n");
+       sp->timer.cb = gsm58_timer_timeout;
+       sp->timer.data = sp;
+       bsc_schedule_timer(&sp->timer, secs, micro);
+}
+
+static void gsm58_timer_stop(struct gsm58_selproc *plmn)
+{
+       if (timer_pending(&sp->timer)) {
+               DEBUGP(DRR, "stopping pending timer\n");
+               bsc_del_timer(&sp->timer);
+       }
+}
diff --git a/src/host/gsm48-andreas/gsm58.h b/src/host/gsm48-andreas/gsm58.h
new file mode 100644 (file)
index 0000000..7a93e9b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * (C) 2010 by Andreas Eversberg <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.
+ *
+ */
+
+/* GSM 05.08 events */
+#define        GSM58_EVENT_START_NORMAL        1
+#define        GSM58_EVENT_START_STORED        2
+#define        GSM58_EVENT_START_ANY           3
+#define        GSM58_EVENT_TIMEOUT             4
+#define        GSM58_EVENT_SYNC                5
+#define        GSM58_EVENT_SYSINFO             6
+#define        GSM58_EVENT_    7
+#define        GSM58_EVENT_    8
+#define        GSM58_EVENT_    9
+#define        GSM58_EVENT_    10
+#define        GSM58_EVENT_    11
+#define        GSM58_EVENT_    12
+
+case GSM58_EVENT_START_NORMAL_SEL:
+gsm58_start_normal_sel(ms, msg);
+break;
+case GSM58_EVENT_START_STORED_SEL:
+gsm58_start_stored_sel(ms, msg);
+break;
+case GSM58_EVENT_START_ANY_SEL:
+gsm58_start_any_sel(ms, msg);
+break;
+case GSM58_EVENT_TIMEOUT:
+gsm58_sel_timeout(ms, msg);
+break;
+case GSM58_EVENT_SYNC:
+gsm58_sel_sync(ms, msg);
+break;
+case GSM58_EVENT_SYSINFO:
+gsm58_sel_sysinfo(ms, msg);
+break;
+
+enum {
+       GSM58_MODE_IDLE,
+       GSM58_MODE_SYNC,
+       GSM58_MODE_READ,
+       GSM58_MODE_CAMP
+};
+
+/* GSM 05.08 message */
+struct gsm58_msg {
+       int                     msg_type;
+       uint16_t                mcc;
+       uint16_t                mnc;
+       uint8_t                 ba[128];
+       uint16_t                arfcn;
+};
+
+#define        GSM58_ALLOC_SIZE        sizeof(struct gsm58_mgs)
+#define GSM58_ALLOC_HEADROOM   0
+
+/* GSM 05.08 selection process */
+struct gsm58_selproc {
+       int                     mode;
+       uint16_t                mcc;
+       uint16_t                mnc;
+       uint8_t                 ba[128];
+       uint16_t                cur_freq; /* index */
+       uint16_t                arfcn; /* channel number */
+};
+
+