my patch for decode using burst_id

classic Classic list List threaded Threaded
10 messages Options
bob
Reply | Threaded
Open this post in threaded view
|

my patch for decode using burst_id

bob
Hi,List
 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!
the patch is following:

static struct {
    int            has_si1;
    int            has_si3;
    int            ccch_mode;
    int            neci;
    int            sys_count;
       
    enum dch_state_t    dch_state;
    uint8_t            dch_nr;
    int            dch_badcnt;
    int            dch_ciph;

    FILE *            fh;

    sbit_t            bursts_dl[116 * 4];
    sbit_t            bursts_ul[116 * 4];
    sbit_t            bursts_ccch[4][116*4];
    sbit_t            mI[8][114];

    struct gsm_sysinfo_freq    cell_arfcns[1024];

    uint8_t            kc[8];
} app_state;

static char *
void layer3_rx_burst(struct osmocom_ms *ms, struct msgb *msg)
{
    struct l1ctl_burst_ind *bi;
    int16_t rx_dbm;
    uint16_t arfcn;
    int ul,do_rel=0;

    /* Header handling */
    bi = (struct l1ctl_burst_ind *) msg->l1h;

    arfcn = ntohs(bi->band_arfcn);
    rx_dbm = rxlev2dbm(bi->rx_level);
    ul = !!(arfcn & ARFCN_UPLINK);

    if (app_state.dch_state == DCH_NONE)
        local_ccch_burst_decode(bi,ms);
    /* Check for channel start */
    if (app_state.dch_state == DCH_WAIT_EST) {
        if (bi->chan_nr == app_state.dch_nr) {
            if (bi->snr > 64) {
                /* Change state */
                app_state.dch_state = DCH_ACTIVE;
                app_state.dch_badcnt = 0;

                /* Open output */
                //app_state.fh = fopen(gen_filename(ms, bi), "wb");
            } else {
                /* Abandon ? */
                do_rel = (app_state.dch_badcnt++) >= 4;
            }
        }
    }

    /* Check for channel end */
    if (app_state.dch_state == DCH_ACTIVE) {
        if (!ul) {
            /* Bad burst counting */
            if (bi->snr < 64)
                {
                    app_state.dch_badcnt++;
                    printf("sdcch app_state.dch_badcnt++\n");
                }
            else if (app_state.dch_badcnt >= 2)
                app_state.dch_badcnt -= 2;
            else
                app_state.dch_badcnt = 0;

            /* Release condition */
            do_rel = app_state.dch_badcnt >= 6;
        }
    }

    // when in TCH mode, we only measure the SACCH to kown the link quanlity
    if (app_state.dch_state == DCH_TCH) {
        //printf("app_state.dch_state == DCH_TCH\n");
        if (!ul && (bi->flags & BI_FLG_SACCH)) {
            //printf("TCH SACCH\n");
            /* Bad burst counting */
            if (bi->snr < 40)
                {
                    app_state.dch_badcnt++;
                    printf("sacch app_state.dch_badcnt++\n");
                }
            else if (app_state.dch_badcnt >= 2)
                app_state.dch_badcnt -= 2;
            else
                app_state.dch_badcnt = 0;

            /* Release condition */
            do_rel = app_state.dch_badcnt >= 6;
        }
    }

    /* Release ? */
    if (do_rel) {
        printf("The Delicate Channel is released because of bad SNR!\n");
        /* L1 release */
        l1ctl_tx_dm_rel_req(ms);
        l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
                L1CTL_FBSB_F_FB01SB, 100, 0,
                app_state.ccch_mode);

        /* Change state */
        app_state.dch_state = DCH_WAIT_REL;
        app_state.dch_badcnt = 0;
        app_state.dch_ciph = 0;

        /* Close output */
        if (app_state.fh) {
            fclose(app_state.fh);
            app_state.fh = NULL;
        }
    }

    /* Save the burst */
    if (app_state.dch_state == DCH_ACTIVE || app_state.dch_state == DCH_TCH)
        //fwrite(bi, sizeof(*bi), 1, app_state.fh);

    /* Try local decoding */
    if (!ul && (app_state.dch_state == DCH_ACTIVE || app_state.dch_state == DCH_TCH))
        local_burst_decode(ms,bi);
}

