2 * OsmocomBB <-> SDR connection bridge
3 * TDMA scheduler: handlers for DL / UL bursts on logical channels
5 * (C) 2017-2021 by Vadim Yanitskiy <axilirator@gmail.com>
6 * Contributions by sysmocom - s.f.m.c. GmbH
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
26 #include <osmocom/core/logging.h>
27 #include <osmocom/core/bits.h>
29 #include <osmocom/gsm/gsm_utils.h>
30 #include <osmocom/gsm/protocol/gsm_04_08.h>
31 #include <osmocom/coding/gsm0503_coding.h>
33 #include "l1ctl_proto.h"
34 #include "scheduler.h"
35 #include "sched_trx.h"
40 int rx_data_fn(struct trx_instance
*trx
, struct trx_ts
*ts
,
41 struct trx_lchan_state
*lchan
, uint32_t fn
, uint8_t bid
,
42 const sbit_t
*bits
, const struct trx_meas_set
*meas
)
44 const struct trx_lchan_desc
*lchan_desc
;
45 uint8_t l2
[GSM_MACBLOCK_LEN
], *mask
;
46 int n_errors
, n_bits_total
, rc
;
47 sbit_t
*buffer
, *offset
;
50 lchan_desc
= &trx_lchan_desc
[lchan
->type
];
51 mask
= &lchan
->rx_burst_mask
;
52 buffer
= lchan
->rx_bursts
;
54 LOGP(DSCHD
, LOGL_DEBUG
, "Data received on %s: fn=%u ts=%u bid=%u\n",
55 lchan_desc
->name
, fn
, ts
->index
, bid
);
57 /* Align to the first burst of a block */
58 if (*mask
== 0x00 && bid
!= 0)
64 /* Store the measurements */
65 sched_trx_meas_push(lchan
, meas
);
67 /* Copy burst to buffer of 4 bursts */
68 offset
= buffer
+ bid
* 116;
69 memcpy(offset
, bits
+ 3, 58);
70 memcpy(offset
+ 58, bits
+ 87, 58);
72 /* Wait until complete set of bursts */
76 /* Calculate AVG of the measurements */
77 sched_trx_meas_avg(lchan
, 4);
79 /* Check for complete set of bursts */
80 if ((*mask
& 0xf) != 0xf) {
81 LOGP(DSCHD
, LOGL_ERROR
, "Received incomplete (%s) data frame at "
82 "fn=%u (%u/%u) for %s\n",
83 burst_mask2str(mask
, 4), lchan
->meas_avg
.fn
,
84 lchan
->meas_avg
.fn
% ts
->mf_layout
->period
,
85 ts
->mf_layout
->period
,
87 /* NOTE: xCCH has an insane amount of redundancy for error
88 * correction, so even just 2 valid bursts might be enough
89 * to reconstruct some L2 frames. This is why we do not
93 /* Keep the mask updated */
96 /* Attempt to decode */
97 rc
= gsm0503_xcch_decode(l2
, buffer
, &n_errors
, &n_bits_total
);
99 LOGP(DSCHD
, LOGL_ERROR
, "Received bad %s frame (rc=%d, ber=%d/%d) at fn=%u\n",
100 lchan_desc
->name
, rc
, n_errors
, n_bits_total
, lchan
->meas_avg
.fn
);
103 * We should anyway send dummy frame for
104 * proper measurement reporting...
106 return sched_send_dt_ind(trx
, ts
, lchan
, NULL
, 0,
107 n_errors
, true, false);
110 /* Send a L2 frame to the higher layers */
111 return sched_send_dt_ind(trx
, ts
, lchan
, l2
, GSM_MACBLOCK_LEN
,
112 n_errors
, false, false);
115 int tx_data_fn(struct trx_instance
*trx
, struct trx_ts
*ts
,
116 struct trx_lchan_state
*lchan
,
117 struct sched_burst_req
*br
)
119 const struct trx_lchan_desc
*lchan_desc
;
120 ubit_t
*buffer
, *offset
;
125 /* Set up pointers */
126 lchan_desc
= &trx_lchan_desc
[lchan
->type
];
127 mask
= &lchan
->tx_burst_mask
;
128 buffer
= lchan
->tx_bursts
;
131 /* If we have encoded bursts */
138 /* Check the prim payload length */
139 if (lchan
->prim
->payload_len
!= GSM_MACBLOCK_LEN
) {
140 LOGP(DSCHD
, LOGL_ERROR
, "Primitive has odd length %zu (expected %u), "
141 "so dropping...\n", lchan
->prim
->payload_len
, GSM_MACBLOCK_LEN
);
143 sched_prim_drop(lchan
);
148 rc
= gsm0503_xcch_encode(buffer
, lchan
->prim
->payload
);
150 LOGP(DSCHD
, LOGL_ERROR
, "Failed to encode L2 payload (len=%zu): %s\n",
151 lchan
->prim
->payload_len
, osmo_hexdump(lchan
->prim
->payload
,
152 lchan
->prim
->payload_len
));
154 /* Forget this primitive */
155 sched_prim_drop(lchan
);
161 /* Determine which burst should be sent */
162 offset
= buffer
+ br
->bid
* 116;
165 *mask
|= (1 << br
->bid
);
167 /* Choose proper TSC */
168 tsc
= sched_nb_training_bits
[trx
->tsc
];
170 /* Compose a new burst */
171 memset(br
->burst
, 0, 3); /* TB */
172 memcpy(br
->burst
+ 3, offset
, 58); /* Payload 1/2 */
173 memcpy(br
->burst
+ 61, tsc
, 26); /* TSC */
174 memcpy(br
->burst
+ 87, offset
+ 58, 58); /* Payload 2/2 */
175 memset(br
->burst
+ 145, 0, 3); /* TB */
176 br
->burst_len
= GSM_BURST_LEN
;
178 LOGP(DSCHD
, LOGL_DEBUG
, "Scheduled %s fn=%u ts=%u burst=%u\n",
179 lchan_desc
->name
, br
->fn
, ts
->index
, br
->bid
);
181 /* If we have sent the last (4/4) burst */
182 if ((*mask
& 0x0f) == 0x0f) {
183 /* Confirm data sending */
184 sched_send_dt_conf(trx
, ts
, lchan
, br
->fn
, false);
186 /* Forget processed primitive */
187 sched_prim_drop(lchan
);