treewide: remove FSF address
[osmocom-bb.git] / src / host / trxcon / sched_lchan_common.c
blobac6d26286143d8f6edf6f2fd36d64d101cc34dcc
1 /*
2 * OsmocomBB <-> SDR connection bridge
3 * TDMA scheduler: common routines for lchan handlers
5 * (C) 2017-2020 by Vadim Yanitskiy <axilirator@gmail.com>
7 * All Rights Reserved
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.
21 #include <errno.h>
22 #include <string.h>
23 #include <talloc.h>
24 #include <stdint.h>
25 #include <stdbool.h>
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"
42 #include "logging.h"
43 #include "trxcon.h"
44 #include "trx_if.h"
45 #include "l1ctl.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];
91 char *ptr = buf;
93 OSMO_ASSERT(bits <= 8 && bits > 0);
95 while (--bits >= 0)
96 *(ptr++) = (*mask & (1 << bits)) ? '*' : '.';
97 *ptr = '\0';
99 return buf;
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 */
109 if (gsmtap == NULL)
110 return 0;
112 /* Omit frames with unknown channel type */
113 if (lchan_desc->gsmtap_chan_type == GSMTAP_CHANNEL_UNKNOWN)
114 return 0;
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 */
145 dl_hdr.snr = 0;
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);
159 return 0;
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);
190 return 0;
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);
207 l2[0] = 0xd0;
208 return 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);
216 l2[0] = 0xc0;
217 return GSM_EFR_BYTES;
218 case GSM48_CMODE_SPEECH_AMR: /* Adaptive Multi Rate */
219 /* FIXME: AMR is not implemented yet */
220 return 0;
221 case GSM48_CMODE_SIGN:
222 LOGP(DSCH, LOGL_ERROR, "BFI is not allowed in signalling mode\n");
223 return 0;
224 default:
225 LOGP(DSCH, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->tch_mode);
226 return 0;