static void
local_burst_decode(struct osmocom_ms *ms,struct l1ctl_burst_ind *bi)
{
    int16_t rx_dbm;
    uint16_t arfcn;
    uint32_t fn;
    uint8_t cbits, tn, lch_idx;
    int ul, bid, i, d_tch_mode;
    sbit_t *bursts;
    ubit_t bt[116];

    /* Get params (Only for SDCCH and SACCH/{4,8,F,H}) */
    arfcn  = ntohs(bi->band_arfcn);
    rx_dbm = rxlev2dbm(bi->rx_level);

    fn     = ntohl(bi->frame_nr);
    ul     = !!(arfcn & ARFCN_UPLINK);
    bursts = ul ? app_state.bursts_ul : app_state.bursts_dl;

    cbits  = bi->chan_nr >> 3;
    tn     = bi->chan_nr & 7;

    bid    = -1;

    if (cbits == 0x01) {            /* TCH/F */
        lch_idx = 0;
        if (bi->flags & BI_FLG_SACCH) {
            uint32_t fn_report;
            fn_report = (fn - (tn * 13) + 104) % 104;
            bid = (fn_report - 12) / 26;
            printf(" SACCH fn = %d fn_report = %d\n",fn,fn_report);
        }else{
            //printf(" TCH/F \n");
            process_tch_f(ms,bi);           
        }
    } else if ((cbits & 0x1e) == 0x02) {    /* TCH/H */
        lch_idx = cbits & 1;
        if (bi->flags & BI_FLG_SACCH) {
            uint32_t fn_report;
            uint8_t tn_report = (tn & ~1) | lch_idx;
            fn_report = (fn - (tn_report * 13) + 104) % 104;
            bid = (fn_report - 12) / 26;
        }
    } else if ((cbits & 0x1c) == 0x04) {    /* SDCCH/4 */
        lch_idx = cbits & 3;
        bid = bi->flags & 3;
        printf(" SDCCH/4\n");
    } else if ((cbits & 0x18) == 0x08) {    /* SDCCH/8 */
        lch_idx = cbits & 7;
        bid = bi->flags & 3;
        //printf(" SDCCH/8\n");
    }

    if (bid == -1)
        return;

    /* Clear if new set */
    if (bid == 0)
        memset(bursts, 0x00, 116 * 4);

    /* Unpack (ignore hu/hl) */
    osmo_pbit2ubit_ext(bt,  0, bi->bits,  0, 57, 0);
    osmo_pbit2ubit_ext(bt, 59, bi->bits, 57, 57, 0);
    bt[57] = bt[58] = 1;

    /* A5/x */
    if (app_state.dch_ciph) {
        ubit_t ks_dl[114], ks_ul[114], *ks = ul ? ks_ul : ks_dl;
        osmo_a5(app_state.dch_ciph, app_state.kc, fn, ks_dl, ks_ul);
        for (i= 0; i< 57; i++)  bt[i] ^= ks[i];
        for (i=59; i<116; i++)  bt[i] ^= ks[i-2];
    }

    /* Convert to softbits */
    for (i=0; i<116; i++)
        bursts[(116*bid)+i] = bt[i] ? - (bi->snr >> 1) : (bi->snr >> 1);

    /* If last, decode */
    if (bid == 3)
    {
        uint8_t l2[23];
        int rv,i;
        struct  gsm48_ass_cmd *ia;
        uint8_t ch_type, ch_subch, ch_ts;
        uint8_t chan_req_val, chan_req_mask, ra;

        rv = xcch_decode(l2, bursts);

        if((l2[0] == 0x03) && (l2[4] == 0x2e))
        {
            ia =(struct  gsm48_ass_cmd *)&l2[5];

            rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
            //l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
            printf("Jump to TCH Channel\n");
           
            d_tch_mode = GSM48_CMODE_SPEECH_EFR;
            /* open speech file and configure d_tch_decoders */
            switch (d_tch_mode) {
           
            case GSM48_CMODE_SPEECH_V1:
                d_speech_file = fopen( "speech.au.gsm", "wb" );
                break;
           
            case GSM48_CMODE_SPEECH_EFR:
                d_speech_file = fopen( gen_filename(ms,bi), "wb" );
                fwrite(amr_nb_magic, 1, 6, d_speech_file); /* Write header */
                break;
           
            default:
                d_speech_file = NULL;

  }           
            app_state.dch_state = DCH_TCH;
           
            if (!ia->chan_desc.h0.h) {
                /* Non-hopping */
                uint16_t arfcn;
       
                arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
       
                LOGP(DRR, LOGL_NOTICE, "ASS CMD(chan_nr=0x%02x, "
                    "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ",
                    ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
                    ia->chan_desc.h0.tsc);
       
                /* request L1 to go to dedicated mode on assigned channel */
                rv = l1ctl_tx_dm_est_req_h0(ms,
                    arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
                    GSM48_CMODE_SPEECH_EFR, 0);
            }
        #ifdef TCH_HOPPING   
             else {
                /* Hopping is not support now! */
                uint8_t maio, hsn, ma_len;
                uint16_t ma[64], arfcn;
                int i, j, k;
       
                hsn = ia->chan_desc.h1.hsn;
                maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
       
                LOGP(DRR, LOGL_NOTICE, "ASS CMD( chan_nr=0x%02x, "
                    "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ",
                    ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
                    ia->chan_desc.h1.tsc);
       
                /* decode mobile allocation */
                ma_len = 0;
                for (i=1, j=0; i<=1024; i++) {
                    arfcn = i & 1023;
                    if (app_state.cell_arfcns[arfcn].mask & 0x01) {
                        k = ia->mob_alloc_len - (j>>3) - 1;
                        if (ia->mob_alloc[k] & (1 << (j&7))) {
                            ma[ma_len++] = arfcn;
                        }
                        j++;
                    }
                }
               
                /* request L1 to go to dedicated mode on assigned channel */
                rv = l1ctl_tx_dm_est_req_h1(ms,
                    maio, hsn, ma, ma_len,
                    ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
                    GSM48_CMODE_SPEECH_EFR, 0);
            }
        #endif
        }

        if (rv == 0)
        {
            uint8_t chan_type, chan_ts, chan_ss;
            uint8_t gsmtap_chan_type;

            /* Send to GSMTAP */
            rsl_dec_chan_nr(bi->chan_nr, &chan_type, &chan_ss, &chan_ts);
            gsmtap_chan_type = chantype_rsl2gsmtap(
                chan_type,
                bi->flags & BI_FLG_SACCH ? 0x40 : 0x00
            );
            gsmtap_send(gsmtap_inst,
                arfcn, chan_ts, gsmtap_chan_type, chan_ss,
                ntohl(bi->frame_nr), bi->rx_level, bi->snr,
                l2, sizeof(l2)
            );

            /* Crude CIPH.MOD.COMMAND detect */
            if ((l2[3] == 0x06) && (l2[4] == 0x35) && (l2[5] & 1))
                app_state.dch_ciph = 1 + ((l2[5] >> 1) & 7);
        }
    }
}

