aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/gsm/gsm0502.h
blob: 0ac13873882f0c88021db7bde61e799d000cfce4 (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
/*! \defgroup gsm0502 GSM 05.02 / 3GPP TS 45.002
 *  @{
 * \file gsm0502.h
 */

#pragma once

#include <stdint.h>

#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>

/* 4.3.3 TDMA frame number : constants and modular arithmetic */
#define GSM_TDMA_FN_DURATION_nS		4615384		/* in 1e−9 seconds (approx) */
#define GSM_TDMA_FN_DURATION_uS		4615		/* in 1e-6 seconds (approx) */

#define GSM_TDMA_SUPERFRAME		(26 * 51)
#define GSM_TDMA_HYPERFRAME		(2048 * GSM_TDMA_SUPERFRAME)

/*! Return the sum of two specified TDMA frame numbers (summation) */
#define GSM_TDMA_FN_SUM(a, b) \
	(((a) + (b)) % GSM_TDMA_HYPERFRAME)
/*! Return the difference of two specified TDMA frame numbers (subtraction) */
#define GSM_TDMA_FN_SUB(a, b) \
	(((a) + GSM_TDMA_HYPERFRAME - (b)) % GSM_TDMA_HYPERFRAME)
/*! Return the *minimum* difference of two specified TDMA frame numbers (distance) */
#define GSM_TDMA_FN_DIFF(a, b) \
	OSMO_MIN(GSM_TDMA_FN_SUB(a, b), GSM_TDMA_FN_SUB(b, a))

/*! Increment the given TDMA frame number by 1 and return the result (like ++fn) */
#define GSM_TDMA_FN_INC(fn) \
	((fn) = GSM_TDMA_FN_SUM((fn), 1))
/*! Decrement the given TDMA frame number by 1 and return the result (like --fn) */
#define GSM_TDMA_FN_DEC(fn) \
	((fn) = GSM_TDMA_FN_SUB((fn), 1))

/* 5.2.3.1 Normal burst for GMSK (1 bit per symbol) */
#define GSM_NBITS_NB_GMSK_TAIL		3
#define GSM_NBITS_NB_GMSK_PAYLOAD	(2 * 58)
#define GSM_NBITS_NB_GMSK_TRAIN_SEQ	26
#define GSM_NBITS_NB_GMSK_BURST		148  /* without guard period */

/* 5.2.3.3 Normal burst for 8-PSK (3 bits per symbol) */
#define GSM_NBITS_NB_8PSK_TAIL		(GSM_NBITS_NB_GMSK_TAIL * 3)
#define GSM_NBITS_NB_8PSK_PAYLOAD	(GSM_NBITS_NB_GMSK_PAYLOAD * 3)
#define GSM_NBITS_NB_8PSK_TRAIN_SEQ	(GSM_NBITS_NB_GMSK_TRAIN_SEQ * 3)
#define GSM_NBITS_NB_8PSK_BURST		(GSM_NBITS_NB_GMSK_BURST * 3)

/* 5.2.5 Synchronization burst (also GMSK) */
#define GSM_NBITS_SB_GMSK_TAIL		GSM_NBITS_NB_GMSK_TAIL
#define GSM_NBITS_SB_GMSK_PAYLOAD	(2 * 39)
#define GSM_NBITS_SB_GMSK_ETRAIN_SEQ	64
#define GSM_NBITS_SB_GMSK_BURST		GSM_NBITS_NB_GMSK_BURST

/* 5.2.6 Dummy burst (also GMSK) */
#define GSM_NBITS_DB_GMSK_TAIL		GSM_NBITS_NB_GMSK_TAIL
#define GSM_NBITS_DB_GMSK_MIXED		142
#define GSM_NBITS_DB_GMSK_BURST		GSM_NBITS_NB_GMSK_BURST

/* 5.2.7 Access burst (also GMSK) */
#define GSM_NBITS_AB_GMSK_ETAIL		8
#define GSM_NBITS_AB_GMSK_SYNCH_SEQ	41
#define GSM_NBITS_AB_GMSK_PAYLOAD	36
#define GSM_NBITS_AB_GMSK_TAIL		GSM_NBITS_NB_GMSK_TAIL
#define GSM_NBITS_AB_GMSK_BURST		GSM_NBITS_NB_GMSK_BURST

/*! Compare the given TDMA FNs, taking the wrapping into account.
 * \param[in] fn1 First TDMA Fn value to compare.
 * \param[in] fn2 Second TDMA Fn value to compare.
 * \returns similarly to memcmp(), -1 if fn1 goes before fn2;
 *                                  0 if fn1 equals fn2;
 *                                  1 if fn1 goes after fn2. */
static inline int gsm0502_fncmp(uint32_t fn1, uint32_t fn2)
{
	const uint32_t thresh = GSM_TDMA_HYPERFRAME / 2;

	if (fn1 == fn2)
		return 0;
	if ((fn1 < fn2 && (fn2 - fn1) < thresh) ||
	    (fn1 > fn2 && (fn1 - fn2) > thresh))
		return -1;

	return 1;
}

/* Table 5 Clause 7 TS 05.02 */
static inline unsigned int
gsm0502_get_n_pag_blocks(const struct gsm48_control_channel_descr *chan_desc)
{
	if (chan_desc->ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
		return 3 - chan_desc->bs_ag_blks_res;
	else
		return 9 - chan_desc->bs_ag_blks_res;
}

/* Chapter 6.5.2 of TS 05.02 */
static inline unsigned int
gsm0502_get_ccch_group(uint64_t imsi, unsigned int bs_cc_chans,
			unsigned int n_pag_blocks)
{
	return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) / n_pag_blocks;
}

/* Chapter 6.5.2 of TS 05.02 */
static inline unsigned int
gsm0502_get_paging_group(uint64_t imsi, unsigned int bs_cc_chans,
			 int n_pag_blocks)
{
	return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks;
}

unsigned int
gsm0502_calc_paging_group(const struct gsm48_control_channel_descr *chan_desc, uint64_t imsi);

enum gsm0502_fn_remap_channel {
	FN_REMAP_TCH_F,
	FN_REMAP_TCH_H0,
	FN_REMAP_TCH_H1,
	FN_REMAP_FACCH_F,
	FN_REMAP_FACCH_H0,
	FN_REMAP_FACCH_H1,
	FN_REMAP_MAX,
};

uint32_t gsm0502_fn_remap(uint32_t fn, enum gsm0502_fn_remap_channel channel);

uint16_t gsm0502_hop_seq_gen(const struct gsm_time *t,
			     uint8_t hsn, uint8_t maio,
			     size_t n, const uint16_t *ma);

int gsm0502_fn2ccch_block(uint32_t fn);

/*! @} */