summaryrefslogtreecommitdiff
path: root/src/lib/gsm_receiver_cf.h
blob: 978576b68a014e1d4684426da29ff8f69dcbd0a5 (plain)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/* -*- c++ -*- */
/*
 * Copyright 2004 Free Software Foundation, Inc.
 *
 * This file is part of GNU Radio
 *
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GNU Radio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */
#ifndef INCLUDED_GSM_RECEIVER_CF_H
#define INCLUDED_GSM_RECEIVER_CF_H

#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;
    }
};

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;

typedef boost::shared_ptr<gsm_receiver_cf> gsm_receiver_cf_sptr;
typedef std::vector<gr_complex> vector_complex;

/*!
 * \brief Return a shared_ptr to a new instance of gsm_receiver_cf.
 *
 * To avoid accidental use of raw pointers, gsm_receiver_cf's
 * constructor is private.  howto_make_square_ff is the public
 * interface for creating new instances.
 */
gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, int osr);

/*!
 * \brief Receives fcch
 * \ingroup block
 * \sa
 */

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_complex d_norm_training_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS];
    
    gr_feval_dd *d_tuner;
    unsigned d_counter;

    //variables used to store result of the find_fcch_burst fuction
    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;//!!

    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, //synchronization search part
      synchronized //receiver is synchronized in this state
    } d_state;

    friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, int osr);
    gsm_receiver_cf(gr_feval_dd *tuner, int osr);

    bool find_fcch_burst(const gr_complex *in, const int nitems);
    double compute_freq_offset(double best_sum, unsigned denominator);
    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 unsigned char * input, int ninput, gr_complex * gmsk_output, gr_complex start_point);
    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);

  public:
    ~gsm_receiver_cf();
    void forecast(int noutput_items, gr_vector_int &ninput_items_required);
    int general_work(int noutput_items,
                     gr_vector_int &ninput_items,
                     gr_vector_const_void_star &input_items,
                     gr_vector_void_star &output_items);
};

#endif /* INCLUDED_GSM_RECEIVER_CF_H */
personal git repositories of Harald Welte. Your mileage may vary