summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/gsm_constants.h10
-rw-r--r--src/lib/gsm_receiver_cf.cc333
-rw-r--r--src/lib/gsm_receiver_cf.h203
-rwxr-xr-xsrc/python/gsm_findfcch.py108
4 files changed, 362 insertions, 292 deletions
diff --git a/src/lib/gsm_constants.h b/src/lib/gsm_constants.h
index 9ba70cb..d08df17 100644
--- a/src/lib/gsm_constants.h
+++ b/src/lib/gsm_constants.h
@@ -6,7 +6,7 @@
//Burst timing
#define TAIL_BITS 3
-#define GUARD_BITS 8 //8.25
+#define GUARD_BITS 8.25
#define DATA_BITS 58 //size of 1 data block in normal burst
#define N_TRAIN_BITS 26
#define N_SYNC_BITS 64
@@ -16,7 +16,7 @@
#define TS_BITS (TAIL_BITS+USEFUL_BITS+TAIL_BITS+GUARD_BITS) //a full TS (156)
#define TS_PER_FRAME 8
-#define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // +2 for extra 8*0.25 guard bits
+#define FRAME_BITS (TS_PER_FRAME * TS_BITS)
#define FCCH_POS TAIL_BITS
#define SYNC_POS 39
#define TRAIN_POS 58
@@ -25,6 +25,8 @@
#define FCCH_HITS_NEEDED (USEFUL_BITS - 4)
#define FCCH_MAX_MISSES 1
+#define CHAN_IMP_RESP_LENGTH 5
+
static const int SYNC_BITS[] = {
1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
@@ -32,6 +34,10 @@ static const int SYNC_BITS[] = {
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
};
+const unsigned FCCH_FRAMES[] = {0,10,20,30,40};
+const unsigned SCH_FRAMES[] = {1,11,21,31,41};
+
+
// Sync : .+...++.+..+++.++++++.++++++....++.+..+.+.+++.+.+...+..++++..+..
// Diff Encoded Sync: .++..+.+++.+..++.....++.....+...+.+++.+++++..+++++..++.+...+.++.
diff --git a/src/lib/gsm_receiver_cf.cc b/src/lib/gsm_receiver_cf.cc
index 578cd80..089a563 100644
--- a/src/lib/gsm_receiver_cf.cc
+++ b/src/lib/gsm_receiver_cf.cc
@@ -38,6 +38,9 @@
#define FCCH_BUFFER_SIZE (FCCH_HITS_NEEDED)
#define SYNC_SEARCH_RANGE 40
+//TODO !! - move this methods to some else place
+
+// - move it to some else place !!
typedef std::list<float> list_float;
typedef std::vector<float> vector_float;
@@ -62,14 +65,15 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, int osr)
gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)),
gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))),
d_OSR(osr),
+ d_chan_imp_length(CHAN_IMP_RESP_LENGTH),
d_tuner(tuner),
d_counter(0),
d_fcch_start_pos(0),
d_freq_offset(0),
- d_state(first_fcch_search),
- d_fcch_count(0), //!!
- d_x_temp(0),//!!
- d_x2_temp(0)//!!
+ d_state(first_fcch_search)
+// d_fcch_count(0), //!!
+// d_x_temp(0),//!!
+// d_x2_temp(0)//!!
{
gmsk_mapper(SYNC_BITS, d_sch_training_seq, N_SYNC_BITS);
}
@@ -98,6 +102,7 @@ gsm_receiver_cf::general_work(int noutput_items,
float prev_freq_offset;
switch (d_state) {
+ //bootstrapping
case first_fcch_search:
if (find_fcch_burst(in, ninput_items[0])) {
set_frequency(d_freq_offset);
@@ -113,7 +118,6 @@ gsm_receiver_cf::general_work(int noutput_items,
prev_freq_offset = d_freq_offset;
if (find_fcch_burst(in, ninput_items[0])) {
if (abs(d_freq_offset) > 100) {
- float mean_freq_offset = (prev_freq_offset + d_freq_offset) / 2;
set_frequency(d_freq_offset);
}
produced_out = 0;
@@ -126,15 +130,59 @@ gsm_receiver_cf::general_work(int noutput_items,
case sch_search:
if (find_sch_burst(in, ninput_items[0], out)) {
-// d_state = read_bcch;
- d_state = next_fcch_search;//read_bcch;
+ d_channel_conf.set_multiframe_type(0, multiframe_51);
+ d_channel_conf.set_burst_types(0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst);
+ d_channel_conf.set_burst_types(0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst);
+ d_burst_nr++;
+ d_state = synchronized;
} else {
d_state = sch_search;
}
break;
- case read_bcch:
- consume_each(ninput_items[0]);
+ //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[100];//!!
+ 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: {
+
+ }
+ 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, chan_imp_resp, 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);
+ printf("bcc: %d, ncc: %d, t1: %d, t2: %d, t3: %d\n", d_bcc, d_ncc, t1, t2, t3);
+ offset = burst_start - GUARD_BITS * d_OSR;
+ to_consume += offset;
+ }
+ std::cout << offset << std::endl;
+ }
+ break;
+ case normal_burst:
+
+ break;
+
+ case rach_burst:
+ break;
+ case dummy:
+ break;
+ case empty:
+ break;
+ }
+
+ d_burst_nr++;
+ to_consume += floor(TS_BITS * d_OSR);
+ consume_each(to_consume);
+ }
break;
}
@@ -158,7 +206,6 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems)
int sample_number = 0;
bool end = false;
bool result = false;
-// float mean=0, phase_offset=0, freq_offset=0;
circular_buffer_float::iterator buffer_iter;
enum states {
@@ -208,7 +255,6 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems)
if ((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count <= FCCH_HITS_NEEDED * d_OSR)) {
fcch_search_state = init;
- //DCOUT("hit_count: " << hit_count << " miss_count: " << miss_count << " d_counter: " << d_counter);
continue;
} else if (((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count > FCCH_HITS_NEEDED * d_OSR)) || (hit_count > 2 * FCCH_HITS_NEEDED * d_OSR)) {
fcch_search_state = fcch_found;
@@ -241,18 +287,15 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems)
}
phase_diff = compute_phase_diff(in[sample_number], in[sample_number-1]);
-// std::cout << phase_diff << "\n";
phase_diff_buffer.push_back(phase_diff);
fcch_search_state = found_something;
break;
case fcch_found:
- DCOUT("znalezione fcch na pozycji" << d_counter + start_pos);
+ DCOUT("fcch found on position: " << d_counter + start_pos);
to_consume = start_pos + FCCH_HITS_NEEDED * d_OSR + 1;
-// mean = d_best_sum / FCCH_HITS_NEEDED;
-// phase_offset = mean - (M_PI / 2);
-// freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI);
+
d_fcch_start_pos = d_counter + start_pos;
compute_freq_offset();
end = true;
@@ -281,13 +324,13 @@ double gsm_receiver_cf::compute_freq_offset()
freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI);
d_freq_offset -= freq_offset;
- d_fcch_count++;
- d_x_temp += freq_offset;
- d_x2_temp += freq_offset * freq_offset;
- d_mean = d_x_temp / d_fcch_count;
+// d_fcch_count++;
+// d_x_temp += freq_offset;
+// d_x2_temp += freq_offset * freq_offset;
+// d_mean = d_x_temp / d_fcch_count;
- DCOUT("freq_offset: " << freq_offset );//" d_best_sum: " << d_best_sum
-// DCOUT("wariancja: " << sqrt((d_x2_temp / d_fcch_count - d_mean * d_mean)) << " fcch_count:" << d_fcch_count << " d_mean: " << d_mean);
+ DCOUT("freq_offset: " << freq_offset );//" d_best_sum: " << d_best_sum
+// DCOUT("wariance: " << sqrt((d_x2_temp / d_fcch_count - d_mean * d_mean)) << " fcch_count:" << d_fcch_count << " d_mean: " << d_mean);
return freq_offset;
}
@@ -305,41 +348,23 @@ inline float gsm_receiver_cf::compute_phase_diff(gr_complex val1, gr_complex val
bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , float *out)
{
-// int sample_number = 0;
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;
- vector_complex correlation_buffer;
- vector_float power_buffer;
- vector_float window_energy_buffer;
- int strongest_window_nr;
- int chan_imp_resp_center;
- float max_correlation = 0;
+ gr_complex chan_imp_resp[CHAN_IMP_RESP_LENGTH*d_OSR];
+// vector_complex correlation_buffer;
+// vector_float power_buffer;
+// vector_float window_energy_buffer;
enum states {
- start, reach_sch, find_sch_start, search_not_finished, sch_found
+ start, reach_sch, find_sch_start, detect_and_decode_sch, search_not_finished, sch_found
} sch_search_state;
sch_search_state = start;
- //!!!!
- int chan_imp_length = 5;
- //!!!!
- gr_complex chan_imp_resp[100];
- gr_complex rhh_temp[100];
- gr_complex rhh[6];
- gr_complex filtered_burst[148];
- //!!!!
- int fn_o;
- int bsic_o;
+ int t1, t2, t3;
int burst_start = 0;
- unsigned int stop_states[2] = {4,12};
- float output[BURST_SIZE];
unsigned char output_binary[BURST_SIZE];
-
- float energy = 0;
- bool loop_end = false;
- vector_float::iterator iter;
while (!end) {
switch (sch_search_state) {
@@ -362,115 +387,16 @@ bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , fl
break;
case find_sch_start:
-// DCOUT("find_sch_start d_counter" << d_counter);
- for (int ii = SYNC_POS * d_OSR; ii < (SYNC_POS + SYNC_SEARCH_RANGE)*d_OSR; ii++) {
- to_consume++;
- gr_complex correlation = correlate_sequence(&d_sch_training_seq[5], &in[ii], N_SYNC_BITS - 10);
- correlation_buffer.push_back(correlation); // tylko do znalezienia odp imp kanału
- power_buffer.push_back(pow(abs(correlation), 2));
- if (abs(correlation) > 30000 / 54) {
-// DCOUT("znaleziono środek sch na pozycji: " << ii - SYNC_POS * d_OSR);
- }
- }
-
- //compute window energies
-
- iter = power_buffer.begin();
- while (iter != power_buffer.end()) {
- vector_float::iterator iter_ii = iter;
- energy = 0;
-
- for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++, iter_ii++) {
- if (iter_ii == power_buffer.end()) {
- loop_end = true;
- break;
- }
- energy += (*iter_ii);
- }
-// std::cout << "\n";
-
- if (loop_end) {
- break;
- }
- iter++;
-// std::cout << energy << "\n";
- window_energy_buffer.push_back(energy);
- }
-
- strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin();
- d_channel_imp_resp.clear();
-
-// std::cout << "# name: h_est\n" ;
-// std::cout << "# type: complex matrix\n" ;
-// std::cout << "# rows: 1\n" ;
-// std::cout << "# columns: " << (chan_imp_length)*d_OSR << "\n";
-
- max_correlation = 0;
- for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++) {
- gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
- if (abs(correlation) > max_correlation) {
- chan_imp_resp_center = ii;
- max_correlation = abs(correlation);
- }
-// std::cout << correlation << " ";
- d_channel_imp_resp.push_back(correlation);
- chan_imp_resp[ii] = correlation;
- }
-// DCOUT("\nSrodek odp_imp:" << chan_imp_resp_center );
-
- autocorrelation(chan_imp_resp, rhh_temp, chan_imp_length*d_OSR);
-// std::cout << "\n# name: rhh_temp\n" ;
-// std::cout << "# type: complex matrix\n" ;
-// std::cout << "# rows: 1\n" ;
-// std::cout << "# columns: " << (chan_imp_length)*d_OSR << "\n";
-
-// for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++) {
-// std::cout << rhh_temp[ii] << " ";
-// }
-
-// std::cout << "\n# name: Rhh\n" ;
-// std::cout << "# type: complex matrix\n" ;
-// std::cout << "# rows: 1\n" ;
-// std::cout << "# columns: " << (chan_imp_length) << "\n";
-
- for (int ii = 0; ii < (chan_imp_length); ii++) {
- rhh[ii] = conj(rhh_temp[ii*d_OSR]);
-// std::cout << rhh[ii] << " ";
- }
-
-// std::cout << "\n# name: normal_burst\n" ;
-// std::cout << "# type: complex matrix\n" ;
-// std::cout << "# rows: 1\n" ;
-// std::cout << "# columns: " << 156*d_OSR << "\n";
- burst_start = strongest_window_nr + chan_imp_resp_center - 48 * d_OSR - 2 * d_OSR + 2 + SYNC_POS * d_OSR;
- for (int ii = 0; ii < 156*d_OSR; ii++) {
- gr_complex sample = in[burst_start+ii];
-// std::cout << sample << " ";
- }
-
- mafi(&in[burst_start], 148, chan_imp_resp, chan_imp_length*d_OSR, filtered_burst);
-
-// std::cout << "\n# name: Y\n" ;
-// std::cout << "# type: complex matrix\n" ;
-// std::cout << "# rows: 1\n" ;
-// std::cout << "# columns: " << 148 << "\n";
- for (int ii = 0; ii < 148; ii++) {
- gr_complex filtered_sample = filtered_burst[ii];
-// std::cout << filtered_sample << " ";
- }
-
- viterbi_detector(filtered_burst, 148, rhh, 3, stop_states, 2, output);
-// printf("# name: output\n# type: matrix\n# rows: 1\n# columns: 148\n");
- for(int i=0; i<BURST_SIZE ; i++){
- output_binary[i] = (output[i]>0);
-// printf(" %d", output_binary[i]);
- }
-// printf("\n");
- decode_sch(&output_binary[3], &fn_o, &bsic_o);
-
-// std::cout << "fn: " << fn_o << " bsic: " << bsic_o << "\n";
-// DCOUT("strongest_window_nr: " << strongest_window_nr);
+ burst_start = get_sch_chan_imp_resp(in, chan_imp_resp);
+ sch_search_state = detect_and_decode_sch;
+ break;
+ case detect_and_decode_sch:
+ detect_burst(in, chan_imp_resp, burst_start, output_binary);
+ decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc);
+ d_burst_nr.set(t1, t2, t3, 0);
+ printf("bcc: %d, ncc: %d, t1: %d, t2: %d, t3: %d\n", d_bcc, d_ncc, t1, t2, t3);
+ to_consume += burst_start + BURST_SIZE * d_OSR;
sch_search_state = sch_found;
break;
@@ -491,6 +417,87 @@ bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , fl
return result;
}
+int gsm_receiver_cf::get_sch_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp)
+{
+ vector_complex correlation_buffer;
+ vector_float power_buffer;
+ vector_float window_energy_buffer;
+
+ int strongest_window_nr;
+ int burst_start = 0;
+ int chan_imp_resp_center;
+ float max_correlation = 0;
+ float energy = 0;
+
+ for (int ii = SYNC_POS * d_OSR; ii < (SYNC_POS + SYNC_SEARCH_RANGE)*d_OSR; ii++) {
+ gr_complex correlation = correlate_sequence(&d_sch_training_seq[5], &in[ii], N_SYNC_BITS - 10);
+ correlation_buffer.push_back(correlation);
+ power_buffer.push_back(pow(abs(correlation), 2));
+ }
+
+ //compute window energies
+ vector_float::iterator iter = power_buffer.begin();
+ bool loop_end = false;
+ while (iter != power_buffer.end()) {
+ vector_float::iterator iter_ii = iter;
+ energy = 0;
+
+ for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++, iter_ii++) {
+ if (iter_ii == power_buffer.end()) {
+ loop_end = true;
+ break;
+ }
+ energy += (*iter_ii);
+ }
+ if (loop_end) {
+ break;
+ }
+ iter++;
+ window_energy_buffer.push_back(energy);
+ }
+
+ strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin();
+ d_channel_imp_resp.clear();
+
+ max_correlation = 0;
+ for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++) {
+ gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
+ if (abs(correlation) > max_correlation) {
+ chan_imp_resp_center = ii;
+ max_correlation = abs(correlation);
+ }
+ d_channel_imp_resp.push_back(correlation);
+ chan_imp_resp[ii] = correlation;
+ }
+
+ burst_start = strongest_window_nr + chan_imp_resp_center - 48 * d_OSR - 2 * d_OSR + 2 + SYNC_POS * d_OSR;
+ return burst_start;
+}
+
+void gsm_receiver_cf::detect_burst(const gr_complex * in, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary)
+{
+ float output[BURST_SIZE];
+ gr_complex rhh_temp[CHAN_IMP_RESP_LENGTH*d_OSR];
+ gr_complex rhh[CHAN_IMP_RESP_LENGTH];
+ gr_complex filtered_burst[BURST_SIZE];
+ int start_state = 3;
+ unsigned int stop_states[2] = {4, 12};
+
+ autocorrelation(chan_imp_resp, rhh_temp, d_chan_imp_length*d_OSR);
+ for (int ii = 0; ii < (d_chan_imp_length); ii++) {
+ rhh[ii] = conj(rhh_temp[ii*d_OSR]);
+ }
+
+ mafi(&in[burst_start], BURST_SIZE, chan_imp_resp, d_chan_imp_length*d_OSR, filtered_burst);
+
+ viterbi_detector(filtered_burst, BURST_SIZE, rhh, start_state, stop_states, 2, output);
+
+ for (int i = 0; i < BURST_SIZE ; i++) {
+ output_binary[i] = (output[i] > 0);
+ }
+}
+
+//TODO consider placing this funtion in a separate class for signal processing
void gsm_receiver_cf::gmsk_mapper(const int * input, gr_complex * output, int ninput)
{
gr_complex j = gr_complex(0.0, 1.0);
@@ -511,6 +518,7 @@ void gsm_receiver_cf::gmsk_mapper(const int * input, gr_complex * output, int ni
}
}
+//TODO consider use of some generalized function for correlation and placing it in a separate class for signal processing
gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, const gr_complex * input_signal, int length)
{
gr_complex result(0.0, 0.0);
@@ -521,7 +529,7 @@ gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, cons
result += sequence[ii] * conj(input_signal[sample_number]);
}
- result = result/gr_complex(length, 0);
+ result = result / gr_complex(length, 0);
return result;
}
@@ -543,6 +551,7 @@ gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, cons
// }
//oblicza dodatnią część autokorelacji
+//TODO consider placing this funtion in a separate class for signal processing
inline void gsm_receiver_cf::autocorrelation(const gr_complex * input, gr_complex * out, int length)
{
int i, k;
@@ -554,29 +563,23 @@ 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;
-// std::cout << "\nfilter:";
-// for(n = 0; n < filter_length; n++)
-// {
-// std::cout << filter[n] << " ";
-// }
-// std::cout << "\n";
+
for (n = 0; n < input_length; n++) {
a = n * d_OSR;
output[n] = 0;
ii = 0;
-
+
while (ii < filter_length) {
if ((a + ii) >= input_length*d_OSR)
break;
-// if(n==0)
-// std::cout << input[a+ii] << " ";
output[n] += input[a+ii] * filter[ii]; //!!conj
ii++;
}
- output[n] = output[n]*gr_complex(0,-1);//!!nie powinno tego tu być
+ output[n] = output[n] * gr_complex(0, -1);//!!this shouldn't be here
}
}
diff --git a/src/lib/gsm_receiver_cf.h b/src/lib/gsm_receiver_cf.h
index 20d66da..2bad50e 100644
--- a/src/lib/gsm_receiver_cf.h
+++ b/src/lib/gsm_receiver_cf.h
@@ -29,19 +29,176 @@
#include <vector>
+//TODO !! - move this classes to some other place
+#include <vector>
+#include <algorithm>
+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:
+ uint32_t d_t1, d_t2, d_t3, d_timeslot_nr;
+ public:
+ burst_counter():
+ d_t1(0),
+ d_t2(0),
+ d_t3(0),
+ d_timeslot_nr(0) {
+ }
+
+ burst_counter(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) {
+ }
+
+ 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;
+ }
+ 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;
+ }
+
+ 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;
+ }
+};
+
+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 !!
+
class gsm_receiver_cf;
-/*
- * We use boost::shared_ptr's instead of raw pointers for all access
- * to gr_blocks (and many other data structures). The shared_ptr gets
- * us transparent reference counting, which greatly simplifies storage
- * management issues. This is especially helpful in our hybrid
- * C++ / Python system.
- *
- * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm
- *
- * As a convention, the _sptr suffix indicates a boost::shared_ptr
- */
typedef boost::shared_ptr<gsm_receiver_cf> gsm_receiver_cf_sptr;
typedef std::vector<gr_complex> vector_complex;
@@ -65,6 +222,8 @@ class gsm_receiver_cf : public gr_block
private:
const int d_OSR;
+ const int d_chan_imp_length;
+
gr_complex d_sch_training_seq[N_SYNC_BITS]; //encoded training sequence of a SCH burst
gr_feval_dd *d_tuner;
@@ -74,14 +233,22 @@ class gsm_receiver_cf : public gr_block
int d_fcch_start_pos;
float d_freq_offset;
double d_best_sum;
-
- int d_fcch_count; //!!!
- double d_x_temp, d_x2_temp, d_mean;//!!
-
+
+// int d_fcch_count; //!!!
+// double d_x_temp, d_x2_temp, d_mean;//!!
+
+ burst_counter d_burst_nr;
+ channel_configuration d_channel_conf;
+
vector_complex d_channel_imp_resp;
+ int d_ncc;
+ int d_bcc;
+
enum states {
- first_fcch_search, next_fcch_search, sch_search, read_bcch
+ //synchronization search part
+ first_fcch_search, next_fcch_search, sch_search, synchronized
+ //
} d_state;
friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, int osr);
@@ -91,8 +258,10 @@ class gsm_receiver_cf : public gr_block
double compute_freq_offset();
void set_frequency(double freq_offset);
inline float compute_phase_diff(gr_complex val1, gr_complex val2);
-
+
bool find_sch_burst(const gr_complex *in, const int nitems , float *out);
+ int get_sch_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp);
+ void detect_burst(const gr_complex * in, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary);
void gmsk_mapper(const int * input, gr_complex * gmsk_output, int ninput);
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);
diff --git a/src/python/gsm_findfcch.py b/src/python/gsm_findfcch.py
deleted file mode 100755
index 2050d33..0000000
--- a/src/python/gsm_findfcch.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-#!/usr/bin/env python
-
-from gnuradio import gr, gru, blks2
-#, gsm
-from gnuradio.eng_option import eng_option
-from optparse import OptionParser
-from os import sys
-
-for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs']:
- if extdir not in sys.path:
- sys.path.append(extdir)
-import gsm
-
-class tune(gr.feval_dd):
- def __init__(self, top_block):
- gr.feval_dd.__init__(self)
- self.top_block = top_block
- # self.center_freq = 0
- def eval(self, freq_offet):
- # self.center_freq = self.center_freq - freq_offet
- self.top_block.set_frequency(freq_offet)
- return freq_offet
-
-class gsm_receiver_first_blood(gr.top_block):
- def __init__(self):
- gr.top_block.__init__(self)
- (options, args) = self._przetworz_opcje()
- self.tune_callback = tune(self)
- self.options = options
- self.args = args
- self._ustaw_taktowanie()
- self.zrodlo = self._ustaw_zrodlo()
- self.filtr = self._ustaw_filtr()
- self.interpolator = self._ustaw_interpolator()
- self.odbiornik = self._ustaw_odbiornik()
- self.konwerter = self._ustaw_konwerter()
- self.ujscie = self._ustaw_ujscie()
-
- self.connect(self.zrodlo, self.filtr, self.interpolator, self.odbiornik, self.konwerter, self.ujscie)
-# self.connect(self.zrodlo, self.ujscie)
-
- def _ustaw_ujscie(self):
- nazwa_pliku_wy = self.options.outputfile
- ujscie = gr.file_sink(gr.sizeof_float, nazwa_pliku_wy)
- return ujscie
-
- def _ustaw_zrodlo(self):
- nazwa_pliku = self.options.inputfile
- zrodlo = gr.file_source(gr.sizeof_gr_complex, nazwa_pliku, False)
- return zrodlo
-
- def _ustaw_taktowanie(self):
- options = self.options
- clock_rate = 64e6
- self.clock_rate = clock_rate
- self.input_rate = clock_rate / options.decim
- self.gsm_symb_rate = 1625000.0 / 6.0
- self.sps = self.input_rate / self.gsm_symb_rate / self.options.osr
-
- def _ustaw_filtr(self):
- filter_cutoff = 145e3
- filter_t_width = 10e3
- offset = 0
- #print "input_rate:", self.input_rate, "sample rate:", self.sps, " filter_cutoff:", filter_cutoff, " filter_t_width:", filter_t_width
- filter_taps = gr.firdes.low_pass(1.0, self.input_rate, filter_cutoff, filter_t_width, gr.firdes.WIN_HAMMING)
- filtr = gr.freq_xlating_fir_filter_ccf(1, filter_taps, offset, self.input_rate)
- return filtr
-
- def _ustaw_konwerter(self):
- v2s = gr.vector_to_stream(gr.sizeof_float, 142)
- return v2s
-
- def _ustaw_interpolator(self):
- interpolator = gr.fractional_interpolator_cc(0, self.sps)
-# interpolator = blks2.rational_resampler_ccf(13, 6)
- return interpolator
-
- def _ustaw_odbiornik(self):
- odbiornik = gsm.receiver_cf(self.tune_callback, self.options.osr)
- return odbiornik
-
- def _przetworz_opcje(self):
- parser = OptionParser(option_class=eng_option)
- parser.add_option("-d", "--decim", type="int", default=128,
- help="Set USRP decimation rate to DECIM [default=%default]")
- parser.add_option("-r", "--osr", type="int", default=4,
- help="Oversampling ratio [default=%default]")
- parser.add_option("-I", "--inputfile", type="string", default="cfile",
- help="Input filename")
- parser.add_option("-O", "--outputfile", type="string", default="cfile2.out",
- help="Output filename")
- (options, args) = parser.parse_args ()
- return (options, args)
-
- def set_frequency(self, center_freq):
- self.filtr.set_center_freq(center_freq)
-
-def main():
- try:
- gsm_receiver_first_blood().run()
- except KeyboardInterrupt:
- pass
-
-if __name__ == '__main__':
- main()
-
-
personal git repositories of Harald Welte. Your mileage may vary