summaryrefslogtreecommitdiff
path: root/gsm-tvoid/src/lib/gsm_burst_sink_c.cc
blob: 103c09f53b3197274fc8db52931b92a3689fdfec (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

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gsm_burst_sink_c.h"
#include <gr_io_signature.h>
#include <gr_math.h>
#include <stdio.h>
#include <gri_mmse_fir_interpolator_cc.h>

gsm_burst_sink_c_sptr gsm_make_burst_sink_c (gr_feval_ll *t,float sample_rate)
{
  return gsm_burst_sink_c_sptr (new gsm_burst_sink_c(t,sample_rate));
}

static const int MIN_IN = 1;	// minimum number of input streams
static const int MAX_IN = 1;	// maximum number of input streams

gsm_burst_sink_c::gsm_burst_sink_c (gr_feval_ll *t, float sample_rate) : 
	gsm_burst(t),
	gr_sync_block (	"burst_sink_c",
				gr_make_io_signature (MIN_IN, MAX_IN, sizeof (gr_complex)),
				gr_make_io_signature (0,0,0)
			),
	d_clock_counter(0.0),
	d_mu(0.5),
	d_last_sample(0.0,0.0),
	d_ii(0),
	d_interp(new gri_mmse_fir_interpolator_cc())

{

	//clocking parameters
	d_sample_interval = 1.0 / sample_rate;
	d_relative_sample_rate = sample_rate / GSM_SYMBOL_RATE;
	
	fprintf(stderr,"Sample interval      : %e\n",d_sample_interval);
	fprintf(stderr,"Relative sample rate : %g\n",d_relative_sample_rate);
	
	//we need history for interpolator taps and some saftey relative to relative rate
	int hist = d_interp->ntaps(); // + 16;  // interpolator need -4/+3 samples NTAPS = 8  , 16 for safety margin
	set_history(hist); //need history for interpolator
	
}

gsm_burst_sink_c::~gsm_burst_sink_c ()
{
	delete d_interp;
}


int gsm_burst_sink_c::work(int noutput_items,
		gr_vector_const_void_star &input_items,
		gr_vector_void_star &output_items)

{
	const gr_complex *in = (const gr_complex *) input_items[0];
	
//	fprintf(stderr,"#o=%d",noutput_items);

	assert( d_ii >= 0 );

//	while (( rval < noutput_items) && ( ii < ni ) ) {
	while ( d_ii < noutput_items ) {
//	while ( oo++ < noutput_items ) {
		//clock symbols 
		//TODO: this is very basic and can be improved.  Need tracking...
		//TODO: use burst_start offsets as timing feedback
		//TODO: save complex samples for Viterbi EQ
		
		//from m&m
		gr_complex sample = d_interp->interpolate (&in[d_ii], d_mu);
		
		gr_complex conjprod = sample * conj(d_last_sample);
		float diff_angle = gr_fast_atan2f(imag(conjprod), real(conjprod));

		d_last_sample = sample;

#if 1		
		assert(d_bbuf_pos <= BBUF_SIZE );
		
		if (d_bbuf_pos >= 0)	//could be negative offset from burst alignment.  TODO: perhaps better just to add some padding to the buffer
			d_burst_buffer[d_bbuf_pos] = diff_angle;
		
		d_bbuf_pos++;
		
		if ( d_bbuf_pos >= BBUF_SIZE ) { 
			if (get_burst()) {
				//adjust timing
				//TODO: generate timing error from burst buffer (phase & freq)
							
				switch ( d_clock_options & QB_MASK ) {
				case QB_QUARTER: //extra 1/4 bit each burst
					d_mu -= d_relative_sample_rate / 4.0;
					break;
				case QB_FULL04:	//extra bit on timeslot 0 & 4
					if (!(d_ts%4))
						d_mu -= d_relative_sample_rate;
					break;
				case QB_NONE:	//don't adjust for quarter bits at all
				default:
					break;
				}
				
				d_last_burst_s_count = d_sample_count;
				
				//fprintf(stderr,"clock: %f, pos: %d\n",d_clock_counter,d_bbuf_pos);
			}
		}	   
#endif			

		d_mu += d_relative_sample_rate;
		d_ii += (int)floor(d_mu);
		//d_sample_count += (int)floor(d_mu);		//TODO: outside loop?
		d_mu -= floor(d_mu);
	}

	//reset d_ii, accounting for advance
	d_ii -= noutput_items;
	
//	fprintf(stderr,"/mu=%f",d_mu);
//	fprintf(stderr,"/ii=%d\n",d_ii);

	return noutput_items;
}
personal git repositories of Harald Welte. Your mileage may vary