void tch_deinterleave(ubit_t *mC, int blockOffset)
{
    int k;
    for (k = 0; k < 456; k++) {
        int B = ( k + blockOffset ) % 8;
        int j = 2 * ((49 * k) % 57) + ((k % 8) / 4);
        mC[k] = app_state.mI[B][j];
        app_state.mI[B][j] = 0;
        //OBJDCOUT("deinterleave k="<<k<<" B="<<B<<" j="<<j);
    }
}

void tch_unmap(const uint16_t *map, size_t mapSize, ubit_t * dest, ubit_t * soure)
{
    unsigned int i;
    for(i=0; i<mapSize; i++)
    {
        dest[map[i]] = soure[i];
    }
}

void tch_map(const uint16_t *map, size_t mapSize, ubit_t * dest, ubit_t * soure)
{
    unsigned int i;
    for(i=0; i<mapSize; i++)
    {
        dest[i] = soure[map[i]];
    }
}

void fillField(ubit_t *mStart, size_t writeIndex, uint64_t value, unsigned length)
{
    char *dpBase = mStart + writeIndex;
    char *dp = dpBase + length - 1;

    while (dp>=dpBase) {
        *dp-- = value & 0x01;
        value >>= 1;
    }
}

uint64_t count_tch = 0;

static void process_tch_f(struct osmocom_ms *ms,struct l1ctl_burst_ind *bi)
{
    int16_t rx_dbm;
    uint16_t arfcn;
    uint32_t fn,B;
    uint8_t cbits, tn, lch_idx;
    int ul, bid, i, k, length;
    sbit_t *bursts, mC[456];
    ubit_t bt[114],convu[189],convd[189],tch_raw[260],TCHW[260],EFRBits[244],EFRAMR[8 + 244];

    pbit_t voice[33];
    /* Get params (Only for SDCCH and SACCH/{4,8,F,H}) */
    arfcn  = ntohs(bi->band_arfcn);
    rx_dbm = rxlev2dbm(bi->rx_level);

    fn     = ntohl(bi->frame_nr);
    ul     = !!(arfcn & ARFCN_UPLINK);

    cbits  = bi->chan_nr >> 3;
    tn     = bi->chan_nr & 7;

    B  = -1;
   
    B = count_tch % 8;

    if (B == -1)
        return;

    /* Clear if new set */
    if (B == 0){
        for(i=0; i<4; i++){
            memset(app_state.mI[i], 0x00, 114);
        }
    }else if(B == 4){
        for(i=4; i<8; i++){
            memset(app_state.mI[i], 0x00, 114);
        }       
    }

    /* Unpack (ignore hu/hl) */
    osmo_pbit2ubit_ext(bt,  0, bi->bits,  0, 57, 0);
    osmo_pbit2ubit_ext(bt, 57, bi->bits, 57, 57, 0);

    /* Convert to softbits */
    for (i=0; i<114; i++)
        app_state.mI[B][i] = bt[i] ? - (bi->snr >> 1) : (bi->snr >> 1);
   
    count_tch++;   
    // Deinterleave according to the diagonal "phase" of B.
    // See GSM 05.03 3.1.3.
    // Deinterleaves i[] to c[]
    if((B % 4 ==3)&&(count_tch >= 7)){
        if(B == 3)
        {
            tch_deinterleave(mC, 4);
        }else{
            tch_deinterleave(mC, 0);
        }

        for (k = 0; k < 78; k++) {
            tch_raw[182 + k] = mC[378 +k];
        }
   
        osmo_conv_decode(&conv_tch_afs_12_2, mC, convu);

        // 3.1.2.1
        // copy class 1 bits u[] to d[]
        for (k = 0; k <= 90; k++) {
            convd[2*k] = convu[k];
            convd[2*k+1] = convu[184-k];
        }
       
        memcpy(tch_raw,convd,182);    // the last 78 bit has been stored!

        //now only process EFR or AMR 12_2, fix me!
        tch_unmap(gsm660_bitorder, 260, TCHW, tch_raw);

        // Remove repeating bits and CRC to get raw EFR frame (244 bits)
        for (k=0; k<71; k++)
        EFRBits[k] = TCHW[k] & 1;
   
        for (k=73; k<123; k++)
        EFRBits[k-2] = TCHW[k] & 1;
   
        for (k=125; k<178; k++)
        EFRBits[k-4] = TCHW[k] & 1;
   
        for (k=180; k<230; k++)
        EFRBits[k-6] = TCHW[k] & 1;
   
        for (k=232; k<252; k++)
        EFRBits[k-8] = TCHW[k] & 1;
   
        // Map bits as AMR 12.2k
        tch_map(gsm690_12_2_bitorder, 244, EFRAMR + 8,EFRBits);
   
        // Put the whole frame (hdr + payload)
        //mVFrameAMR.pack(mPrevGoodFrame);
        //mPrevGoodFrameLength = 32;
        fillField(EFRAMR, 0, 0x3c, 8);
        voice[32] = 0;
        length = osmo_ubit2pbit(voice, EFRAMR, 8 + 244);
        fwrite(voice, 1, 32, d_speech_file);       
    }
   
}

Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

