diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2010-03-27 11:05:16 +0100 |
---|---|---|
committer | Andreas Eversberg <jolly@eversberg.eu> | 2010-03-27 11:08:47 +0100 |
commit | 413b10e33ea9c86555e87809816fc1fbeb7f1959 (patch) | |
tree | 8b4548990ea0de0247bb0a2ea2f68c934c307c47 /src/host/gsm48-andreas | |
parent | 51f1e4b8a265e98c0bf5532a41e6c0932ca9bd7f (diff) |
Added process of link control in idle mode.
The process is described in GSM 05.08 and will search and select BCCH.
The process is partly complete.
Diffstat (limited to 'src/host/gsm48-andreas')
-rw-r--r-- | src/host/gsm48-andreas/gsm58.c | 341 | ||||
-rw-r--r-- | src/host/gsm48-andreas/gsm58.h | 84 |
2 files changed, 425 insertions, 0 deletions
diff --git a/src/host/gsm48-andreas/gsm58.c b/src/host/gsm48-andreas/gsm58.c new file mode 100644 index 00000000..168ef3f6 --- /dev/null +++ b/src/host/gsm48-andreas/gsm58.c @@ -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 index 00000000..7a93e9bb --- /dev/null +++ b/src/host/gsm48-andreas/gsm58.h @@ -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 */ +}; + + |