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>