diff options
-rw-r--r-- | src/lib/Makefile.am | 10 | ||||
-rw-r--r-- | src/lib/gsm_constants.h | 9 | ||||
-rw-r--r-- | src/lib/gsm_receiver_cf.cc | 272 | ||||
-rw-r--r-- | src/lib/gsm_receiver_cf.h | 203 | ||||
-rw-r--r-- | src/lib/gsm_receiver_config.cc | 63 | ||||
-rw-r--r-- | src/lib/gsm_receiver_config.h | 143 | ||||
-rw-r--r-- | src/lib/viterbi_detector.h | 5 |
7 files changed, 386 insertions, 319 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 78c7511..59504c4 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -66,7 +66,9 @@ _gsm_la_SOURCES = \ gsm.cc libgsmdemod_la_SOURCES = \ - gsm_receiver_cf.cc + gsm_receiver_cf.cc \ + gsm_receiver_config.cc \ + viterbi_detector.cc # magic flags _gsm_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version @@ -87,7 +89,11 @@ gsm.cc gsm.py: $(LOCAL_IFILES) $(ALL_IFILES) # These headers get installed in ${prefix}/include/gnuradio grinclude_HEADERS = \ - gsm_receiver_cf.h + gsm_receiver_cf.h \ + gsm_receiver_config.h + +noinst_HEADERS = \ + viterbi_detector.h # These swig headers get installed in ${prefix}/include/gnuradio/swig swiginclude_HEADERS = \ diff --git a/src/lib/gsm_constants.h b/src/lib/gsm_constants.h index 520ff4f..bc16902 100644 --- a/src/lib/gsm_constants.h +++ b/src/lib/gsm_constants.h @@ -22,7 +22,7 @@ #define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // 156.25 * 8 #define FCCH_POS TAIL_BITS #define SYNC_POS 39 -#define TRAIN_POS TAIL_BITS + DATA_BITS + 5 //first 5 bits of a training sequence +#define TRAIN_POS ( TAIL_BITS + DATA_BITS + 5) //first 5 bits of a training sequence //aren't used for channel impulse response estimation #define TRAIN_BEGINNING 5 #define SAFETY_MARGIN 6 // @@ -41,9 +41,12 @@ static const unsigned char SYNC_BITS[] = { }; const unsigned FCCH_FRAMES[] = {0, 10, 20, 30, 40}; -const unsigned SCH_FRAMES[] = {1, 11, 21, 31, 41}; -const unsigned BCCH_FRAMES[] = {2, 3, 4, 5}; +const unsigned SCH_FRAMES[] = {1,11,21,31,41}; +const unsigned BCCH_FRAMES[] = {2,3,4,5}; //!!the receiver shouldn't care about logical +const unsigned TRAFFIC_CHANNEL_F[] = {0,1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24}; + //!!channels so this will be removed from this header +const unsigned TEST[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}; // Sync : .+...++.+..+++.++++++.++++++....++.+..+.+.+++.+.+...+..++++..+.. // Diff Encoded Sync: .++..+.+++.+..++.....++.....+...+.+++.+++++..+++++..++.+...+.++. diff --git a/src/lib/gsm_receiver_cf.cc b/src/lib/gsm_receiver_cf.cc index c1280f4..1ee823c 100644 --- a/src/lib/gsm_receiver_cf.cc +++ b/src/lib/gsm_receiver_cf.cc @@ -39,9 +39,54 @@ #define SYNC_SEARCH_RANGE 30 #define TRAIN_SEARCH_RANGE 40 -//TODO !! - move this methods to some else place +//tutaj umieściłem funkcję która dostaje normalny pakiet + numer +//numer pakietu to numer ramki + numer szczeliny czasowej +//w tym przykładzie po prostu wyrzuca zawartość pakietu na wyjście +//ps. pakiety które nie mają trzech zer na początku zazwyczaj są błędnie odebrane +//ewentulanie innego typu (np. obierasz dummy jako normalny) +void gsm_receiver_cf::przetwarzaj_normalny_pakiet(burst_counter burst_nr, unsigned char * pakiet) +{ + if (burst_nr.get_timeslot_nr() == 6) { + printf("burst = [ "); + for (int i = 0; i < BURST_SIZE ; i++) { + printf(" %d", pakiet[i]); + } + printf("];\n"); +// std::cout << " t2: " << burst_nr.get_t2() << "\n"; + } +} + +// Tutaj ustawia się jekie rodzaje pakietów przypadają na dane stany licznika. +// Licznik ramek składa składa się z trzech części: t3,t2,t1. +// T3 liczy modulo 51, a t2 liczy modulo 26. +// Ja zakładam, że dla danej szczeliny do określenia jaki typ pakietu przypada +// dla danej chwili może być używany tylko jeden z tych liczników. Z dokumentu +// 3gpp 04.03 wynika, że to jest prawda w warstwie fizycznej. +void gsm_receiver_cf::konfiguruj_odbiornik() +{ + // poniżej jest przykład jak się konfiguruje odbiornik + // najpierw mówię mu, że szczelina w szczelinie nr.0 typy pakietów zmieniają się wg. + // licznika t3, czyli modulo 51: + + d_channel_conf.set_multiframe_type(TSC0, multiframe_51); + // tutaj mówię mu, gdzie ma szukać pakietów korekcji częstotliwości FCCH + // w gsm_constants jest definicja: const unsigned FCCH_FRAMES[] = {0, 10, 20, 30, 40}; + // kanał fcch jest nadawany zawsze w w szczelinie nr.0 więc podaję najapierw TSC0 + // potem wartości licznika z tej wcześniej zdefiniowanej tablicy, dalej ilość elementów tablicy, + // a na końcu typ pakietu + // typy są zdefiniowane w gsm_receiver_config.h + d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); + + //w plikach z danymi są opisy i tam można znaleźć nr. szczeliny, w której nadawany był głos + //w pierwszym to jest: + //Traffic channel timeslot: 6 + //mogę skonfigurować żeby odbiornik na ślepo szukał tam pakietów normalnych, bez uciekania + //się do dekodowania informacji sterującej: +// d_channel_conf.set_multiframe_type(TSC6, multiframe_26); +// d_channel_conf.set_burst_types(TSC6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), normal_burst); +} + -// - move it to some else place !! typedef std::list<float> list_float; typedef std::vector<float> vector_float; @@ -71,8 +116,8 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, int osr) d_counter(0), d_fcch_start_pos(0), d_freq_offset(0), - d_state(first_fcch_search), - d_burst_nr(osr) + d_burst_nr(osr), + d_state(first_fcch_search) { int i; gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0)); @@ -133,101 +178,106 @@ gsm_receiver_cf::general_work(int noutput_items, break; case sch_search: { - gr_complex chan_imp_resp[CHAN_IMP_RESP_LENGTH*d_OSR]; - int t1, t2, t3; - int burst_start = 0; - unsigned char output_binary[BURST_SIZE]; - - if (find_sch_burst(in, ninput_items[0], out)) { - burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); - detect_burst(in, chan_imp_resp, burst_start, output_binary); - if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { - DCOUT("sch burst_start: " << burst_start); - d_burst_nr.set(t1, t2, t3, 0); - DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); - d_channel_conf.set_multiframe_type(TSC0, multiframe_51); - d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); - d_channel_conf.set_burst_types(TSC0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); - d_channel_conf.set_burst_types(TSC0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst); - d_burst_nr++; - - consume_each(burst_start + BURST_SIZE * d_OSR); - d_state = synchronized; + gr_complex chan_imp_resp[CHAN_IMP_RESP_LENGTH*d_OSR]; + int t1, t2, t3; + int burst_start = 0; + unsigned char output_binary[BURST_SIZE]; + + if (find_sch_burst(in, ninput_items[0], out)) { + burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); + detect_burst(in, chan_imp_resp, burst_start, output_binary); + if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { + DCOUT("sch burst_start: " << burst_start); + d_burst_nr.set(t1, t2, t3, 0); + DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); + d_channel_conf.set_multiframe_type(TSC0, multiframe_51); + konfiguruj_odbiornik();//!! + d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); + d_channel_conf.set_burst_types(TSC0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); + d_channel_conf.set_burst_types(TSC0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst); + d_burst_nr++; + + consume_each(burst_start + BURST_SIZE * d_OSR); + d_state = synchronized; + } else { + d_state = next_fcch_search; + } } else { - d_state = next_fcch_search; + d_state = sch_search; } - } else { - d_state = sch_search; + break; } - break; - } - //in this state receiver is synchronized and it processes bursts according to burst type for given burst number + //in this state receiver is synchronized and it processes bursts according to burst type for given burst number case synchronized: { - gr_complex chan_imp_resp[d_chan_imp_length*d_OSR]; - burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); - int burst_start; - int offset = 0; - int to_consume = 0; - unsigned char output_binary[BURST_SIZE]; - - switch (b_type) { - case fcch_burst: { - int ii; - int first_sample = ceil((GUARD_PERIOD + 2 * TAIL_BITS) * d_OSR) + 1; - int last_sample = first_sample + USEFUL_BITS * d_OSR; - double phase_sum = 0; - for (ii = first_sample; ii < last_sample; ii++) { - double phase_diff = compute_phase_diff(in[ii], in[ii-1]) - (M_PI / 2) / d_OSR; - phase_sum += phase_diff; - } - double freq_offset = compute_freq_offset(phase_sum, last_sample - first_sample); - if (abs(freq_offset) > FCCH_MAX_FREQ_OFFSET) { - d_freq_offset -= freq_offset; - set_frequency(d_freq_offset); - DCOUT("adjusting frequency, new frequency offset: " << d_freq_offset << "\n"); - } - } - break; + gr_complex chan_imp_resp[d_chan_imp_length*d_OSR]; + burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); + int burst_start; + int offset = 0; + int to_consume = 0; + unsigned char output_binary[BURST_SIZE]; + + switch (b_type) { + case fcch_burst: { + int ii; + int first_sample = ceil((GUARD_PERIOD + 2 * TAIL_BITS) * d_OSR) + 1; + int last_sample = first_sample + USEFUL_BITS * d_OSR; + double phase_sum = 0; + for (ii = first_sample; ii < last_sample; ii++) { + double phase_diff = compute_phase_diff(in[ii], in[ii-1]) - (M_PI / 2) / d_OSR; + phase_sum += phase_diff; + } + double freq_offset = compute_freq_offset(phase_sum, last_sample - first_sample); + if (abs(freq_offset) > FCCH_MAX_FREQ_OFFSET) { + d_freq_offset -= freq_offset; + set_frequency(d_freq_offset); + DCOUT("adjusting frequency, new frequency offset: " << d_freq_offset << "\n"); + } + } + break; - case sch_burst: { - int t1, t2, t3, d_ncc, d_bcc; - burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); - detect_burst(in, &d_channel_imp_resp[0], burst_start, output_binary); - if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { + case sch_burst: { + int t1, t2, t3, d_ncc, d_bcc; + burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); + detect_burst(in, &d_channel_imp_resp[0], burst_start, output_binary); + if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { // d_burst_nr.set(t1, t2, t3, 0); - DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); - offset = burst_start - floor((GUARD_PERIOD) * d_OSR); - DCOUT(offset); - to_consume += offset; - } + DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3); + offset = burst_start - floor((GUARD_PERIOD) * d_OSR); + DCOUT(offset); + to_consume += offset; + } + } + break; + + case normal_burst: + burst_start = get_norm_chan_imp_resp(in, chan_imp_resp, TRAIN_SEARCH_RANGE, d_bcc); + detect_burst(in, &d_channel_imp_resp[0], burst_start, output_binary); + przetwarzaj_normalny_pakiet(d_burst_nr, output_binary); + break; + + case rach_burst: + //implementation of this channel isn't possible in current gsm_receiver + //it would take some realtime processing, counter of samples from USRP to + //stay synchronized with this device and possibility to switch frequency from uplink + //to C0 (where sch is) back and forth + + break; + case dummy: + burst_start = get_norm_chan_imp_resp(in, chan_imp_resp, TRAIN_SEARCH_RANGE, 8); + detect_burst(in, &d_channel_imp_resp[0], burst_start, output_binary); + break; + case empty: + break; } - break; - case normal_burst: - burst_start = get_norm_chan_imp_resp(in, chan_imp_resp, TRAIN_SEARCH_RANGE); - detect_burst(in, &d_channel_imp_resp[0], burst_start, output_binary); - printf("burst = [ "); - for (int i = 0; i < BURST_SIZE ; i++) { - printf(" %d", output_binary[i]); - } - printf("];\n"); - break; - - case rach_burst: - break; - case dummy: - break; - case empty: - break; - } + d_burst_nr++; - d_burst_nr++; - to_consume += TS_BITS * d_OSR + d_burst_nr.get_offset(); - consume_each(to_consume); - } - break; + to_consume += TS_BITS * d_OSR + d_burst_nr.get_offset(); + consume_each(to_consume); + } + break; } return produced_out; @@ -244,7 +294,7 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems) int start_pos = -1; float min_phase_diff; float max_phase_diff; - double best_sum; + double best_sum = 0; float lowest_max_min_diff = 99999; int to_consume = 0; @@ -388,7 +438,7 @@ bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , fl int to_consume = 0; bool end = false; bool result = false; - int sample_nr_near_sch_start = d_fcch_start_pos + (FRAME_BITS - SAFETY_MARGIN) * d_OSR; + unsigned sample_nr_near_sch_start = d_fcch_start_pos + (FRAME_BITS - SAFETY_MARGIN) * d_OSR; enum states { start, reach_sch, search_not_finished, sch_found @@ -442,7 +492,7 @@ int gsm_receiver_cf::get_sch_chan_imp_resp(const gr_complex *in, gr_complex * ch int strongest_window_nr; int burst_start = 0; - int chan_imp_resp_center; + int chan_imp_resp_center = 0; float max_correlation = 0; float energy = 0; @@ -564,7 +614,6 @@ inline void gsm_receiver_cf::autocorrelation(const gr_complex * input, gr_comple } //TODO consider use of some generalized function for filtering and placing it in a separate class for signal processing -//funkcja matched filter inline void gsm_receiver_cf::mafi(const gr_complex * input, int input_length, gr_complex * filter, int filter_length, gr_complex * output) { int ii = 0, n, a; @@ -583,7 +632,7 @@ inline void gsm_receiver_cf::mafi(const gr_complex * input, int input_length, gr } } -int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp, unsigned search_range) +int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp, unsigned search_range, int bcc) { vector_complex correlation_buffer; vector_float power_buffer; @@ -591,16 +640,16 @@ int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *in, gr_complex * c int strongest_window_nr; int burst_start = 0; - int chan_imp_resp_center; + int chan_imp_resp_center = 0; float max_correlation = 0; float energy = 0; int search_center = (int)((TRAIN_POS + GUARD_PERIOD) * d_OSR); - int search_start_pos = search_center+1; - int search_stop_pos = search_center + d_chan_imp_length * d_OSR + 2*d_OSR; + int search_start_pos = search_center + 1; + int search_stop_pos = search_center + d_chan_imp_length * d_OSR + 2 * d_OSR; for (int ii = search_start_pos; ii < search_stop_pos; ii++) { - gr_complex correlation = correlate_sequence(&d_norm_training_seq[d_bcc][TRAIN_BEGINNING], &in[ii], N_TRAIN_BITS - 10); + gr_complex correlation = correlate_sequence(&d_norm_training_seq[bcc][TRAIN_BEGINNING], &in[ii], N_TRAIN_BITS - 10); correlation_buffer.push_back(correlation); power_buffer.push_back(pow(abs(correlation), 2)); @@ -614,27 +663,22 @@ int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *in, gr_complex * c energy = 0; for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++, iter_ii++) { -// for (int ii = 0; ii < (d_chan_imp_length); ii++) { if (iter_ii == power_buffer.end()) { loop_end = true; break; } energy += (*iter_ii); -// iter_ii = iter_ii + d_OSR; } if (loop_end) { break; } iter++; -// std::cout << energy << "\n"; window_energy_buffer.push_back(energy); } -// std::cout << window_energy_buffer.size() << "\n"; strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin(); d_channel_imp_resp.clear(); -// strongest_window_nr = 3; max_correlation = 0; for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++) { @@ -646,20 +690,22 @@ int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *in, gr_complex * c d_channel_imp_resp.push_back(correlation); chan_imp_resp[ii] = correlation; } -//WE WANT TO USE THE FIRST SAMPLE OF THE IMPULSERESPONSE, AND THE -// CORRESPONDING SAMPLES OF THE RECEIVED SIGNAL. -// THE VARIABLE sync_w SHOULD CONTAIN THE BEGINNING OF THE USED PART OF -// TRAINING SEQUENCE, WHICH IS 3+57+1+6=67 BITS INTO THE BURST. THAT IS -// WE HAVE THAT sync_T16 EQUALS FIRST SAMPLE IN BIT NUMBER 67. + // We want to use the first sample of the impulseresponse, and the + // corresponding samples of the received signal. + // the variable sync_w should contain the beginning of the used part of + // training sequence, which is 3+57+1+6=67 bits into the burst. That is + // we have that sync_t16 equals first sample in bit number 67. + burst_start = search_start_pos + chan_imp_resp_center + strongest_window_nr - TRAIN_POS * d_OSR; - burst_start = search_start_pos + chan_imp_resp_center + strongest_window_nr - 66 * d_OSR - 2 * d_OSR + 2; -// COMPENSATING FOR THE 2 Tb DELAY INTRODUCED IN THE GMSK MODULATOR. -// EACH BIT IS STRECHED OVER A PERIOD OF 3 Tb WITH ITS MAXIMUM VALUE -// IN THE LAST BIT PERIOD. HENCE, burst_start IS 2 * OSR -//compute burst start - std::cout << " burst_start: " << (float)burst_start/(float)d_OSR<< " center: " << ((float)(search_start_pos + strongest_window_nr + chan_imp_resp_center))/d_OSR << " stronegest window nr: " << strongest_window_nr << "\n"; + // GMSK modulator introduces ISI - each bit is expanded for 3*Tb + // and it's maximum value is in the last bit period, so burst starts + // 2*Tb earlier + burst_start -= 2 * d_OSR; + burst_start += 2; + //std::cout << " burst_start: " << burst_start << " center: " << ((float)(search_start_pos + strongest_window_nr + chan_imp_resp_center)) / d_OSR << " stronegest window nr: " << strongest_window_nr << "\n"; return burst_start; } + diff --git a/src/lib/gsm_receiver_cf.h b/src/lib/gsm_receiver_cf.h index e07eb60..8e30b42 100644 --- a/src/lib/gsm_receiver_cf.h +++ b/src/lib/gsm_receiver_cf.h @@ -22,206 +22,12 @@ #ifndef INCLUDED_GSM_RECEIVER_CF_H #define INCLUDED_GSM_RECEIVER_CF_H +#include <vector> #include <gr_block.h> #include <gr_complex.h> #include <gr_feval.h> #include <gsm_constants.h> -#include <vector> - - -//TODO !! - move this classes to some other place -#include <vector> -#include <algorithm> -#include <math.h> -typedef enum {empty, fcch_burst, sch_burst, normal_burst, rach_burst, dummy} burst_type; -typedef enum {unknown, multiframe_26, multiframe_51} multiframe_type; - -class multiframe_configuration -{ - private: - multiframe_type d_type; - std::vector<burst_type> d_burst_types; - public: - multiframe_configuration() { - d_type = unknown; - fill(d_burst_types.begin(), d_burst_types.end(), empty); - } - -// multiframe_configuration(multiframe_type type, const std::vector<burst_type> & burst_types): -// d_type(type) { -// d_burst_types.resize(burst_types.size()); -// copy(burst_types.begin(), burst_types.end(), d_burst_types.begin()); -// } - -// multiframe_configuration(multiframe_configuration & conf) { -// d_type = conf.d_type; -// copy(conf.d_burst_types.begin(), conf.d_burst_types.end(), d_burst_types.begin()); -// } - - ~multiframe_configuration() {} - - void set_type(multiframe_type type) { - if (type == multiframe_26) { - d_burst_types.resize(26); - } else { - d_burst_types.resize(51); - } - - d_type = type; - } - - void set_burst_type(int nr, burst_type type) { - d_burst_types[nr] = type; - } - - multiframe_type get_type() { - return d_type; - } - - burst_type get_burst_type(int nr) { - return d_burst_types[nr]; - } -}; - -class burst_counter -{ - private: - const int d_OSR; - uint32_t d_t1, d_t2, d_t3, d_timeslot_nr; - double d_first_sample_offset; - double d_offset; - public: - burst_counter(int osr): - d_OSR(osr), - d_t1(0), - d_t2(0), - d_t3(0), - d_timeslot_nr(0), - d_first_sample_offset(0), - d_offset(0) { - } - - burst_counter(int osr, uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr): - d_OSR(osr), - d_t1(t1), - d_t2(t2), - d_t3(t3), - d_timeslot_nr(timeslot_nr), - d_offset(0) { - double first_sample_position = (get_frame_nr()*8+timeslot_nr)*TS_BITS; - d_first_sample_offset = first_sample_position - floor(first_sample_position); - } - - burst_counter & operator++(int) { - d_timeslot_nr++; - if (d_timeslot_nr == TS_PER_FRAME) { - d_timeslot_nr = 0; - - if ((d_t2 == 25) && (d_t3 == 50)) { - d_t1 = (d_t1 + 1) % (1 << 11); - } - - d_t2 = (d_t2 + 1) % 26; - d_t3 = (d_t3 + 1) % 51; - } - - d_first_sample_offset += GUARD_FRACTIONAL * d_OSR; - d_offset = floor(d_first_sample_offset); - d_first_sample_offset = d_first_sample_offset - d_offset; - return (*this); - } - - void set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr) { - d_t1 = t1; - d_t2 = t2; - d_t3 = t3; - d_timeslot_nr = timeslot_nr; - double first_sample_position = (get_frame_nr()*8+timeslot_nr)*TS_BITS; - d_first_sample_offset = first_sample_position - floor(first_sample_position); - d_offset = 0; - } - - uint32_t get_t1() { - return d_t1; - } - - uint32_t get_t2() { - return d_t2; - } - - uint32_t get_t3() { - return d_t3; - } - - uint32_t get_timeslot_nr() { - return d_timeslot_nr; - } - - uint32_t get_frame_nr() { - return (51 * 26 * d_t1) + (51 * (((d_t3 + 26) - d_t2) % 26)) + d_t3; - } - - unsigned get_offset(){ - return (unsigned)d_offset; - } - //!! - float get_first_sample_offset(){ - return d_first_sample_offset; - } -}; - -class channel_configuration -{ - private: - multiframe_configuration d_timeslots_descriptions[TS_PER_FRAME]; - public: - channel_configuration() { - for (int i = 0; i < TS_PER_FRAME; i++) { - d_timeslots_descriptions[i].set_type(unknown); - } - } -// void set_timeslot_desc(int timeslot_nr, multiframe_configuration conf){ -// d_timeslots_descriptions[timeslot_nr] = conf; -// } - void set_multiframe_type(int timeslot_nr, multiframe_type type) { - d_timeslots_descriptions[timeslot_nr].set_type(type); - } - - void set_burst_types(int timeslot_nr, const unsigned mapping[], 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); - } - } - - 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); -}; - -burst_type channel_configuration::get_burst_type(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_burst_type(nr); -} -// move it to some other place !! +#include <gsm_receiver_config.h> class gsm_receiver_cf; @@ -245,7 +51,6 @@ gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, int osr); class gsm_receiver_cf : public gr_block { - private: const int d_OSR; const int d_chan_imp_length; @@ -288,7 +93,9 @@ class gsm_receiver_cf : public gr_block gr_complex correlate_sequence(const gr_complex * sequence, const gr_complex * input_signal, int ninput); inline void autocorrelation(const gr_complex * input, gr_complex * out, int length); inline void mafi(const gr_complex * input, int input_length, gr_complex * filter, int filter_length, gr_complex * output); - int get_norm_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp, unsigned search_range); + int get_norm_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp, unsigned search_range, int bcc); + void przetwarzaj_normalny_pakiet(burst_counter burst_nr, unsigned char * pakiet); + void konfiguruj_odbiornik(); public: ~gsm_receiver_cf(); diff --git a/src/lib/gsm_receiver_config.cc b/src/lib/gsm_receiver_config.cc index 1d4cf1d..1eaff7f 100644 --- a/src/lib/gsm_receiver_config.cc +++ b/src/lib/gsm_receiver_config.cc @@ -1,7 +1,10 @@ // // C++ Implementation: gsm_receiver_config // -// Description: +// Description: +// This file contains classes which define gsm_receiver configuration +// and the burst_counter which is used to store internal state of the receiver +// when it's synchronized // // // Author: Piotr Krysik <perper@o2.pl>, (C) 2009 @@ -9,3 +12,61 @@ // Copyright: See COPYING file that comes with this distribution // // +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gsm_receiver_config.h> + +burst_counter & burst_counter::operator++(int) +{ + d_timeslot_nr++; + if (d_timeslot_nr == TS_PER_FRAME) { + d_timeslot_nr = 0; + + if ((d_t2 == 25) && (d_t3 == 50)) { + d_t1 = (d_t1 + 1) % (1 << 11); + } + + d_t2 = (d_t2 + 1) % 26; + d_t3 = (d_t3 + 1) % 51; + } + + //update offset - this is integer for d_OSR which is multiple of four + d_offset_fractional += GUARD_FRACTIONAL * d_OSR; + d_offset_integer = floor(d_offset_fractional); + d_offset_fractional = d_offset_fractional - d_offset_integer; + return (*this); +} + +void burst_counter::set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr) +{ + d_t1 = t1; + d_t2 = t2; + d_t3 = t3; + d_timeslot_nr = timeslot_nr; + double first_sample_position = (get_frame_nr() * 8 + timeslot_nr) * TS_BITS; + d_offset_fractional = first_sample_position - floor(first_sample_position); + d_offset_integer = 0; +} + +burst_type channel_configuration::get_burst_type(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_burst_type(nr); +} diff --git a/src/lib/gsm_receiver_config.h b/src/lib/gsm_receiver_config.h index 1d4cf1d..9222602 100644 --- a/src/lib/gsm_receiver_config.h +++ b/src/lib/gsm_receiver_config.h @@ -1,11 +1,150 @@ // // C++ Implementation: gsm_receiver_config // -// Description: -// +// Description: +// This file contains classes which define gsm_receiver configuration +// and the burst_counter which is used to store internal state of the receiver +// when it's synchronized // // Author: Piotr Krysik <perper@o2.pl>, (C) 2009 // // Copyright: See COPYING file that comes with this distribution // // +#ifndef INCLUDED_GSM_RECEIVER_CONFIG_H +#define INCLUDED_GSM_RECEIVER_CONFIG_H + +#include <vector> +#include <algorithm> +#include <math.h> +#include <stdint.h> +#include <gsm_constants.h> + +typedef enum {empty, fcch_burst, sch_burst, normal_burst, rach_burst, dummy} burst_type; +typedef enum {unknown, multiframe_26, multiframe_51} multiframe_type; + +class multiframe_configuration +{ + private: + multiframe_type d_type; + std::vector<burst_type> d_burst_types; + public: + multiframe_configuration() { + d_type = unknown; + fill(d_burst_types.begin(), d_burst_types.end(), empty); + } + + ~multiframe_configuration() {} + + void set_type(multiframe_type type) { + if (type == multiframe_26) { + d_burst_types.resize(26); + } else { + d_burst_types.resize(51); + } + + d_type = type; + } + + void set_burst_type(int nr, burst_type type) { + d_burst_types[nr] = type; + } + + multiframe_type get_type() { + return d_type; + } + + burst_type get_burst_type(int nr) { + return d_burst_types[nr]; + } +}; + +class burst_counter +{ + private: + const int d_OSR; + uint32_t d_t1, d_t2, d_t3, d_timeslot_nr; + double d_offset_fractional; + double d_offset_integer; + public: + burst_counter(int osr): + d_OSR(osr), + d_t1(0), + d_t2(0), + d_t3(0), + d_timeslot_nr(0), + d_offset_fractional(0.0), + d_offset_integer(0.0) { + } + + burst_counter(int osr, uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr): + d_OSR(osr), + d_t1(t1), + d_t2(t2), + d_t3(t3), + d_timeslot_nr(timeslot_nr), + d_offset_fractional(0.0), + d_offset_integer(0.0) { + double first_sample_position = (get_frame_nr() * 8 + timeslot_nr) * TS_BITS; + d_offset_integer = floor(first_sample_position); + d_offset_fractional = first_sample_position - floor(first_sample_position); + } + + burst_counter & operator++(int); + void set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr); + + uint32_t get_t1() { + return d_t1; + } + + uint32_t get_t2() { + return d_t2; + } + + uint32_t get_t3() { + return d_t3; + } + + uint32_t get_timeslot_nr() { + return d_timeslot_nr; + } + + uint32_t get_frame_nr() { + return (51 * 26 * d_t1) + (51 * (((d_t3 + 26) - d_t2) % 26)) + d_t3; + } + + unsigned get_offset() { + return (unsigned)d_offset_integer; + } +}; + +class channel_configuration +{ + private: + multiframe_configuration d_timeslots_descriptions[TS_PER_FRAME]; + public: + channel_configuration() { + for (int i = 0; i < TS_PER_FRAME; i++) { + d_timeslots_descriptions[i].set_type(unknown); + } + } + + void set_multiframe_type(int timeslot_nr, multiframe_type type) { + d_timeslots_descriptions[timeslot_nr].set_type(type); + } + + void set_burst_types(int timeslot_nr, const unsigned mapping[], 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); + } + } + + 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); +}; + +#endif /* INCLUDED_GSM_RECEIVER_CONFIG_H */ diff --git a/src/lib/viterbi_detector.h b/src/lib/viterbi_detector.h index 9ecb2a0..03f483f 100644 --- a/src/lib/viterbi_detector.h +++ b/src/lib/viterbi_detector.h @@ -53,4 +53,9 @@ ** TEST(S): Tested with real world normal burst. */ +#ifndef INCLUDED_VITERBI_DETECTOR_H +#define INCLUDED_VITERBI_DETECTOR_H + void viterbi_detector(const gr_complex * input, unsigned int samples_num, gr_complex * rhh, unsigned int start_state, const unsigned int * stop_states, unsigned int stops_num, float * output); + +#endif /* INCLUDED_VITERBI_DETECTOR_H */ |