From 31d4d5eb21655fba5081dae441cc1cfdffe857b9 Mon Sep 17 00:00:00 2001 From: Dieter Spaar Date: Thu, 29 Jul 2010 21:15:03 +0200 Subject: Implement support for TCH/FACCH on various TS including decryption --- gsm-receiver/src/lib/decoder/gsmstack.c | 92 ++++++---- gsm-receiver/src/lib/decoder/gsmstack.h | 2 +- gsm-receiver/src/lib/gsm.i | 2 +- gsm-receiver/src/lib/gsm_receiver_cf.cc | 274 ++++++++++++++++++++-------- gsm-receiver/src/lib/gsm_receiver_cf.h | 24 +-- gsm-receiver/src/lib/gsm_receiver_config.cc | 21 +++ gsm-receiver/src/lib/gsm_receiver_config.h | 23 +++ gsm-receiver/src/python/go.sh | 16 +- gsm-receiver/src/python/gsm_receive.py | 4 +- 9 files changed, 326 insertions(+), 132 deletions(-) diff --git a/gsm-receiver/src/lib/decoder/gsmstack.c b/gsm-receiver/src/lib/decoder/gsmstack.c index 3766268..e5734b9 100644 --- a/gsm-receiver/src/lib/decoder/gsmstack.c +++ b/gsm-receiver/src/lib/decoder/gsmstack.c @@ -229,9 +229,8 @@ GS_new(GS_CTX *ctx) * 142 bit */ int -GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn) +GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn, int first_burst) { -// int fn; int bsic; int ret; unsigned char *data; @@ -240,39 +239,49 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn) memset(ctx->msg, 0, sizeof(ctx->msg)); -#if 0 - if (ts != 0) { - /* non-0 timeslots should end up in PCAP */ - data = decode_cch(ctx, ctx->burst, &len); - if (data == NULL) + if (ts_ctx->type == TST_TCHF && type == NORMAL) { + /* Dieter: we came here because the burst might contain FACCH bits */ + ctx->fn = fn; + ts_ctx->burst_count2 = fn % 26; + + if (ts_ctx->burst_count2 >= 12) + ts_ctx->burst_count2--; + ts_ctx->burst_count2 = ts_ctx->burst_count2 % 8; + + /* copy data bits and stealing flags to buffer */ + memcpy(ts_ctx->burst2 + (116 * ts_ctx->burst_count2), src, 58); + memcpy(ts_ctx->burst2 + (116 * ts_ctx->burst_count2) + 58, src + 58 + 26, 58); + + /* Return if not enough bursts for a full gsm message */ + if ((ts_ctx->burst_count2 % 4) != 3) + return 0; + + data = decode_facch(ctx, ts_ctx->burst2, &len, (ts_ctx->burst_count2 == 3) ? 1 : 0); + if (data == NULL) { + DEBUGF("cannot decode FACCH fnr=%d ts=%d\n", ctx->fn, ts); return -1; -// write_pcap_packet(ctx->pcap_fd, 0 /* arfcn */, ts, ctx->fn, data, len); - return; + } + + out_gsmdecode(0, 0, ts, ctx->fn, data, len); + + if (ctx->gsmtap_fd >= 0) { + struct msgb *msg; + uint8_t chan_type = GSMTAP_CHANNEL_TCH_F; + uint8_t ss = 0; + int fn = (ctx->fn - 3); /* "- 3" for start of frame */ + + msg = gsmtap_makemsg(0, ts, chan_type, ss, ctx->fn, 0, 0, data, len); + if (msg) + write(ctx->gsmtap_fd, msg->data, msg->len); + } + return 0; } -#endif -/* if (ts == 0) { - if (type == SCH) { -// ret = decode_sch(src, &fn, &bsic); - if (ret != 0) - return 0; - if ((ctx->bsic > 0) && (bsic != ctx->bsic)) - fprintf(stderr, "WARN: BSIC changed.\n"); - //DEBUGF("FN %d, BSIC %d\n", fn, bsic); - ctx->fn = fn; - ctx->bsic = bsic; - /* Reset message concatenator */ -// ts_ctx->burst_count = 0; -// return 0; -// } - - /* If we did not get Frame Number yet then return */ -// if (ctx->fn < 0) -// return 0; - -// ctx->fn++; -// } - ctx->fn = fn; + /* normal burst processing */ + if (first_burst) /* Dieter: it is important to start with the correct burst */ + ts_ctx->burst_count = 0; + + ctx->fn = fn; if (type == NORMAL) { /* Interested in these frame numbers (cch) * 2-5, 12-15, 22-25, 23-35, 42-45 @@ -290,18 +299,25 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn) ts_ctx->burst_count = 0; data = decode_cch(ctx, ts_ctx->burst, &len); if (data == NULL) { - DEBUGF("cannot decode fnr=0x%08x ts=%d\n", ctx->fn, ts); + DEBUGF("cannot decode fnr=0x%06x (%6d) ts=%d\n", ctx->fn, ctx->fn, ts); return -1; } //DEBUGF("OK TS %d, len %d\n", ts, len); - out_gsmdecode(0, 0, ts, ctx->fn - 4, data, len); + out_gsmdecode(0, 0, ts, ctx->fn, data, len); if (ctx->gsmtap_fd >= 0) { + /* Dieter: set channel type according to configuration */ struct msgb *msg; + uint8_t chan_type = GSMTAP_CHANNEL_BCCH; + uint8_t ss = 0; + int fn = (ctx->fn - 3); /* "- 3" for start of frame */ + + chan_type = get_chan_type(ts_ctx->type, fn, &ss); + /* arfcn, ts, chan_type, ss, fn, signal, snr, data, len */ - msg = gsmtap_makemsg(0, ts, GSMTAP_CHANNEL_BCCH, 0, - ctx->fn-4, 0, 0, data, len); + msg = gsmtap_makemsg(0, ts, chan_type, ss, + ctx->fn, 0, 0, data, len); if (msg) write(ctx->gsmtap_fd, msg->data, msg->len); @@ -318,13 +334,15 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn) /* - * Output data so that it can be parsed from gsmdeocde. + * Output data so that it can be parsed from gsmdecode. */ static void out_gsmdecode(char type, int arfcn, int ts, int fn, char *data, int len) { char *end = data + len; + printf("%6d %d:", (fn + 0), ts); + /* FIXME: speed this up by first printing into an array */ while (data < end) printf(" %02.2x", (unsigned char)*data++); diff --git a/gsm-receiver/src/lib/decoder/gsmstack.h b/gsm-receiver/src/lib/decoder/gsmstack.h index ea84d60..5fceb45 100644 --- a/gsm-receiver/src/lib/decoder/gsmstack.h +++ b/gsm-receiver/src/lib/decoder/gsmstack.h @@ -59,7 +59,7 @@ typedef struct } GS_CTX; int GS_new(GS_CTX *ctx); -int GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn); +int GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn, int first_burst); #ifdef __cplusplus } diff --git a/gsm-receiver/src/lib/gsm.i b/gsm-receiver/src/lib/gsm.i index 3a5c561..15af8b7 100644 --- a/gsm-receiver/src/lib/gsm.i +++ b/gsm-receiver/src/lib/gsm.i @@ -38,7 +38,7 @@ GR_SWIG_BLOCK_MAGIC(gsm,receiver_cf); -gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); +gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration); class gsm_receiver_cf : public gr_block { diff --git a/gsm-receiver/src/lib/gsm_receiver_cf.cc b/gsm-receiver/src/lib/gsm_receiver_cf.cc index 80611e3..9feabef 100644 --- a/gsm-receiver/src/lib/gsm_receiver_cf.cc +++ b/gsm-receiver/src/lib/gsm_receiver_cf.cc @@ -45,14 +45,25 @@ //FIXME: decide to use this define or not //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready -void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_data, unsigned FN) +void decrypt(const unsigned char * burst_binary, byte * KC, unsigned char * decrypted_data, unsigned FN) { byte AtoB[2*DATA_BITS]; + /* KC is all zero: no decryption */ + + if(KC[0] == 0 && KC[1] == 0 && KC[2] == 0 && KC[3] == 0 & + KC[4] == 0 && KC[5] == 0 && KC[6] == 0 && KC[7] == 0) { + for (int i = 0; i < 148; i++) { + decrypted_data[i] = burst_binary[i]; + } + return; + } + keysetup(KC, FN); runA51(AtoB); - for (int i = 0; i < 148; i++) { + /* guard bits */ + for (int i = 0; i < 3; i++) { decrypted_data[i] = burst_binary[i]; } @@ -60,13 +71,55 @@ void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_da decrypted_data[i+3] = AtoB[i] ^ burst_binary[i+3]; } + /* stealing bits and midamble */ + for (int i = 60; i < 88; i++) { + decrypted_data[i] = burst_binary[i]; + } + for (int i = 0; i < 57; i++) { decrypted_data[i+88] = AtoB[i+57] ^ burst_binary[i+88]; } + + /* guard bits */ + for (int i = 145; i < 148; i++) { + decrypted_data[i] = burst_binary[i]; + } +} + +//TODO: this shouldn't be here */ +void dump_bits(const unsigned char * burst_binary, unsigned char * decrypted_data, burst_counter burst_nr, bool first_burst) +{ + int i; + + /* Cipher bits */ + printf("C%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod()); + for (int i = 0; i < 57; i++) + printf("%d", burst_binary[i+3]); + for (int i = 0; i < 57; i++) + printf("%d", burst_binary[i+88]); + printf("\n"); + + /* Plain bits */ + printf("P%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod()); + for (int i = 0; i < 57; i++) + printf("%d", decrypted_data[i+3]); + for (int i = 0; i < 57; i++) + printf("%d", decrypted_data[i+88]); + printf("\n"); + + /* Keystream bits */ + printf("S%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod()); + for (int i = 0; i < 57; i++) + printf("%d", burst_binary[i+3] ^ decrypted_data[i+3]); + for (int i = 0; i < 57; i++) + printf("%d", burst_binary[i+88] ^ decrypted_data[i+88]); + printf("\n"); } void gsm_receiver_cf::read_key(std::string key) { + printf("Key: '%s'\n", key.c_str()); + int i; int b; for (i = 0;i < 8;i++) { @@ -75,86 +128,133 @@ void gsm_receiver_cf::read_key(std::string key) } } -void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary) +void gsm_receiver_cf::read_configuration(std::string configuration) { - float decrypted_data[148]; + printf("Configuration: '%s'\n", configuration.c_str()); + + if ((char)configuration[0] == 0) { + printf(" No configuration set.\n"); + return; + } + + /* get timeslot */ + int ts = atoi(configuration.c_str()); + if (ts < 0 || ts > 7) { + printf(" Invalid TS: %d\n", ts); + return; + } + + printf(" Configuration TS: %d\n", ts); + + if((char)configuration[1] == 'C') + d_gs_ctx.ts_ctx[ts].type = TST_FCCH_SCH_BCCH_CCCH_SDCCH4; + else if((char)configuration[1] == 'B') + d_gs_ctx.ts_ctx[ts].type = TST_FCCH_SCH_BCCH_CCCH; + else if((char)configuration[1] == 'S') + d_gs_ctx.ts_ctx[ts].type = TST_SDCCH8; + else if((char)configuration[1] == 'T') + d_gs_ctx.ts_ctx[ts].type = TST_TCHF; + else { + printf(" Invalid configuration: %c\n", (char)configuration[1]); + return; + } + /* any other timeslot than 0: turn TS0 off */ + if(ts != 0) { + d_gs_ctx.ts_ctx[0].type = TST_OFF; + d_trace_sch = false; + printf(" TS0 is turned off\n"); + } +} + +void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary, bool first_burst) +{ + unsigned char decrypted_data[148]; + float decrypted_data_float[148]; unsigned char * voice_frame; + int ts = burst_nr.get_timeslot_nr(); + + /* no processing if turned off*/ + if (d_gs_ctx.ts_ctx[ts].type == TST_OFF) + return; -// if (burst_nr.get_timeslot_nr() == 7) { + /* handle traffic timeslots */ +#if 0 + /* always try to decrypt and decode traffic in TS 1...7 */ + /* TODO: this will fail if there is unencrypted traffic in more than one TS */ if (burst_nr.get_timeslot_nr() >= 1 && burst_nr.get_timeslot_nr() <= 7) { +#else + if (d_gs_ctx.ts_ctx[ts].type == TST_TCHF) { +#endif decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod()); - GSM::Time time(burst_nr.get_frame_nr(), burst_nr.get_timeslot_nr()); - GSM::RxBurst rxbrst(decrypted_data, time); - switch (burst_nr.get_timeslot_nr()) { - case 1: - if ( d_tch_decoder1.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder1.get_voice_frame(), 1 , 33, d_gsm_file); - } - break; - case 2: - if ( d_tch_decoder2.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder2.get_voice_frame(), 1 , 33, d_gsm_file); - } - break; - case 3: - if ( d_tch_decoder3.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder3.get_voice_frame(), 1 , 33, d_gsm_file); - } - break; - case 4: - if ( d_tch_decoder4.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder4.get_voice_frame(), 1 , 33, d_gsm_file); - } - break; - case 5: - if ( d_tch_decoder5.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder5.get_voice_frame(), 1 , 33, d_gsm_file); - } - break; - case 6: - if ( d_tch_decoder6.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder6.get_voice_frame(), 1 , 33, d_gsm_file); + int i; + for (i = 0; i< 148; i++) + decrypted_data_float[i] = decrypted_data[i]; + + GSM::Time time(burst_nr.get_frame_nr(), ts); + GSM::RxBurst rxbrst(decrypted_data_float, time); + if (ts - TIMESLOT1 >= 0 && ts - TIMESLOT1 < N_TCH_DECODER) { + if ( d_tch_decoder[ts - TIMESLOT1]->processBurst( rxbrst ) == true) { + fwrite(d_tch_decoder[ts - TIMESLOT1]->get_voice_frame(), 1 , 33, d_gsm_file); } - break; - case 7: - if ( d_tch_decoder7.processBurst( rxbrst ) == true) { - fwrite(d_tch_decoder7.get_voice_frame(), 1 , 33, d_gsm_file); + else if (rxbrst.Hl() || rxbrst.Hu()) { + /* Stolen bits are set, might be FACCH */ + GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst); } - break; } } - if (burst_nr.get_timeslot_nr() == 0) { - GS_process(&d_gs_ctx, TIMESLOT0, 6, &burst_binary[3], burst_nr.get_frame_nr()); + /* handle SDCCH/8 timeslots */ + if (d_gs_ctx.ts_ctx[ts].type == TST_SDCCH8) { + decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod()); + #if 1 /* dump cipher, plain and keystream bits */ + dump_bits(burst_binary, decrypted_data, burst_nr, first_burst); + #endif + GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst); } + + /* TS0 is special (TODO) */ + if (ts == 0) { + memcpy(decrypted_data, burst_binary, sizeof(decrypted_data)); + if (d_gs_ctx.ts_ctx[ts].type == TST_FCCH_SCH_BCCH_CCCH_SDCCH4) { + if (SDCCH_SACCH_4_MAP[burst_nr.get_frame_nr() % 51] != 0) { /* SDCCH/4 or SACCH/4 */ + decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod()); + #if 1 /* dump cipher, plain and keystream bits */ + dump_bits(burst_binary, decrypted_data, burst_nr, first_burst); + #endif + } + } + GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst); + } + } //TODO: this shouldn't be here also - the same reason void gsm_receiver_cf::configure_receiver() { - d_channel_conf.set_multiframe_type(TSC0, multiframe_51); - - d_channel_conf.set_burst_types(TSC0, TEST_CCH_FRAMES, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), dummy_or_normal); - d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); - - d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT1, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); - d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT2, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + int ts; + printf("configure_receiver\n"); - d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT3, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); - d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT4, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + /* configure TS0, TS0 is special (TODO) */ - d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT5, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); - d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51); + d_channel_conf.set_burst_types(TIMESLOT0, TEST_CCH_FRAMES, TEST_CCH_FIRST, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), normal_burst); + /* FCCH bursts */ + d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); + /* SCH bursts */ + d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); - d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_26); - d_channel_conf.set_burst_types(TIMESLOT7, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + /* configure TS1...TS7 */ + for (ts = TIMESLOT1; ts < TIMESLOT7; ts++) { + if (d_gs_ctx.ts_ctx[ts].type == TST_TCHF) { + d_channel_conf.set_multiframe_type(ts, multiframe_26); + d_channel_conf.set_burst_types(ts, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal); + } + else if (d_gs_ctx.ts_ctx[ts].type == TST_SDCCH8) { + d_channel_conf.set_multiframe_type(ts, multiframe_51); + d_channel_conf.set_burst_types(ts, SDCCH_SACCH_8_FRAMES, SDCCH_SACCH_8_FIRST, sizeof(SDCCH_SACCH_8_FRAMES) / sizeof(unsigned), dummy_or_normal); + } + } } @@ -164,9 +264,9 @@ typedef std::vector vector_float; typedef boost::circular_buffer circular_buffer_float; gsm_receiver_cf_sptr -gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key) +gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration) { - return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key)); + return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key, configuration)); } static const int MIN_IN = 1; // mininum number of input streams @@ -177,7 +277,7 @@ static const int MAX_OUT = 1; // maximum number of output streams /* * The private constructor */ -gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key) +gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration) : gr_block("gsm_receiver", gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)), gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))), @@ -190,13 +290,7 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, d_state(first_fcch_search), d_burst_nr(osr), d_failed_sch(0), - d_tch_decoder1( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder2( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder3( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder4( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder5( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder6( GSM::gFACCH_TCHFMapping ), //!! - d_tch_decoder7( GSM::gFACCH_TCHFMapping ) //!! + d_trace_sch(true) { int i; gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0)); @@ -212,7 +306,10 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint); } - d_gsm_file = fopen( "speech.gsm", "wb" ); //!! + for (i = 0; i < N_TCH_DECODER; i++) + d_tch_decoder[i] = new GSM::TCHFACCHL1Decoder(GSM::gFACCH_TCHFMapping); + + d_gsm_file = fopen( "speech.au.gsm", "wb" ); //!! d_hex_to_int['0'] = 0; //!! d_hex_to_int['4'] = 4; //!! d_hex_to_int['8'] = 8; //!! @@ -230,8 +327,14 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, d_hex_to_int['b'] = 0xb; //!! d_hex_to_int['f'] = 0xf; //!! read_key(key); //!! - /* Initialize GSM Stack */ + + /* Initialize GSM Stack, clear d_gs_ctx */ GS_new(&d_gs_ctx); //TODO: remove it! it's not a right place for a decoder + + /* configuration is stored in d_gs_ctx */ + read_configuration(configuration); + + configure_receiver(); } /* @@ -295,16 +398,23 @@ gsm_receiver_cf::general_work(int noutput_items, burst_start = get_sch_chan_imp_resp(input, &channel_imp_resp[0]); //get channel impulse response from it detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //detect bits using MLSE detection if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //decode SCH burst - DCOUT("sch burst_start: " << burst_start); - DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); + if(d_trace_sch) + { + DCOUT("sch burst_start: " << burst_start); + DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); + } d_burst_nr.set(t1, t2, t3, 0); //set counter of bursts value + #if 0 /* Dieter: now done in constructor */ //configure the receiver - tell him where to find which burst type d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51); //in the timeslot nr.0 bursts changes according to t3 counter configure_receiver();//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready + // Dieter: don't call it, otherwise overwrites configuration of configure_receiver() d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); //tell where to find fcch bursts d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); //sch bursts d_channel_conf.set_burst_types(TIMESLOT0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst);//!and maybe normal bursts of the BCCH logical channel + #endif + d_burst_nr++; consume_each(burst_start + BURST_SIZE * d_OSR); //consume samples up to next guard period @@ -326,6 +436,7 @@ gsm_receiver_cf::general_work(int noutput_items, unsigned char output_binary[BURST_SIZE]; burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); //get burst type for given burst number + bool first_burst = d_channel_conf.get_first_burst(d_burst_nr); // first burst of four ? switch (b_type) { case fcch_burst: { //if it's FCCH burst @@ -355,9 +466,12 @@ gsm_receiver_cf::general_work(int noutput_items, if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //and decode SCH data // d_burst_nr.set(t1, t2, t3, 0); //but only to check if burst_start value is correct d_failed_sch = 0; - DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); offset = burst_start - floor((GUARD_PERIOD) * d_OSR); //compute offset from burst_start - burst should start after a guard period - DCOUT(offset); + if(d_trace_sch) + { + DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); + DCOUT(offset); + } to_consume += offset; //adjust with offset number of samples to be consumed } else { d_failed_sch++; @@ -373,7 +487,7 @@ gsm_receiver_cf::general_work(int noutput_items, case normal_burst: //if it's normal burst burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits - process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready + process_normal_burst(d_burst_nr, output_binary, first_burst); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready break; case dummy_or_normal: { @@ -389,7 +503,7 @@ gsm_receiver_cf::general_work(int noutput_items, burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); if (!output_binary[0] && !output_binary[1] && !output_binary[2]) { - process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready + process_normal_burst(d_burst_nr, output_binary, first_burst); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready } } } diff --git a/gsm-receiver/src/lib/gsm_receiver_cf.h b/gsm-receiver/src/lib/gsm_receiver_cf.h index 21cb1ff..d32ad4c 100644 --- a/gsm-receiver/src/lib/gsm_receiver_cf.h +++ b/gsm-receiver/src/lib/gsm_receiver_cf.h @@ -36,12 +36,14 @@ #include //!! #include //!! +#define N_TCH_DECODER 7 /* for TS1..TS7 */ + class gsm_receiver_cf; typedef boost::shared_ptr gsm_receiver_cf_sptr; typedef std::vector vector_complex; -gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); +gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration); /** GSM Receiver GNU Radio block * @@ -57,13 +59,8 @@ class gsm_receiver_cf : public gr_block std::map d_hex_to_int; FILE * d_gsm_file; //!! byte d_KC[8]; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder1; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder2; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder3; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder4; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder5; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder6; //!! - GSM::TCHFACCHL1Decoder d_tch_decoder7; //!! + GSM::TCHFACCHL1Decoder *d_tch_decoder[N_TCH_DECODER]; //!! + bool d_trace_sch; /**@name Configuration of the receiver */ //@{ const int d_OSR; ///< oversampling ratio @@ -117,8 +114,8 @@ class gsm_receiver_cf : public gr_block // GSM Stack GS_CTX d_gs_ctx;//TODO: remove it! it'a not right place for a decoder - friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); - gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key); + friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration); + gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration); /** Function whis is used to search a FCCH burst and to compute frequency offset before * "synchronized" state of the receiver @@ -233,7 +230,12 @@ class gsm_receiver_cf : public gr_block /** * */ - void process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary); + void read_configuration(std::string configuration); + + /** + * + */ + void process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary, bool first_burst); /** * diff --git a/gsm-receiver/src/lib/gsm_receiver_config.cc b/gsm-receiver/src/lib/gsm_receiver_config.cc index 44344f7..33e66b3 100644 --- a/gsm-receiver/src/lib/gsm_receiver_config.cc +++ b/gsm-receiver/src/lib/gsm_receiver_config.cc @@ -82,3 +82,24 @@ burst_type channel_configuration::get_burst_type(burst_counter burst_nr) return d_timeslots_descriptions[timeslot_nr].get_burst_type(nr); } + +bool channel_configuration::get_first_burst(burst_counter burst_nr) +{ + uint32_t timeslot_nr = burst_nr.get_timeslot_nr(); + multiframe_type m_type = d_timeslots_descriptions[timeslot_nr].get_type(); + uint32_t nr; + + switch (m_type) { + case multiframe_26: + nr = burst_nr.get_t2(); + break; + case multiframe_51: + nr = burst_nr.get_t3(); + break; + default: + nr = 0; + break; + } + + return d_timeslots_descriptions[timeslot_nr].get_first_burst(nr); +} diff --git a/gsm-receiver/src/lib/gsm_receiver_config.h b/gsm-receiver/src/lib/gsm_receiver_config.h index b7ba43a..26dd100 100644 --- a/gsm-receiver/src/lib/gsm_receiver_config.h +++ b/gsm-receiver/src/lib/gsm_receiver_config.h @@ -38,10 +38,12 @@ class multiframe_configuration private: multiframe_type d_type; std::vector d_burst_types; + std::vector d_first_burst; public: multiframe_configuration() { d_type = unknown; fill(d_burst_types.begin(), d_burst_types.end(), empty); + fill(d_first_burst.begin(), d_first_burst.end(), false); } ~multiframe_configuration() {} @@ -49,9 +51,13 @@ class multiframe_configuration void set_type(multiframe_type type) { if (type == multiframe_26) { d_burst_types.resize(26); + d_first_burst.resize(26); } else { d_burst_types.resize(51); + d_first_burst.resize(51); } + fill(d_burst_types.begin(), d_burst_types.end(), empty); + fill(d_first_burst.begin(), d_first_burst.end(), false); d_type = type; } @@ -60,6 +66,10 @@ class multiframe_configuration d_burst_types[nr] = type; } + void set_first_burst(int nr, bool first_burst) { + d_first_burst[nr] = first_burst; + } + multiframe_type get_type() { return d_type; } @@ -67,6 +77,10 @@ class multiframe_configuration burst_type get_burst_type(int nr) { return d_burst_types[nr]; } + + bool get_first_burst(int nr) { + return d_first_burst[nr]; + } }; class burst_counter @@ -154,11 +168,20 @@ class channel_configuration } } + void set_burst_types(int timeslot_nr, const unsigned mapping[], const unsigned first_burst[], unsigned mapping_size, burst_type b_type) { + unsigned i; + for (i = 0; i < mapping_size; i++) { + d_timeslots_descriptions[timeslot_nr].set_burst_type(mapping[i], b_type); + d_timeslots_descriptions[timeslot_nr].set_first_burst(mapping[i], first_burst[i] != 0); + } + } + void set_single_burst_type(int timeslot_nr, int burst_nr, burst_type b_type) { d_timeslots_descriptions[timeslot_nr].set_burst_type(burst_nr, b_type); } burst_type get_burst_type(burst_counter burst_nr); + bool get_first_burst(burst_counter burst_nr); }; #endif /* INCLUDED_GSM_RECEIVER_CONFIG_H */ diff --git a/gsm-receiver/src/python/go.sh b/gsm-receiver/src/python/go.sh index e0d1290..5fc37d4 100755 --- a/gsm-receiver/src/python/go.sh +++ b/gsm-receiver/src/python/go.sh @@ -2,6 +2,8 @@ #echo "go.sh [decim==112]" +KEY=$4 +CONFIGURATION=$3 DECIM=$2 FILE=$1 @@ -9,4 +11,16 @@ if [ $DECIM"x" = x ]; then DECIM=112 fi -./gsm_receive.py -d "$DECIM" -I "$FILE" | ../../../gsmdecode/src/gsmdecode -i +if [ $CONFIGURATION"x" = x ]; then + CONFIGURATION="" +fi + +if [ "$KEY""x" = x ]; then + KEY="00 00 00 00 00 00 00 00" +fi + +# Use GSMTAP with WireShark instead of gmsdecode ! + +#./gsm_receive.py -d "$DECIM" -I "$FILE" -c "$CONFIGURATION" -k "$KEY" | ../../../gsmdecode/src/gsmdecode -i + +./gsm_receive.py -d "$DECIM" -I "$FILE" -c "$CONFIGURATION" -k "$KEY" diff --git a/gsm-receiver/src/python/gsm_receive.py b/gsm-receiver/src/python/gsm_receive.py index 130eb05..e66ddf9 100755 --- a/gsm-receiver/src/python/gsm_receive.py +++ b/gsm-receiver/src/python/gsm_receive.py @@ -82,7 +82,7 @@ class gsm_receiver_first_blood(gr.top_block): return interpolator def _set_receiver(self): - receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower()) + receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower(), self.options.configuration.upper()) return receiver def _process_options(self): @@ -97,6 +97,8 @@ class gsm_receiver_first_blood(gr.top_block): help="Output filename") parser.add_option("-k", "--key", type="string", default="AD 6A 3E C2 B4 42 E4 00", help="KC session key") + parser.add_option("-c", "--configuration", type="string", default="", + help="Decoder configuration") (options, args) = parser.parse_args () return (options, args) -- cgit v1.2.3