Harald Welte-3
Hi Bob,

On Mon, Jun 18, 2012 at 04:32:52PM +0800, bob wisebob wrote:

> the patch is following:
> [...]

whatever you sent in your message, it was not a patch.

If you would like to see anyone testing/using your code at all, then at
least you should be sending an unified diff (diff -u) to this list.

Regards,
        Harald
--
- Harald Welte <[hidden email]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

bob
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

bob
 I have done it, This my pacth for burst_id
but it can`t work well for TCH decode!app_ccch_scan.patch
bob
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

bob
In reply to this post by bob
 I think the key importance is the codec mode indication of AMR, in my test network, the channel mode  is speed full rate and half rate version 3;   anyone familiar with it?
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

lonelysurfer
In reply to this post by bob
I want to compare the decoding with airprobe.
For this I need a gsm-receiver cfile with EFR data.
Does someone have such a file?
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

lonelysurfer
In reply to this post by bob
AMR codec is said to have a 1 byte header.
AMR run at various bitrate 4.75, 5.15, 5.90, 6.70, 7.40, 7.95, 10.2 or
12.2 kbit/s and each bitrate provide different sized output blocks of
95, 103, 118, 134, 148, 159, 204, and 244 bits.

In the 1 byte header it's written which is the encoding bitrate of the
specific AMR 20ms encoded audio sample.
In particular the top 4 bits tell the bitrate (CMR) while the lower bits
are reserved and not used (all 0 or all 1).

*CMR*     * MODE*        *FRAME SIZE( in bytes )*
0        AMR 4.75            13
1        AMR 5.15            14
2        AMR 5.9             16
3        AMR 6.7             18
4        AMR 7.4             20
5        AMR 7.95            21
6        AMR 10.2            27
7        AMR 12.2            32

AMR Reference:
http://wiki.forum.nokia.com/index.php/AMR_format
http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec
bob
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

bob
In reply to this post by lonelysurfer
Hi, lonelysurfer:
the website https://srlabs.de/airprobe-how-to/ has a sample,
but the version of speech codec is 1,so there are much defferent
in decode the voice if your network is  AMR speech codec, so there
are much work to do,I think we must  read GSM5.09 about AMR firstly.
I am very happy to work with you about the AMR.
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

Altaf
This post was updated on .
In reply to this post by bob
Hello..

I wanted to make some testing with your patch...When I apply your patch. I get the following error..

fatal: corrupt patch at line 34


What could be the mistake.....
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

lonelysurfer
I made it by hand (copy&paste) but I missed codec.c and conv_tch_afs_12_2.
With codec.c from osmocom/codec/ and the asf tables from http://baseband-devel.722152.n3.nabble.com/libosmocore-viterbi-decoder-td2866035.html the compilation was ok.

I've found some deeper infos about asf @ http://fossies.org/dox/hxplay-11.0.0/amrdump_8cpp_source.html.

In osmocom-bb we have a dummy burst indicator (bi->flags & BI_FLG_DUMMY). I think, these bursts have to be filtered.

Perhaps its easier to begin with FR, because with the sample from https://srlabs.de/airprobe-how-to/ we have FR and with osmocom-bb (mobile_app) and old Nokias (http://www.panuworld.net/nuukiaworld/misc/netmon/tests.htm) EFR can be disabled to get FR.
Reply | Threaded
Open this post in threaded view
|

Re: my patch for decode using burst_id

Harald Welte-3
In reply to this post by bob
Dear Bob,

On Mon, Jun 18, 2012 at 04:38:55AM -0700, bob wrote:
>  I have done it, This my pacth for burst_id
> but it can`t work well for TCH decode!
> http://baseband-devel.722152.n3.nabble.com/file/n4025078/app_ccch_scan.patch
> app_ccch_scan.patch

you still hve not sent the actual patch to this mailing list.

I would appreciate if you could follow common procedures / habits of
FOSS projects and send your patches as unified diff to the mailing list
for review / comments.

Linking code published on a website that is not even online for one
month is very inefficient.  Now people can still read your mails in the
archvie but not your patch.  What a waste!

Regards,
        Harald

--
- Harald Welte <[hidden email]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)