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
|
#ifndef L1_IF_H_TRX
#define L1_IF_H_TRX
#include <osmo-bts/scheduler.h>
#include <osmo-bts/phy_link.h>
#include "trx_if.h"
/*
* TRX frame clock handling
*
* In a "normal" synchronous PHY layer, we would be polled every time
* the PHY needs data for a given frame number. However, the
* OpenBTS-inherited TRX protocol works differently: We (L1) must
* autonomously send burst data based on our own clock, and every so
* often (currently every ~ 216 frames), we get a clock indication from
* the TRX.
*
* We're using a MONOTONIC timerfd interval timer for the 4.615ms frame
* intervals, and then compute + send the 8 bursts for that frame.
*
* Upon receiving a clock indication from the TRX, we compensate
* accordingly: If we were transmitting too fast, we're delaying the
* next interval timer accordingly. If we were too slow, we immediately
* send burst data for the missing frame numbers.
*/
/*! clock state of a given TRX */
struct osmo_trx_clock_state {
/*! number of FN periods without TRX clock indication */
uint32_t fn_without_clock_ind;
struct {
/*! last FN we processed based on FN period timer */
uint32_t fn;
/*! time at which we last processed FN */
struct timespec tv;
} last_fn_timer;
struct {
/*! last FN we received a clock indication for */
uint32_t fn;
/*! time at which we received the last clock indication */
struct timespec tv;
} last_clk_ind;
/*! Osmocom FD wrapper for timerfd */
struct osmo_fd fn_timer_ofd;
};
/* gsm_bts->model_priv, specific to osmo-bts-trx */
struct bts_trx_priv {
struct osmo_trx_clock_state clk_s;
};
struct trx_config {
uint8_t trxd_hdr_ver_req; /* requested TRXD header version */
uint8_t trxd_hdr_ver_use; /* actual TRXD header version in use */
int setformat_sent;
bool enabled;
int arfcn_valid;
uint16_t arfcn;
int arfcn_sent;
int tsc_valid;
uint8_t tsc;
int tsc_sent;
int bsic_valid;
uint8_t bsic;
int bsic_sent;
int rxgain_valid;
uint8_t rxgain;
int rxgain_sent;
int power_valid;
uint8_t power;
int power_oml;
int power_sent;
int maxdly_valid;
int maxdly;
int maxdly_sent;
int maxdlynb_valid;
int maxdlynb;
int maxdlynb_sent;
uint8_t slotmask;
int slottype_valid[TRX_NR_TS];
uint8_t slottype[TRX_NR_TS];
int slottype_sent[TRX_NR_TS];
};
struct trx_l1h {
struct llist_head trx_ctrl_list;
/* Latest RSPed cmd, used to catch duplicate RSPs from sent retransmissions */
struct trx_ctrl_msg *last_acked;
//struct gsm_bts_trx *trx;
struct phy_instance *phy_inst;
struct osmo_fd trx_ofd_ctrl;
struct osmo_timer_list trx_ctrl_timer;
struct osmo_fd trx_ofd_data;
/* transceiver config */
struct trx_config config;
struct l1sched_trx l1s;
};
struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst);
int l1if_provision_transceiver_trx(struct trx_l1h *l1h);
int l1if_provision_transceiver(struct gsm_bts *bts);
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn);
int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
int n_errors, int n_bits_total, float rssi, int16_t toa256);
static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
{
struct phy_instance *pinst = trx->role_bts.l1h;
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
return &l1h->l1s;
}
#endif /* L1_IF_H_TRX */
|