summaryrefslogtreecommitdiff
path: root/gsmstack/get_lctype.c
blob: fcffaa1cdaceae3c44281e474946ca50bd416c11 (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

/* helper routines to determine the logical channel type based on
 * physical channel configuration and frame number */

#include "gsmstack.h"
#include "get_lctype.h"

#define GSM_FN_51	(fn / 51)

#define GSM_TC(fn)	((fn / 51) % 8)


/* parameters determined from CCCH_CONF (octet 2 of control channel description
 * in System Information Type 3:
 * BS_CC_CHANS defines if we have CCCH on ts 2/4/6
 * BS_CCCH_SDCCH_COMB defines if we have SDCCH/8 SACCH/C8 on TS0 
 * BS_AG_BLKS_RES defines which CCCH blocks are reserved for AGCH 
 * if BCCH Ext. is used, BS_AS_BLKS_RES has to be non-zero
 */

static int get_lctype_for_ccch(unsigned int fnr)
{
	unsigned int fnr51 = GSM_FN_51(fnr);
	int lc_type;

	if (fnr51 % 10 == 0)
		lc_type = GSM_LCHAN_FCCH;
	else if (fnr51 % 10 == 1)
		lc_type = GSM_LCHAN_SCH;
	else if (fnr51 >= 2 && fnr_mod_51 <= 5)
		lc_type = GSM_LCHAN_BCCH;
	else if (fnr51 >= 6 && fnr51 <= 9) {
		if (flags & CCCH_F_BCCH_EXT)
			lc_type = GSM_LCHAN_BCCH;
		else
			lc_ctype = GSM_LCHAN_PCH;
	} else
		lc_ctype = GSM_LCHAN_PCH;

	/* FIXME: what about AGCH ? */
	/* FIXME: what about NCH ? */
	/* FIXME: what about CBCH ? */

	return lc_ctype;
}

static int get_lctype_for_sdcch8(unsigned int fnr)
{
	unsigned int fnr51 = GSM_FN_51(fnr);
	unsigned int fnr102 = fnr % 102;
	int lc_type;

	/* the lower 32 bursts are evenly divided between SDCCH8 0..7 */
	if (fnr51 % < 32) {
		lc_type = GSM_LCHAN_SDCCH8;
		subc = fnr51 / 4;
	} else {
		/* the upper 16 bursts are bundles of four bursts for 
		 * alternating either SACCH0..3 or SACCH4..7 */
		lc_type = GSM_LCHAN_SACCH8C;
		subc = (fnr51 - 32) / 4;
		if (fnr102 > 50)
			subc += 4;
	}

	return lc_type;
}

static int get_lctype_for_tch_f(unsigned int fnr)
{
	unsigned int fnr52 = fnr % 52;
	int lc_type = GSM_LCHAN_TCH;

	/* only burst number 12 and 51 are be SACCH */
	if (fnr52 == 12 || fnr52 == 51)
		lc_ctype = GSM_LCHAN_SACCH;
	/* burst number 26 and 39 are empty (for measurements) */
	else if (fnr52 == 26 || fnr52 == 39)
		lc_ctype = GSM_LCHAN_NONE;

	return lc_type;
}

/* get the logical channel type based on frame number and
 * physical channel configuration */
int get_lctype(struct gsm_phys_chan *pchan, int fnr)
{
	switch (pchan->config) {
	case GSM_PCHAN_CCCH:
		return get_lctype_for_ccch(fnr);
		break;
	case GSM_PCHAN_TCH_F:
		return get_lctype_for_tch_f(fnr);
		break;
	case GSM_PCHAN_SDCCH8_SACCH8C:
		return get_lctype_for_sdcch8(fnr);
		break;
	}

	return -EINVAL;
}

/* get a pointer to the logical channel structure based on frame number
 * and physical channel configuration */
struct gsm_logi_chan *get_lchan(struct gsm_phys_chan *pchan, int fnr)
{
	int lctype = get_lctype(pchan, fnr);
	return &pchan->logi_chan[lctype];
}
personal git repositories of Harald Welte. Your mileage may vary