summaryrefslogtreecommitdiffstats
path: root/src/host/trxcon/sched_trx.h
blob: b01624c8f56b093208ff2909fe47ab91d091f002 (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
#pragma once

#include <stdint.h>
#include <stdbool.h>

#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/linuxlist.h>

#include "logging.h"
#include "scheduler.h"

#define GSM_BURST_LEN		148
#define GSM_BURST_PL_LEN	116

#define GPRS_BURST_LEN		GSM_BURST_LEN
#define EDGE_BURST_LEN		444

#define TRX_CH_FLAG_PDCH	(1 << 0)
#define TRX_CH_FLAG_AUTO	(1 << 1)
#define TRX_TS_COUNT		8

#define MAX_A5_KEY_LEN		(128 / 8)

/* Forward declaration to avoid mutual include */
struct trx_lchan_state;
struct trx_instance;
struct trx_ts;

enum trx_burst_type {
	TRX_BURST_GMSK,
	TRX_BURST_8PSK,
};

/**
 * These types define the different channels on a multiframe.
 * Each channel has queues and can be activated individually.
 */
enum trx_lchan_type {
	TRXC_IDLE = 0,
	TRXC_FCCH,
	TRXC_SCH,
	TRXC_BCCH,
	TRXC_RACH,
	TRXC_CCCH,
	TRXC_TCHF,
	TRXC_TCHH_0,
	TRXC_TCHH_1,
	TRXC_SDCCH4_0,
	TRXC_SDCCH4_1,
	TRXC_SDCCH4_2,
	TRXC_SDCCH4_3,
	TRXC_SDCCH8_0,
	TRXC_SDCCH8_1,
	TRXC_SDCCH8_2,
	TRXC_SDCCH8_3,
	TRXC_SDCCH8_4,
	TRXC_SDCCH8_5,
	TRXC_SDCCH8_6,
	TRXC_SDCCH8_7,
	TRXC_SACCHTF,
	TRXC_SACCHTH_0,
	TRXC_SACCHTH_1,
	TRXC_SACCH4_0,
	TRXC_SACCH4_1,
	TRXC_SACCH4_2,
	TRXC_SACCH4_3,
	TRXC_SACCH8_0,
	TRXC_SACCH8_1,
	TRXC_SACCH8_2,
	TRXC_SACCH8_3,
	TRXC_SACCH8_4,
	TRXC_SACCH8_5,
	TRXC_SACCH8_6,
	TRXC_SACCH8_7,
	TRXC_PDTCH,
	TRXC_PTCCH,
	_TRX_CHAN_MAX
};

typedef int trx_lchan_rx_func(struct trx_instance *trx,
	struct trx_ts *ts, struct trx_lchan_state *lchan,
	uint32_t fn, uint8_t bid, sbit_t *bits,
	int8_t rssi, float toa);

typedef int trx_lchan_tx_func(struct trx_instance *trx,
	struct trx_ts *ts, struct trx_lchan_state *lchan,
	uint32_t fn, uint8_t bid);

struct trx_lchan_desc {
	/*! \brief TRX Channel Type */
	enum trx_lchan_type chan;
	/*! \brief Human-readable name */
	const char *name;
	/*! \brief Channel Number (like in RSL) */
	uint8_t chan_nr;
	/*! \brief Link ID (like in RSL) */
	uint8_t link_id;

	/*! \brief How much memory do we need to store bursts */
	size_t burst_buf_size;
	/*! \brief Channel specific flags */
	uint8_t flags;

	/*! \brief Function to call when burst received from PHY */
	trx_lchan_rx_func *rx_fn;
	/*! \brief Function to call when data received from L2 */
	trx_lchan_tx_func *tx_fn;
};

struct trx_frame {
	/*! \brief Downlink TRX channel type */
	enum trx_lchan_type dl_chan;
	/*! \brief Downlink block ID */
	uint8_t dl_bid;
	/*! \brief Uplink TRX channel type */
	enum trx_lchan_type ul_chan;
	/*! \brief Uplink block ID */
	uint8_t ul_bid;
};

struct trx_multiframe {
	/*! \brief Channel combination */
	enum gsm_phys_chan_config chan_config;
	/*! \brief Human-readable name */
	const char *name;
	/*! \brief Repeats how many frames */
	uint8_t period;
	/*! \brief Applies to which timeslots */
	uint8_t slotmask;
	/*! \brief Contains which lchans */
	uint64_t lchan_mask;
	/*! \brief Pointer to scheduling structure */
	const struct trx_frame *frames;
};

/* States each channel on a multiframe */
struct trx_lchan_state {
	/*! \brief Channel type */
	enum trx_lchan_type type;
	/*! \brief Channel status */
	uint8_t active;
	/*! \brief Link to a list of channels */
	struct llist_head list;

	/*! \brief Burst type: GMSK or 8PSK */
	enum trx_burst_type burst_type;
	/*! \brief Frame number of first burst */
	uint32_t rx_first_fn;
	/*! \brief Mask of received bursts */
	uint8_t rx_burst_mask;
	/*! \brief Mask of transmitted bursts */
	uint8_t tx_burst_mask;
	/*! \brief Burst buffer for RX */
	sbit_t *rx_bursts;
	/*! \brief Burst buffer for TX */
	ubit_t *tx_bursts;

	/*! \brief A primitive being sent */
	struct trx_ts_prim *prim;

	/*! \brief Mode for TCH channels */
	uint8_t	rsl_cmode, tch_mode;

	/*! \brief FACCH/H on downlink */
	uint8_t dl_ongoing_facch;
	/*! \brief FACCH/H on uplink */
	uint8_t ul_ongoing_facch;

	struct {
		/*! \brief Number of RSSI values */
		uint8_t rssi_num;
		/*! \brief Sum of RSSI values */
		float rssi_sum;
		/*! \brief Number of TOA values */
		uint8_t toa_num;
		/*! \brief Sum of TOA values */
		float toa_sum;
	} meas;

	/* AMR specific */
	struct {
		/*! \brief 4 possible codecs for AMR */
		uint8_t codec[4];
		/*! \brief Number of possible codecs */
		uint8_t codecs;
		/*! \brief Current uplink FT index */
		uint8_t ul_ft;
		/*! \brief Current downlink FT index */
		uint8_t dl_ft;
		/*! \brief Current uplink CMR index */
		uint8_t ul_cmr;
		/*! \brief Current downlink CMR index */
		uint8_t dl_cmr;
		/*! \brief If AMR loop is enabled */
		uint8_t amr_loop;
		/*! \brief Number of bit error rates */
		uint8_t ber_num;
		/*! \brief Sum of bit error rates */
		float ber_sum;
	} amr;

	/*! \brief A5/X encryption state */
	struct {
		uint8_t key[MAX_A5_KEY_LEN];
		uint8_t key_len;
		uint8_t algo;
	} a5;
};

struct trx_ts {
	/*! \brief Timeslot index within a frame (0..7) */
	uint8_t index;
	/*! \brief Last received frame number */
	uint32_t mf_last_fn;

	/*! \brief Pointer to multiframe layout */
	const struct trx_multiframe *mf_layout;
	/*! \brief Channel states for logical channels */
	struct llist_head lchans;
	/*! \brief Queue primitives for TX */
	struct llist_head tx_prims;
};

/* Represents one TX primitive in the queue of trx_ts */
struct trx_ts_prim {
	/*! \brief Link to queue of TS */
	struct llist_head list;
	/*! \brief Logical channel type */
	enum trx_lchan_type chan;
	/*! \brief Payload length */
	size_t payload_len;
	/*! \brief Payload */
	uint8_t payload[0];
};

extern const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX];
const struct trx_multiframe *sched_mframe_layout(
	enum gsm_phys_chan_config config, int tn);

