[layer23] Implementation of signal loss criteria as defined in TS 05.08
[osmocom-bb.git] / src / host / layer23 / src / mobile / gsm322.c
index fbeff2a..807c662 100644 (file)
@@ -45,6 +45,8 @@ static void gsm322_cs_loss(void *arg);
 static int gsm322_cs_select(struct osmocom_ms *ms, int any, int plmn_allowed);
 static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg);
 
+#define SKIP_MAX_PER_BAND
+
 #warning HACKING!!!
 int hack;
 
@@ -234,22 +236,29 @@ static int gsm322_sync_to_cell(struct gsm322_cellsel *cs)
 {
        struct osmocom_ms *ms = cs->ms;
        struct gsm48_sysinfo *s = cs->si;
+       struct rx_meas_stat *meas = &ms->meas;
 
-       LOGP(DCS, LOGL_INFO, "Start syncing. (ARFCN=%d)\n", cs->arfcn);
        cs->ccch_state = GSM322_CCCH_ST_INIT;
-       if (s) {
+       if (s && s->si3) {
                if (s->ccch_conf == 1) {
-                       LOGP(DCS, LOGL_INFO, "Sysinfo, ccch mode COMB\n");
+                       LOGP(DCS, LOGL_INFO, "Sync to ARFCN=%d rxlev=%s "
+                               "(Sysinfo, ccch mode COMB)\n", cs->arfcn,
+                               gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
                        cs->ccch_mode = CCCH_MODE_COMBINED;
                } else {
-                       LOGP(DCS, LOGL_INFO, "Sysinfo, ccch mode NON-COMB\n");
+                       LOGP(DCS, LOGL_INFO, "Sync to ARFCN=%d rxlev=%s "
+                               "(Sysinfo, ccch mode NON-COMB)\n", cs->arfcn,
+                               gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
                        cs->ccch_mode = CCCH_MODE_NON_COMBINED;
                }
        } else {
-               LOGP(DCS, LOGL_INFO, "No sysinfo, ccch mode NONE\n");
+               LOGP(DCS, LOGL_INFO, "Sync to ARFCN=%d rxlev=%s (No sysinfo "
+                       "yet, ccch mode NONE)\n", cs->arfcn,
+                       gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
                cs->ccch_mode = CCCH_MODE_NONE;
        }
-//     printf("s->ccch_conf %d\n", cs->si->ccch_conf);
+
+       meas->frames = meas->snr = meas->berr = meas->rxlev = 0;
 
        l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
        return l1ctl_tx_fbsb_req(ms, cs->arfcn,
@@ -260,6 +269,8 @@ static int gsm322_sync_to_cell(struct gsm322_cellsel *cs)
 static void gsm322_unselect_cell(struct gsm322_cellsel *cs)
 {
        cs->selected = 0;
+       if (cs->si)
+               cs->si->si5 = 0; /* unset SI5* */
        cs->si = NULL;
        memset(&cs->sel_si, 0, sizeof(cs->sel_si));
        cs->sel_mcc = cs->sel_mnc = cs->sel_lac = cs->sel_id = 0;
@@ -429,41 +440,17 @@ static void stop_plmn_timer(struct gsm322_plmn *plmn)
 /* start cell selection timer */
 void start_cs_timer(struct gsm322_cellsel *cs, int sec, int micro)
 {
-       LOGP(DCS, LOGL_INFO, "Starting CS timer with %d seconds.\n", sec);
+       LOGP(DCS, LOGL_DEBUG, "Starting CS timer with %d seconds.\n", sec);
        cs->timer.cb = gsm322_cs_timeout;
        cs->timer.data = cs;
        bsc_schedule_timer(&cs->timer, sec, micro);
 }
 
-/* start loss timer */
-void start_loss_timer(struct gsm322_cellsel *cs, int sec, int micro)
-{
-       /* update timer */
-       cs->timer.cb = gsm322_cs_loss;
-       cs->timer.data = cs;
-       if (bsc_timer_pending(&cs->timer)) {
-               struct timeval current_time;
-               unsigned long long currentTime;
-
-               gettimeofday(&current_time, NULL);
-               currentTime = current_time.tv_sec * 1000000LL
-                               + current_time.tv_usec;
-               currentTime += sec * 1000000LL + micro;
-               cs->timer.timeout.tv_sec = currentTime / 1000000LL;
-               cs->timer.timeout.tv_usec = currentTime % 1000000LL;
-
-               return;
-       }
-
-       LOGP(DCS, LOGL_INFO, "Starting loss CS timer with %d seconds.\n", sec);
-       bsc_schedule_timer(&cs->timer, sec, micro);
-}
-
 /* stop cell selection timer */
 static void stop_cs_timer(struct gsm322_cellsel *cs)
 {
        if (bsc_timer_pending(&cs->timer)) {
-               LOGP(DCS, LOGL_INFO, "stopping pending CS timer.\n");
+               LOGP(DCS, LOGL_DEBUG, "stopping pending CS timer.\n");
                bsc_del_timer(&cs->timer);
        }
 }
@@ -1512,11 +1499,11 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int any, int plmn_allowed)
        /* set out access class depending on the cell selection type */
        if (any) {
                acc_class = subscr->acc_class | 0x0400; /* add emergency */
-               LOGP(DCS, LOGL_INFO, "Select using access class with Emergency "
-                       "class.\n");
+               LOGP(DCS, LOGL_DEBUG, "Select using access class with "
+                       "Emergency class.\n");
        } else {
                acc_class = subscr->acc_class;
-               LOGP(DCS, LOGL_INFO, "Select using access class \n");
+               LOGP(DCS, LOGL_DEBUG, "Select using access class \n");
        }
 
        /* flags to match */
@@ -1618,7 +1605,10 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int any, int plmn_allowed)
 static int gsm322_cs_scan(struct osmocom_ms *ms)
 {
        struct gsm322_cellsel *cs = &ms->cellsel;
-       int i, j;
+       int i;
+#ifndef SKIP_MAX_PER_BAND
+       int j;
+#endif
        uint8_t mask, flags;
        uint32_t weight = 0, test = cs->scan_state;
 
@@ -1630,6 +1620,7 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                mask |= GSM322_CS_FLAG_BA;
        flags = mask; /* all masked flags are requied */
        for (i = 0; i <= 1023; i++) {
+#ifndef SKIP_MAX_PER_BAND
                /* skip if band has enough frequencies scanned (3.2.1) */
                for (j = 0; gsm_sup_smax[j].max; j++) {
                        if (gsm_sup_smax[j].end > gsm_sup_smax[j].start) {
@@ -1646,6 +1637,7 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                        if (gsm_sup_smax[j].temp == gsm_sup_smax[j].max)
                                continue;
                }
+#endif
                /* search for unscanned frequency */
                if ((cs->list[i].flags & mask) == flags) {
                        /* weight depends on the power level
@@ -1702,7 +1694,6 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
                        gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
                hack = 1;
                gsm322_sync_to_cell(cs);
-//             start_cs_timer(cs, ms->support.sync_to, 0);
 
                return 0;
        }
@@ -1795,11 +1786,10 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
 
        /* Tune to frequency for a while, to receive broadcasts. */
        cs->arfcn = weight & 1023;
-       LOGP(DCS, LOGL_INFO, "Scanning frequency %d (rxlev %s).\n", cs->arfcn,
+       LOGP(DCS, LOGL_DEBUG, "Scanning frequency %d (rxlev %s).\n", cs->arfcn,
                gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
        hack = 1;
        gsm322_sync_to_cell(cs);
-//     start_cs_timer(cs, ms->support.sync_to, 0);
 
        /* Allocate/clean system information. */
        cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_SYSINFO;
@@ -1814,12 +1804,14 @@ static int gsm322_cs_scan(struct osmocom_ms *ms)
        cs->si = cs->list[cs->arfcn].sysinfo;
 
        /* increase scan counter for each maximum scan range */
+#ifndef SKIP_MAX_PER_BAND
        if (gsm_sup_smax[j].max) {
-               LOGP(DCS, LOGL_INFO, "%d frequencies left in band %d..%d\n",
+               LOGP(DCS, LOGL_DEBUG, "%d frequencies left in band %d..%d\n",
                        gsm_sup_smax[j].max - gsm_sup_smax[j].temp,
                        gsm_sup_smax[j].start, gsm_sup_smax[j].end);
                gsm_sup_smax[j].temp++;
        }
+#endif
 
        return 0;
 }
@@ -1876,7 +1868,7 @@ static int gsm322_cs_store(struct osmocom_ms *ms)
                        cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_FORBIDD;
        }
 
-       LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell found. (rxlev %s "
+       LOGP(DCS, LOGL_DEBUG, "Scan frequency %d: Cell found. (rxlev %s "
                "mcc %s mnc %s lac %04x)\n", cs->arfcn,
                gsm_print_rxlev(cs->list[cs->arfcn].rxlev),
                gsm_print_mcc(s->mcc), gsm_print_mnc(s->mnc), s->lac);
@@ -1996,9 +1988,10 @@ struct gsm322_ba_list *gsm322_cs_sysinfo_sacch(struct osmocom_ms *ms)
                        llist_add_tail(&ba->entry, &cs->ba_list);
                }
                /* update (add) ba list */
-               memcpy(freq, ba->freq, sizeof(freq));
+               memset(freq, 0, sizeof(freq));
                for (i = 0; i <= 1023; i++) {
-                       if ((s->freq[i].mask & FREQ_TYPE_REP))
+                       if ((s->freq[i].mask & (FREQ_TYPE_SERV
+                               | FREQ_TYPE_NCELL | FREQ_TYPE_REP)))
                                freq[i >> 3] |= (1 << (i & 7));
                }
                if (!!memcmp(freq, ba->freq, sizeof(freq))) {
@@ -2036,7 +2029,7 @@ static int gsm322_store_ba_list(struct gsm322_cellsel *cs,
        freq[cs->arfcn >> 3] |= (1 << (cs->arfcn & 7));
        for (i = 0; i <= 1023; i++) {
                if ((s->freq[i].mask &
-                       (FREQ_TYPE_SERV | FREQ_TYPE_NCELL)))
+                   (FREQ_TYPE_SERV | FREQ_TYPE_NCELL | FREQ_TYPE_REP)))
                        freq[i >> 3] |= (1 << (i & 7));
        }
        if (!!memcmp(freq, ba->freq, sizeof(freq))) {
@@ -2190,7 +2183,7 @@ static int gsm322_c_scan_sysinfo_bcch(struct osmocom_ms *ms, struct msgb *msg)
          || (s->si2bis && s->nb_ext_ind_si2 && !s->nb_ext_ind_si2bis)
          || (s->si2bis && s->si2ter && s->nb_ext_ind_si2
                && s->nb_ext_ind_si2bis))) {
-               LOGP(DCS, LOGL_INFO, "Received relevant sysinfo.\n");
+               LOGP(DCS, LOGL_DEBUG, "Received relevant sysinfo.\n");
                /* stop timer */
                stop_cs_timer(cs);
 
@@ -2209,21 +2202,16 @@ static void gsm322_cs_timeout(void *arg)
        struct gsm322_cellsel *cs = arg;
        struct osmocom_ms *ms = cs->ms;
 
-       LOGP(DCS, LOGL_INFO, "Cell selection failed.\n");
-
        /* if we have no lock, we retry */
        if (cs->ccch_state != GSM322_CCCH_ST_SYNC)
-               LOGP(DCS, LOGL_INFO, "Sync timeout.\n");
+               LOGP(DCS, LOGL_INFO, "Cell selection failed, sync timeout.\n");
        else
-               LOGP(DCS, LOGL_INFO, "Read timeout.\n");
-
-       LOGP(DCS, LOGL_INFO, "Scan frequency %d: Cell not found. (rxlev %s)\n",
-               cs->arfcn, gsm_print_rxlev(cs->list[cs->arfcn].rxlev));
+               LOGP(DCS, LOGL_INFO, "Cell selection failed, read timeout.\n");
 
        /* remove system information */
        cs->list[cs->arfcn].flags &= ~GSM322_CS_FLAG_SYSINFO; 
        if (cs->list[cs->arfcn].sysinfo) {
-               LOGP(DCS, LOGL_INFO, "free sysinfo arfcn=%d\n", cs->arfcn);
+               LOGP(DCS, LOGL_DEBUG, "free sysinfo arfcn=%d\n", cs->arfcn);
                talloc_free(cs->list[cs->arfcn].sysinfo);
                cs->list[cs->arfcn].sysinfo = NULL;
                gsm322_unselect_cell(cs);
@@ -2254,7 +2242,7 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
 
        /* in case of sticking to a cell, we only select it */
        if (set->stick) {
-               LOGP(DCS, LOGL_FATAL, "Scanning power for sticked cell.\n");
+               LOGP(DCS, LOGL_DEBUG, "Scanning power for sticked cell.\n");
                i = set->stick_arfcn;
                if ((cs->list[i].flags & mask) == flags)
                        s = e = i;
@@ -2262,12 +2250,12 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
                /* search for first frequency to scan */
                if (cs->state == GSM322_C2_STORED_CELL_SEL
                 || cs->state == GSM322_C5_CHOOSE_CELL) {
-                       LOGP(DCS, LOGL_FATAL, "Scanning power for stored BA "
+                       LOGP(DCS, LOGL_DEBUG, "Scanning power for stored BA "
                                "list.\n");
                        mask |= GSM322_CS_FLAG_BA;
                        flags |= GSM322_CS_FLAG_BA;
                } else
-                       LOGP(DCS, LOGL_FATAL, "Scanning power for all "
+                       LOGP(DCS, LOGL_DEBUG, "Scanning power for all "
                                "frequencies.\n");
                for (i = 0; i <= 1023; i++) {
                        if ((cs->list[i].flags & mask) == flags) {
@@ -2341,7 +2329,6 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
                                                cs->list[cs->arfcn].rxlev));
                                hack = 1;
                                gsm322_sync_to_cell(cs);
-//                             start_cs_timer(cs, ms->support.sync_to, 0);
 
                        } else
                                new_c_state(cs, GSM322_C0_NULL);
@@ -2367,7 +2354,7 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
                }
        }
 
-       LOGP(DCS, LOGL_INFO, "Scanning frequencies. (%d..%d)\n", s, e);
+       LOGP(DCS, LOGL_DEBUG, "Scanning frequencies. (%d..%d)\n", s, e);
 
        /* start scan on radio interface */
        if (!cs->powerscan) {
@@ -2385,6 +2372,7 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
        struct osmocom_ms *ms;
        struct gsm322_cellsel *cs;
        struct osmobb_meas_res *mr;
+       struct osmobb_fbsb_res *fr;
        int i;
        int8_t rxlev;
 
@@ -2400,10 +2388,16 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                        return -EINVAL;
                i = mr->band_arfcn & 1023;
                rxlev = mr->rx_lev;
+               if ((cs->list[i].flags & GSM322_CS_FLAG_POWER)) {
+                       LOGP(DCS, LOGL_ERROR, "Getting PM for frequency %d "
+                               "twice. Overwriting the first! Please fix "
+                               "prim_pm.c\n", i);
+               }
                cs->list[i].rxlev = rxlev;
                cs->list[i].flags |= GSM322_CS_FLAG_POWER;
+               cs->list[i].flags &= ~GSM322_CS_FLAG_SIGNAL;
                /* if minimum level is reached or if we stick to a cell */
-               if (rxlev2dbm(rxlev) >= ms->support.min_rxlev_db
+               if (rxlev2dbm(rxlev) >= ms->settings.min_rxlev_db
                 || ms->settings.stick) {
                        cs->list[i].flags |= GSM322_CS_FLAG_SIGNAL;
                        LOGP(DCS, LOGL_INFO, "Found signal (frequency %d "
@@ -2412,7 +2406,7 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                }
                break;
        case S_L1CTL_PM_DONE:
-               LOGP(DCS, LOGL_INFO, "Done with power scanning range.\n");
+               LOGP(DCS, LOGL_DEBUG, "Done with power scanning range.\n");
                ms = signal_data;
                cs = &ms->cellsel;
                if (!cs->powerscan)
@@ -2420,12 +2414,16 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                gsm322_cs_powerscan(ms);
                break;
        case S_L1CTL_FBSB_RESP:
-               ms = signal_data;
+               fr = signal_data;
+               ms = fr->ms;
                cs = &ms->cellsel;
                if (cs->ccch_state == GSM322_CCCH_ST_INIT) {
-                       LOGP(DCS, LOGL_INFO, "Channel synched. (ARFCN=%d)\n",
-                               cs->arfcn);
+                       LOGP(DCS, LOGL_INFO, "Channel synched. (ARFCN=%d, "
+                               "snr=%u, BSIC=%u)\n", cs->arfcn, fr->snr,
+                               fr->bsic);
                        cs->ccch_state = GSM322_CCCH_ST_SYNC;
+                       if (cs->si)
+                               cs->si->bsic = fr->bsic;
 #if 0
                        stop_cs_timer(cs);
 
@@ -2446,17 +2444,23 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                         || cs->state == GSM322_HPLMN_SEARCH)
                                start_cs_timer(cs, ms->support.scan_to, 0);
                                        // TODO: timer depends on BCCH config
+
+                       /* set downlink signalling failure criterion */
+                       ms->meas.ds_fail = ms->meas.dsc = ms->settings.dsc_max;
+                       LOGP(DRR, LOGL_INFO, "using DSC of %d\n", ms->meas.dsc);
                }
                break;
        case S_L1CTL_FBSB_ERR:
+#if 0
                if (hack) {
                        ms = signal_data;
                        cs = &ms->cellsel;
                        gsm322_sync_to_cell(cs);
                        hack--;
-                       LOGP(DCS, LOGL_INFO, "Channel sync error, try again.\n");
+                       LOGP(DCS, LOGL_INFO, "Channel sync error, try again\n");
                        break;
                }
+#endif
                LOGP(DCS, LOGL_INFO, "Channel sync error.\n");
                ms = signal_data;
                cs = &ms->cellsel;
@@ -2467,6 +2471,11 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                else
                        gsm322_cs_timeout(cs);
                break;
+       case S_L1CTL_LOSS_IND:
+               ms = signal_data;
+               cs = &ms->cellsel;
+               gsm322_cs_loss(cs);
+               break;
        case S_L1CTL_RESET:
                ms = signal_data;
                if (ms->mmlayer.power_off_idle) {
@@ -2962,8 +2971,8 @@ static int gsm322_c_switch_on(struct osmocom_ms *ms, struct msgb *msg)
        if (!subscr->sim_valid) {
                LOGP(DCS, LOGL_INFO, "Switch on without SIM.\n");
                return gsm322_c_any_cell_sel(ms, msg);
-       LOGP(DCS, LOGL_INFO, "Switch on with SIM inserted.\n");
        }
+       LOGP(DCS, LOGL_INFO, "Switch on with SIM inserted.\n");
 
        /* stay in NULL state until PLMN is selected */
 
@@ -2990,7 +2999,7 @@ static struct plmnastatelist {
        {ALL_STATES,
         GSM322_EVENT_SWITCH_OFF, gsm322_a_switch_off},
 
-       {SBIT(GSM322_A6_NO_SIM),
+       {SBIT(GSM322_A0_NULL) | SBIT(GSM322_A6_NO_SIM),
         GSM322_EVENT_SIM_INSERT, gsm322_a_switch_on},
 
        {ALL_STATES,
@@ -3099,7 +3108,7 @@ static struct plmnmstatelist {
        {ALL_STATES,
         GSM322_EVENT_SWITCH_OFF, gsm322_m_switch_off},
 
-       {SBIT(GSM322_M5_NO_SIM),
+       {SBIT(GSM322_M0_NULL) | SBIT(GSM322_M5_NO_SIM),
         GSM322_EVENT_SIM_INSERT, gsm322_m_switch_on},
 
        {ALL_STATES,
@@ -3284,9 +3293,10 @@ int gsm322_c_event(struct osmocom_ms *ms, struct msgb *msg)
        int rc;
        int i;
 
-       LOGP(DCS, LOGL_INFO, "(ms %s) Event '%s' for Cell selection in state "
-               "'%s'\n", ms->name, get_event_name(msg_type),
-               cs_state_names[cs->state]);
+       if (msg_type != GSM322_EVENT_SYSINFO)
+               LOGP(DCS, LOGL_INFO, "(ms %s) Event '%s' for Cell selection "
+                       "in state '%s'\n", ms->name, get_event_name(msg_type),
+                       cs_state_names[cs->state]);
        /* find function for current state and message */
        for (i = 0; i < CELLSELSLLEN; i++)
                if ((msg_type == cellselstatelist[i].type)