2 * OsmocomBB <-> SDR connection bridge
3 * TDMA scheduler: common routines for lchan handlers
5 * (C) 2017-2020 by Vadim Yanitskiy <axilirator@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
27 #include <arpa/inet.h>
29 #include <osmocom/core/logging.h>
30 #include <osmocom/core/bits.h>
31 #include <osmocom/core/gsmtap_util.h>
32 #include <osmocom/core/gsmtap.h>
34 #include <osmocom/codec/codec.h>
36 #include <osmocom/gsm/protocol/gsm_04_08.h>
37 #include <osmocom/gsm/protocol/gsm_08_58.h>
39 #include "l1ctl_proto.h"
40 #include "scheduler.h"
41 #include "sched_trx.h"
47 /* GSM 05.02 Chapter 5.2.3 Normal Burst (NB) */
48 const uint8_t sched_nb_training_bits
[8][26] = {
50 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0,
51 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1,
54 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1,
55 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1,
58 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1,
59 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,
62 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0,
63 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
66 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0,
67 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1,
70 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,
71 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0,
74 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1,
75 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1,
78 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
79 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,
83 /* Get a string representation of the burst buffer's completeness.
84 * Examples: " ****.." (incomplete, 4/6 bursts)
85 * " ****" (complete, all 4 bursts)
86 * "**.***.." (incomplete, 5/8 bursts) */
87 const char *burst_mask2str(const uint8_t *mask
, int bits
)
89 /* TODO: CSD is interleaved over 22 bursts, so the mask needs to be extended */
90 static char buf
[8 + 1];
93 OSMO_ASSERT(bits
<= 8 && bits
> 0);
96 *(ptr
++) = (*mask
& (1 << bits
)) ? '*' : '.';
102 int sched_gsmtap_send(enum trx_lchan_type lchan_type
, uint32_t fn
, uint8_t tn
,
103 uint16_t band_arfcn
, int8_t signal_dbm
, uint8_t snr
,
104 const uint8_t *data
, size_t data_len
)
106 const struct trx_lchan_desc
*lchan_desc
= &trx_lchan_desc
[lchan_type
];
108 /* GSMTAP logging may not be enabled */
112 /* Omit frames with unknown channel type */
113 if (lchan_desc
->gsmtap_chan_type
== GSMTAP_CHANNEL_UNKNOWN
)
116 /* TODO: distinguish GSMTAP_CHANNEL_PCH and GSMTAP_CHANNEL_AGCH */
117 return gsmtap_send(gsmtap
, band_arfcn
, tn
, lchan_desc
->gsmtap_chan_type
,
118 lchan_desc
->ss_nr
, fn
, signal_dbm
, snr
, data
, data_len
);
121 int sched_send_dt_ind(struct trx_instance
*trx
, struct trx_ts
*ts
,
122 struct trx_lchan_state
*lchan
, uint8_t *l2
, size_t l2_len
,
123 int bit_error_count
, bool dec_failed
, bool traffic
)
125 const struct trx_meas_set
*meas
= &lchan
->meas_avg
;
126 const struct trx_lchan_desc
*lchan_desc
;
127 struct l1ctl_info_dl dl_hdr
;
129 /* Set up pointers */
130 lchan_desc
= &trx_lchan_desc
[lchan
->type
];
132 /* Fill in known downlink info */
133 dl_hdr
.chan_nr
= lchan_desc
->chan_nr
| ts
->index
;
134 dl_hdr
.link_id
= lchan_desc
->link_id
;
135 dl_hdr
.band_arfcn
= htons(trx
->band_arfcn
);
136 dl_hdr
.num_biterr
= bit_error_count
;
138 /* sched_trx_meas_avg() gives us TDMA frame number of the first burst */
139 dl_hdr
.frame_nr
= htonl(meas
->fn
);
141 /* RX level: 0 .. 63 in typical GSM notation (dBm + 110) */
142 dl_hdr
.rx_level
= dbm2rxlev(meas
->rssi
);
144 /* FIXME: set proper values */
147 /* Mark frame as broken if so */
148 dl_hdr
.fire_crc
= dec_failed
? 2 : 0;
150 /* Put a packet to higher layers */
151 l1ctl_tx_dt_ind(trx
->l1l
, &dl_hdr
, l2
, l2_len
, traffic
);
153 /* Optional GSMTAP logging */
154 if (l2_len
> 0 && (!traffic
|| lchan_desc
->chan_nr
== RSL_CHAN_OSMO_PDCH
)) {
155 sched_gsmtap_send(lchan
->type
, meas
->fn
, ts
->index
,
156 trx
->band_arfcn
, meas
->rssi
, 0, l2
, l2_len
);
162 int sched_send_dt_conf(struct trx_instance
*trx
, struct trx_ts
*ts
,
163 struct trx_lchan_state
*lchan
, uint32_t fn
, bool traffic
)
165 const struct trx_lchan_desc
*lchan_desc
;
166 struct l1ctl_info_dl dl_hdr
;
168 /* Set up pointers */
169 lchan_desc
= &trx_lchan_desc
[lchan
->type
];
171 /* Zero-initialize DL header, because we don't set all fields */
172 memset(&dl_hdr
, 0x00, sizeof(struct l1ctl_info_dl
));
174 /* Fill in known downlink info */
175 dl_hdr
.chan_nr
= lchan_desc
->chan_nr
| ts
->index
;
176 dl_hdr
.link_id
= lchan_desc
->link_id
;
177 dl_hdr
.band_arfcn
= htons(trx
->band_arfcn
);
178 dl_hdr
.frame_nr
= htonl(fn
);
180 l1ctl_tx_dt_conf(trx
->l1l
, &dl_hdr
, traffic
);
182 /* Optional GSMTAP logging */
183 if (!traffic
|| lchan_desc
->chan_nr
== RSL_CHAN_OSMO_PDCH
) {
184 sched_gsmtap_send(lchan
->type
, fn
, ts
->index
,
185 trx
->band_arfcn
| ARFCN_UPLINK
,
186 0, 0, lchan
->prim
->payload
,
187 lchan
->prim
->payload_len
);
194 * Composes a bad frame indication message
195 * according to the current tch_mode.
197 * @param l2 Caller-allocated byte array
198 * @param lchan Logical channel to generate BFI for
199 * @return How much bytes were written
201 size_t sched_bad_frame_ind(uint8_t *l2
, struct trx_lchan_state
*lchan
)
203 switch (lchan
->tch_mode
) {
204 case GSM48_CMODE_SPEECH_V1
:
205 if (lchan
->type
== TRXC_TCHF
) { /* Full Rate */
206 memset(l2
, 0x00, GSM_FR_BYTES
);
209 } else { /* Half Rate */
210 memset(l2
+ 1, 0x00, GSM_HR_BYTES
);
211 l2
[0] = 0x70; /* F = 0, FT = 111 */
212 return GSM_HR_BYTES
+ 1;
214 case GSM48_CMODE_SPEECH_EFR
: /* Enhanced Full Rate */
215 memset(l2
, 0x00, GSM_EFR_BYTES
);
217 return GSM_EFR_BYTES
;
218 case GSM48_CMODE_SPEECH_AMR
: /* Adaptive Multi Rate */
219 /* FIXME: AMR is not implemented yet */
221 case GSM48_CMODE_SIGN
:
222 LOGP(DSCH
, LOGL_ERROR
, "BFI is not allowed in signalling mode\n");
225 LOGP(DSCH
, LOGL_ERROR
, "Invalid TCH mode: %u\n", lchan
->tch_mode
);