Hi,List<br> I found BB is a great project,and I want to study it. In my test network without encryption, I test the burst_id with dsp patch to capture the SMS, and also ,I patch the ccch_scan to capture the voice,but I met a few difficulty, but the amr voice file seems not good, I found it hard to find the error, anyone can help me? Thanks!<br>
the patch is following:<br><br>static struct {<br>    int            has_si1;<br>    int            has_si3;<br>    int            ccch_mode;<br>    int            neci; <br>    int            sys_count;<br>        <br>    enum dch_state_t    dch_state;<br>
    uint8_t            dch_nr;<br>    int            dch_badcnt;<br>    int            dch_ciph;<br><br>    FILE *            fh;<br><br>    sbit_t            bursts_dl[116 * 4];<br>    sbit_t            bursts_ul[116 * 4];<br>
    sbit_t            bursts_ccch[4][116*4];<br>    sbit_t            mI[8][114];<br><br>    struct gsm_sysinfo_freq    cell_arfcns[1024];<br><br>    uint8_t            kc[8];<br>} app_state;<br><br>static char *<br>void layer3_rx_burst(struct osmocom_ms *ms, struct msgb *msg)<br>
{<br>    struct l1ctl_burst_ind *bi;<br>    int16_t rx_dbm;<br>    uint16_t arfcn;<br>    int ul,do_rel=0;<br><br>    /* Header handling */<br>    bi = (struct l1ctl_burst_ind *) msg->l1h;<br><br>    arfcn = ntohs(bi->band_arfcn);<br>
    rx_dbm = rxlev2dbm(bi->rx_level);<br>    ul = !!(arfcn & ARFCN_UPLINK);<br><br>    if (app_state.dch_state == DCH_NONE)<br>        local_ccch_burst_decode(bi,ms);<br>    /* Check for channel start */<br>    if (app_state.dch_state == DCH_WAIT_EST) {<br>
        if (bi->chan_nr == app_state.dch_nr) {<br>            if (bi->snr > 64) {<br>                /* Change state */<br>                app_state.dch_state = DCH_ACTIVE;<br>                app_state.dch_badcnt = 0;<br>
<br>                /* Open output */<br>                //app_state.fh = fopen(gen_filename(ms, bi), "wb");<br>            } else {<br>                /* Abandon ? */<br>                do_rel = (app_state.dch_badcnt++) >= 4;<br>
            }<br>        }<br>    }<br><br>    /* Check for channel end */<br>    if (app_state.dch_state == DCH_ACTIVE) {<br>        if (!ul) {<br>            /* Bad burst counting */<br>            if (bi->snr < 64)<br>
                {<br>                    app_state.dch_badcnt++;<br>                    printf("sdcch app_state.dch_badcnt++\n");<br>                }<br>            else if (app_state.dch_badcnt >= 2)<br>                app_state.dch_badcnt -= 2;<br>
            else<br>                app_state.dch_badcnt = 0;<br><br>            /* Release condition */<br>            do_rel = app_state.dch_badcnt >= 6;<br>        }<br>    }<br><br>    // when in TCH mode, we only measure the SACCH to kown the link quanlity<br>
    if (app_state.dch_state == DCH_TCH) {<br>        //printf("app_state.dch_state == DCH_TCH\n");<br>        if (!ul && (bi->flags & BI_FLG_SACCH)) {<br>            //printf("TCH SACCH\n");<br>
            /* Bad burst counting */<br>            if (bi->snr < 40)<br>                {<br>                    app_state.dch_badcnt++;<br>                    printf("sacch app_state.dch_badcnt++\n");<br>
                }<br>            else if (app_state.dch_badcnt >= 2)<br>                app_state.dch_badcnt -= 2;<br>            else<br>                app_state.dch_badcnt = 0;<br><br>            /* Release condition */<br>
            do_rel = app_state.dch_badcnt >= 6;<br>        }<br>    }<br><br>    /* Release ? */<br>    if (do_rel) {<br>        printf("The Delicate Channel is released because of bad SNR!\n");<br>        /* L1 release */<br>
        l1ctl_tx_dm_rel_req(ms);<br>        l1ctl_tx_fbsb_req(ms, ms->test_arfcn,<br>                L1CTL_FBSB_F_FB01SB, 100, 0,<br>                app_state.ccch_mode);<br><br>        /* Change state */<br>        app_state.dch_state = DCH_WAIT_REL;<br>
        app_state.dch_badcnt = 0;<br>        app_state.dch_ciph = 0;<br><br>        /* Close output */<br>        if (app_state.fh) {<br>            fclose(app_state.fh);<br>            app_state.fh = NULL;<br>        }<br>
    }<br><br>    /* Save the burst */<br>    if (app_state.dch_state == DCH_ACTIVE || app_state.dch_state == DCH_TCH)<br>        //fwrite(bi, sizeof(*bi), 1, app_state.fh);<br><br>    /* Try local decoding */<br>    if (!ul && (app_state.dch_state == DCH_ACTIVE || app_state.dch_state == DCH_TCH))<br>
        local_burst_decode(ms,bi);<br>}<br><br>static void<br>local_burst_decode(struct osmocom_ms *ms,struct l1ctl_burst_ind *bi)<br>{<br>    int16_t rx_dbm;<br>    uint16_t arfcn;<br>    uint32_t fn;<br>    uint8_t cbits, tn, lch_idx;<br>
    int ul, bid, i, d_tch_mode;<br>    sbit_t *bursts;<br>    ubit_t bt[116];<br><br>    /* Get params (Only for SDCCH and SACCH/{4,8,F,H}) */<br>    arfcn  = ntohs(bi->band_arfcn);<br>    rx_dbm = rxlev2dbm(bi->rx_level);<br>
<br>    fn     = ntohl(bi->frame_nr);<br>    ul     = !!(arfcn & ARFCN_UPLINK);<br>    bursts = ul ? app_state.bursts_ul : app_state.bursts_dl;<br><br>    cbits  = bi->chan_nr >> 3;<br>    tn     = bi->chan_nr & 7;<br>
<br>    bid    = -1;<br><br>    if (cbits == 0x01) {            /* TCH/F */<br>        lch_idx = 0;<br>        if (bi->flags & BI_FLG_SACCH) {<br>            uint32_t fn_report;<br>            fn_report = (fn - (tn * 13) + 104) % 104;<br>
            bid = (fn_report - 12) / 26;<br>            printf(" SACCH fn = %d fn_report = %d\n",fn,fn_report);<br>        }else{<br>            //printf(" TCH/F \n");<br>            process_tch_f(ms,bi);            <br>
        }<br>    } else if ((cbits & 0x1e) == 0x02) {    /* TCH/H */<br>        lch_idx = cbits & 1;<br>        if (bi->flags & BI_FLG_SACCH) {<br>            uint32_t fn_report;<br>            uint8_t tn_report = (tn & ~1) | lch_idx;<br>
            fn_report = (fn - (tn_report * 13) + 104) % 104;<br>            bid = (fn_report - 12) / 26;<br>        }<br>    } else if ((cbits & 0x1c) == 0x04) {    /* SDCCH/4 */<br>        lch_idx = cbits & 3;<br>
        bid = bi->flags & 3;<br>        printf(" SDCCH/4\n");<br>    } else if ((cbits & 0x18) == 0x08) {    /* SDCCH/8 */<br>        lch_idx = cbits & 7;<br>        bid = bi->flags & 3;<br>
        //printf(" SDCCH/8\n");<br>    }<br><br>    if (bid == -1)<br>        return;<br><br>    /* Clear if new set */<br>    if (bid == 0)<br>        memset(bursts, 0x00, 116 * 4);<br><br>    /* Unpack (ignore hu/hl) */<br>
    osmo_pbit2ubit_ext(bt,  0, bi->bits,  0, 57, 0);<br>    osmo_pbit2ubit_ext(bt, 59, bi->bits, 57, 57, 0);<br>    bt[57] = bt[58] = 1;<br><br>    /* A5/x */<br>    if (app_state.dch_ciph) {<br>        ubit_t ks_dl[114], ks_ul[114], *ks = ul ? ks_ul : ks_dl;<br>
        osmo_a5(app_state.dch_ciph, app_state.kc, fn, ks_dl, ks_ul);<br>        for (i= 0; i< 57; i++)  bt[i] ^= ks[i];<br>        for (i=59; i<116; i++)  bt[i] ^= ks[i-2];<br>    }<br><br>    /* Convert to softbits */<br>
    for (i=0; i<116; i++)<br>        bursts[(116*bid)+i] = bt[i] ? - (bi->snr >> 1) : (bi->snr >> 1);<br><br>    /* If last, decode */<br>    if (bid == 3)<br>    {<br>        uint8_t l2[23];<br>        int rv,i;<br>
        struct  gsm48_ass_cmd *ia;<br>        uint8_t ch_type, ch_subch, ch_ts;<br>        uint8_t chan_req_val, chan_req_mask, ra;<br><br>        rv = xcch_decode(l2, bursts);<br><br>        if((l2[0] == 0x03) && (l2[4] == 0x2e))<br>
        {<br>            ia =(struct  gsm48_ass_cmd *)&l2[5];<br><br>            rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);<br>            //l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);<br>
            printf("Jump to TCH Channel\n");<br>            <br>            d_tch_mode = GSM48_CMODE_SPEECH_EFR;<br>            /* open speech file and configure d_tch_decoders */<br>            switch (d_tch_mode) {<br>
            <br>            case GSM48_CMODE_SPEECH_V1:<br>                d_speech_file = fopen( "speech.au.gsm", "wb" );<br>                break;<br>            <br>            case GSM48_CMODE_SPEECH_EFR:<br>
                d_speech_file = fopen( gen_filename(ms,bi), "wb" );<br>                fwrite(amr_nb_magic, 1, 6, d_speech_file); /* Write header */<br>                break;<br>            <br>            default:<br>
                d_speech_file = NULL;<br><br>  }            <br>            app_state.dch_state = DCH_TCH;<br>            <br>            if (!ia->chan_desc.h0.h) {<br>                /* Non-hopping */<br>                uint16_t arfcn;<br>
        <br>                arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);<br>        <br>                LOGP(DRR, LOGL_NOTICE, "ASS CMD(chan_nr=0x%02x, "<br>                    "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ",<br>
                    ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,<br>                    ia->chan_desc.h0.tsc);<br>        <br>                /* request L1 to go to dedicated mode on assigned channel */<br>                rv = l1ctl_tx_dm_est_req_h0(ms,<br>
                    arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,<br>                    GSM48_CMODE_SPEECH_EFR, 0);<br>            }<br>        #ifdef TCH_HOPPING    <br>             else { <br>                /* Hopping is not support now! */<br>
                uint8_t maio, hsn, ma_len;<br>                uint16_t ma[64], arfcn;<br>                int i, j, k;<br>        <br>                hsn = ia->chan_desc.h1.hsn;<br>                maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);<br>
        <br>                LOGP(DRR, LOGL_NOTICE, "ASS CMD( chan_nr=0x%02x, "<br>                    "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ",<br>                    ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,<br>
                    ia->chan_desc.h1.tsc);<br>        <br>                /* decode mobile allocation */<br>                ma_len = 0;<br>                for (i=1, j=0; i<=1024; i++) {<br>                    arfcn = i & 1023;<br>
                    if (app_state.cell_arfcns[arfcn].mask & 0x01) {<br>                        k = ia->mob_alloc_len - (j>>3) - 1;<br>                        if (ia->mob_alloc[k] & (1 << (j&7))) {<br>
                            ma[ma_len++] = arfcn;<br>                        }<br>                        j++;<br>                    }<br>                }<br>                <br>                /* request L1 to go to dedicated mode on assigned channel */<br>
                rv = l1ctl_tx_dm_est_req_h1(ms,<br>                    maio, hsn, ma, ma_len,<br>                    ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,<br>                    GSM48_CMODE_SPEECH_EFR, 0);<br>
            }<br>        #endif<br>        }<br><br>        if (rv == 0)<br>        {<br>            uint8_t chan_type, chan_ts, chan_ss;<br>            uint8_t gsmtap_chan_type;<br><br>            /* Send to GSMTAP */<br>
            rsl_dec_chan_nr(bi->chan_nr, &chan_type, &chan_ss, &chan_ts);<br>            gsmtap_chan_type = chantype_rsl2gsmtap(<br>                chan_type,<br>                bi->flags & BI_FLG_SACCH ? 0x40 : 0x00<br>
            );<br>            gsmtap_send(gsmtap_inst,<br>                arfcn, chan_ts, gsmtap_chan_type, chan_ss,<br>                ntohl(bi->frame_nr), bi->rx_level, bi->snr,<br>                l2, sizeof(l2)<br>
            );<br><br>            /* Crude CIPH.MOD.COMMAND detect */<br>            if ((l2[3] == 0x06) && (l2[4] == 0x35) && (l2[5] & 1))<br>                app_state.dch_ciph = 1 + ((l2[5] >> 1) & 7);<br>
        }<br>    }<br>}<br><br>void tch_deinterleave(ubit_t *mC, int blockOffset)<br>{<br>    int k;<br>    for (k = 0; k < 456; k++) {<br>        int B = ( k + blockOffset ) % 8;<br>        int j = 2 * ((49 * k) % 57) + ((k % 8) / 4);<br>
        mC[k] = app_state.mI[B][j];<br>        app_state.mI[B][j] = 0;<br>        //OBJDCOUT("deinterleave k="<<k<<" B="<<B<<" j="<<j);<br>    }<br>} <br><br>void tch_unmap(const uint16_t *map, size_t mapSize, ubit_t * dest, ubit_t * soure)<br>
{<br>    unsigned int i;<br>    for(i=0; i<mapSize; i++)<br>    {<br>        dest[map[i]] = soure[i];<br>    }<br>}<br><br>void tch_map(const uint16_t *map, size_t mapSize, ubit_t * dest, ubit_t * soure)<br>{<br>    unsigned int i;<br>
    for(i=0; i<mapSize; i++)<br>    {<br>        dest[i] = soure[map[i]];<br>    }<br>}<br><br>void fillField(ubit_t *mStart, size_t writeIndex, uint64_t value, unsigned length)<br>{<br>    char *dpBase = mStart + writeIndex;<br>
    char *dp = dpBase + length - 1;<br><br>    while (dp>=dpBase) {<br>        *dp-- = value & 0x01;<br>        value >>= 1;<br>    }<br>}<br><br>uint64_t count_tch = 0;<br><br>static void process_tch_f(struct osmocom_ms *ms,struct l1ctl_burst_ind *bi)<br>
{<br>    int16_t rx_dbm;<br>    uint16_t arfcn;<br>    uint32_t fn,B;<br>    uint8_t cbits, tn, lch_idx;<br>    int ul, bid, i, k, length;<br>    sbit_t *bursts, mC[456];<br>    ubit_t bt[114],convu[189],convd[189],tch_raw[260],TCHW[260],EFRBits[244],EFRAMR[8 + 244];<br>
<br>    pbit_t voice[33];<br>    /* Get params (Only for SDCCH and SACCH/{4,8,F,H}) */<br>    arfcn  = ntohs(bi->band_arfcn);<br>    rx_dbm = rxlev2dbm(bi->rx_level);<br><br>    fn     = ntohl(bi->frame_nr);<br>    ul     = !!(arfcn & ARFCN_UPLINK);<br>
<br>    cbits  = bi->chan_nr >> 3;<br>    tn     = bi->chan_nr & 7;<br><br>    B  = -1;<br>    <br>    B = count_tch % 8;<br><br>    if (B == -1)<br>        return;<br><br>    /* Clear if new set */<br>    if (B == 0){<br>
        for(i=0; i<4; i++){<br>            memset(app_state.mI[i], 0x00, 114);<br>        }<br>    }else if(B == 4){<br>        for(i=4; i<8; i++){<br>            memset(app_state.mI[i], 0x00, 114);<br>        }        <br>
    }<br><br>    /* Unpack (ignore hu/hl) */<br>    osmo_pbit2ubit_ext(bt,  0, bi->bits,  0, 57, 0);<br>    osmo_pbit2ubit_ext(bt, 57, bi->bits, 57, 57, 0);<br><br>    /* Convert to softbits */<br>    for (i=0; i<114; i++)<br>
        app_state.mI[B][i] = bt[i] ? - (bi->snr >> 1) : (bi->snr >> 1);<br>    <br>    count_tch++;    <br>    // Deinterleave according to the diagonal "phase" of B.<br>    // See GSM 05.03 3.1.3.<br>
    // Deinterleaves i[] to c[]<br>    if((B % 4 ==3)&&(count_tch >= 7)){<br>        if(B == 3)<br>        {<br>            tch_deinterleave(mC, 4);<br>        }else{<br>            tch_deinterleave(mC, 0);<br>
        }<br><br>        for (k = 0; k < 78; k++) {<br>            tch_raw[182 + k] = mC[378 +k];<br>        }<br>    <br>        osmo_conv_decode(&conv_tch_afs_12_2, mC, convu);<br><br>        // 3.1.2.1<br>        // copy class 1 bits u[] to d[]<br>
        for (k = 0; k <= 90; k++) {<br>            convd[2*k] = convu[k];<br>            convd[2*k+1] = convu[184-k];<br>        }<br>        <br>        memcpy(tch_raw,convd,182);    // the last 78 bit has been stored!<br>
<br>        //now only process EFR or AMR 12_2, fix me!<br>        tch_unmap(gsm660_bitorder, 260, TCHW, tch_raw);<br><br>        // Remove repeating bits and CRC to get raw EFR frame (244 bits)<br>        for (k=0; k<71; k++)<br>
        EFRBits[k] = TCHW[k] & 1;<br>    <br>        for (k=73; k<123; k++)<br>        EFRBits[k-2] = TCHW[k] & 1;<br>    <br>        for (k=125; k<178; k++)<br>        EFRBits[k-4] = TCHW[k] & 1;<br>    <br>
        for (k=180; k<230; k++)<br>        EFRBits[k-6] = TCHW[k] & 1;<br>    <br>        for (k=232; k<252; k++)<br>        EFRBits[k-8] = TCHW[k] & 1;<br>    <br>        // Map bits as AMR 12.2k<br>        tch_map(gsm690_12_2_bitorder, 244, EFRAMR + 8,EFRBits);<br>
    <br>        // Put the whole frame (hdr + payload)<br>        //mVFrameAMR.pack(mPrevGoodFrame);<br>        //mPrevGoodFrameLength = 32;<br>        fillField(EFRAMR, 0, 0x3c, 8);<br>        voice[32] = 0;<br>        length = osmo_ubit2pbit(voice, EFRAMR, 8 + 244);<br>
        fwrite(voice, 1, 32, d_speech_file);        <br>    }<br>    <br>}<br><br>