summaryrefslogtreecommitdiffstats
path: root/src/target/firmware/include/layer1/sync.h
blob: 40cc3aaaf03ea61f122b1e47fd31a17365464602 (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
#ifndef _L1_SYNC_H
#define _L1_SYNC_H

#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm_utils.h>
#include <layer1/tdma_sched.h>
#include <layer1/mframe_sched.h>
#include <l1ctl_proto.h>

/* structure representing L1 sync information about a cell */
struct l1_cell_info {
	/* on which ARFCN (+band) is the cell? */
	uint16_t	arfcn;
	/* what's the BSIC of the cell (from SCH burst decoding) */
	uint8_t		bsic;
	/* Combined or non-combined CCCH */
	uint8_t		ccch_mode; /* enum ccch_mode */
	/* whats the delta of the cells current GSM frame number
	 * compared to our current local frame number */
	int32_t		fn_offset;
	/* how much does the TPU need adjustment (delta) to synchronize
	 * with the cells burst */
	uint32_t	time_alignment;
	/* FIXME: should we also store the AFC value? */
};

enum l1s_chan {
	L1S_CHAN_MAIN,
	L1S_CHAN_SACCH,
	L1S_CHAN_TRAFFIC,
	_NUM_L1S_CHAN
};

enum l1_compl {
	L1_COMPL_FB,
	L1_COMPL_RACH,
	L1_COMPL_TX_NB,
	L1_COMPL_TX_TCH,
};

typedef void l1_compl_cb(enum l1_compl c);

#define L1S_NUM_COMPL		32
#define L1S_NUM_NEIGH_CELL	6

struct l1s_h0 {
	uint16_t arfcn;
};

struct l1s_h1 {
	uint8_t hsn;
	uint8_t maio;
	uint8_t n;
	uint16_t ma[64];
};

struct l1s_state {
	struct gsm_time	current_time;	/* current GSM time */
	struct gsm_time	next_time;	/* GSM time at next TMDMA irq */

	/* the cell on which we are camping right now */
	struct l1_cell_info serving_cell;

	/* neighbor cell sync info */
	struct l1_cell_info neigh_cell[L1S_NUM_NEIGH_CELL];

	/* TDMA scheduler */
	struct tdma_scheduler tdma_sched;

	/* Multiframe scheduler */
	struct mframe_scheduler mframe_sched;

	/* The current TPU offset register */
	uint32_t	tpu_offset;
	int32_t		tpu_offset_correction;

	/* TX parameters */
	int8_t		ta;
	uint8_t		tx_power;

	/* TCH */
	uint8_t		tch_mode;
	uint8_t		tch_sync;
	uint8_t		audio_mode;

	/* Transmit queues of pending packets for main DCCH and ACCH */
	struct llist_head tx_queue[_NUM_L1S_CHAN];
	struct msgb *tx_meas;

	/* Which L1A completions are scheduled right now */
	uint32_t scheduled_compl;
	/* callbacks for each of the completions */
	l1_compl_cb *completion[L1S_NUM_COMPL];

	/* Structures below are for L1-task specific parameters, used
	 * to communicate between l1-sync and l1-async (l23_api) */
	struct {
		uint8_t mode;	/* FB_MODE 0/1 */
	} fb;

	struct {
		/* power measurement l1 task */
		unsigned int mode;
		union {
			struct {
				uint16_t arfcn_start;
				uint16_t arfcn_next;
				uint16_t arfcn_end;
			} range;
		};
		struct msgb *msg;
	} pm;

	struct {
		uint8_t		ra;
	} rach;

	struct {
		enum {
			GSM_DCHAN_NONE = 0,
			GSM_DCHAN_SDCCH_4,
			GSM_DCHAN_SDCCH_8,
			GSM_DCHAN_TCH_H,
			GSM_DCHAN_TCH_F,
			GSM_DCHAN_UNKNOWN,
		} type;

		uint8_t chan_nr;
		uint8_t scn;
		uint8_t tsc;
		uint8_t tn;
		uint8_t h;

		union {
			struct l1s_h0 h0;
			struct l1s_h1 h1;
		};

		uint8_t st_tsc;
		uint8_t st_tn;
		uint8_t st_h;

		union {
			struct l1s_h0 st_h0;
			struct l1s_h1 st_h1;
		};
	} dedicated;

	/* neighbor cell power measurement process */
	struct {
		uint32_t start_fn; /* frame number of measumrement start */
		uint8_t valid; /* we have a complete set of measurements */
		uint8_t rounds; /* current rounds of complete measurements */
		uint8_t pos; /* current neighbor to measure */
		uint8_t running; /* DSP task running */
		uint8_t n; /* number of neighbors to measure */
		uint16_t band_arfcn[64]; /* list of ARFCNs */
		uint8_t tn[64]; /* list of TS offset for each measurement */
		uint16_t level_sum[64]; /* sum while processing rounds */
		uint8_t level[64]; /* latest results */
	} neigh_pm;

	/* neighbor cell SCH sync process */
	struct {
		uint8_t flags_bsic[64]; /* flags + bsic */
		uint8_t count; /* counter for sync process */
		uint8_t index; /* cell of current sync process (0..63) */
		uint8_t running; /* DSP task running */
	} neigh_sb;
};

#define NEIGH_PM_FLAG_SCANNED	0x80
#define NEIGH_PM_FLAG_BSIC	0x40

extern struct l1s_state l1s;

struct l1s_meas_hdr {
	uint16_t snr;		/* signal/noise ratio */
	int16_t toa_qbit;	/* time of arrival (qbits) */
	int16_t pm_dbm8;	/* power level in dbm/8 */
	int16_t freq_err; 	/* Frequency error in Hz */
};

int16_t l1s_snr_int(uint16_t snr);
uint16_t l1s_snr_fract(uint16_t snr);

void l1s_dsp_abort(void);

void l1s_tx_apc_helper(uint16_t arfcn);

/* schedule a completion */
void l1s_compl_sched(enum l1_compl c);

void l1s_init(void);

/* reset the layer1 as part of synchronizing to a new cell */
void l1s_reset(void);

/* init.c */
void layer1_init(void);

/* A debug macro to print every TDMA frame */
#ifdef DEBUG_EVERY_TDMA
#define putchart(x) putchar(x)
#else
#define putchart(x)
#endif

/* Convert an angle in fx1.15 notatinon into Hz */
#define BITFREQ_DIV_2PI		43104	/* 270kHz / 2 * pi */
#define BITFREQ_DIV_PI		86208	/* 270kHz / pi */
#define ANG2FREQ_SCALING	(2<<15)	/* 2^15 scaling factor for fx1.15 */
#define ANGLE_TO_FREQ(angle)	((int16_t)angle * BITFREQ_DIV_PI / ANG2FREQ_SCALING)

void l1s_reset_hw(void);
void synchronize_tdma(struct l1_cell_info *cinfo);
void l1s_time_inc(struct gsm_time *time, uint32_t delta_fn);
void l1s_time_dump(const struct gsm_time *time);

#endif /* _L1_SYNC_H */