/* Scheduler management functions */
int sched_trx_init(struct trx_instance *trx, uint32_t fn_advance);
int sched_trx_reset(struct trx_instance *trx, int reset_clock);
int sched_trx_shutdown(struct trx_instance *trx);

/* Timeslot management functions */
struct trx_ts *sched_trx_add_ts(struct trx_instance *trx, int tn);
void sched_trx_del_ts(struct trx_instance *trx, int tn);
int sched_trx_reset_ts(struct trx_instance *trx, int tn);
int sched_trx_configure_ts(struct trx_instance *trx, int tn,
	enum gsm_phys_chan_config config);
int sched_trx_start_ciphering(struct trx_ts *ts, uint8_t algo,
	uint8_t *key, uint8_t key_len);

/* Logical channel management functions */
enum gsm_phys_chan_config sched_trx_chan_nr2pchan_config(uint8_t chan_nr);
enum trx_lchan_type sched_trx_chan_nr2lchan_type(uint8_t chan_nr,
	uint8_t link_id);

void sched_trx_deactivate_all_lchans(struct trx_ts *ts);
int sched_trx_set_lchans(struct trx_ts *ts, uint8_t chan_nr, int active);
int sched_trx_activate_lchan(struct trx_ts *ts, enum trx_lchan_type chan);
int sched_trx_deactivate_lchan(struct trx_ts *ts, enum trx_lchan_type chan);
struct trx_lchan_state *sched_trx_find_lchan(struct trx_ts *ts,
	enum trx_lchan_type chan);

/* Primitive management functions */
int sched_prim_init(struct trx_instance *trx, struct trx_ts_prim **prim,
	size_t pl_len, uint8_t chan_nr, uint8_t link_id);
int sched_prim_push(struct trx_instance *trx,
	struct trx_ts_prim *prim, uint8_t chan_nr);

#define CHAN_IS_TCH(chan) \
	(chan == TRXC_TCHF || chan == TRXC_TCHH_0 || chan == TRXC_TCHH_1)

#define PRIM_IS_TCH(prim) \
	CHAN_IS_TCH(prim->chan) && prim->payload_len != GSM_MACBLOCK_LEN

#define PRIM_IS_FACCH(prim) \
	CHAN_IS_TCH(prim->chan) && prim->payload_len == GSM_MACBLOCK_LEN

struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,
	enum trx_lchan_type lchan_type);
void sched_prim_drop(struct trx_lchan_state *lchan);
void sched_prim_flush_queue(struct llist_head *list);

int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
	uint32_t burst_fn, sbit_t *bits, uint16_t nbits, int8_t rssi, float toa);
int sched_trx_handle_tx_burst(struct trx_instance *trx,
	struct trx_ts *ts, struct trx_lchan_state *lchan,
	uint32_t fn, ubit_t *bits);

/* Shared declarations for lchan handlers */
extern const uint8_t sched_nb_training_bits[8][26];

size_t sched_bad_frame_ind(uint8_t *l2, uint8_t rsl_cmode, uint8_t tch_mode);
int sched_send_data_ind(struct trx_instance *trx, struct trx_ts *ts,
	struct trx_lchan_state *lchan, uint8_t *l2, size_t l2_len,
	bool dec_failed, int bit_error_count);
int sched_send_data_conf(struct trx_instance *trx, struct trx_ts *ts,
	struct trx_lchan_state *lchan, uint32_t fn, size_t l2_len);