2017-07-04 12:38:50 +00:00
|
|
|
#pragma once
|
|
|
|
|
2022-07-04 15:25:27 +00:00
|
|
|
#include <time.h>
|
2017-07-04 12:38:50 +00:00
|
|
|
#include <stdint.h>
|
2017-12-16 09:21:05 +00:00
|
|
|
#include <stdbool.h>
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
#include <osmocom/core/bits.h>
|
|
|
|
#include <osmocom/core/utils.h>
|
2019-11-05 11:51:06 +00:00
|
|
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
2017-07-04 12:38:50 +00:00
|
|
|
#include <osmocom/gsm/gsm_utils.h>
|
2022-07-04 15:25:27 +00:00
|
|
|
#include <osmocom/gsm/gsm0502.h>
|
2017-07-04 12:38:50 +00:00
|
|
|
#include <osmocom/core/linuxlist.h>
|
2022-07-04 15:25:27 +00:00
|
|
|
#include <osmocom/core/timer.h>
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
#define GSM_BURST_LEN 148
|
|
|
|
#define GSM_BURST_PL_LEN 116
|
|
|
|
|
|
|
|
#define GPRS_BURST_LEN GSM_BURST_LEN
|
|
|
|
#define EDGE_BURST_LEN 444
|
|
|
|
|
2018-03-01 10:30:47 +00:00
|
|
|
#define GPRS_L2_MAX_LEN 54
|
|
|
|
#define EDGE_L2_MAX_LEN 155
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CH_LID_DEDIC 0x00
|
|
|
|
#define L1SCHED_CH_LID_SACCH 0x40
|
2018-03-22 16:02:25 +00:00
|
|
|
|
trxcon/scheduler: fix handling of PTCCH logical channel
According to 3GPP TS 45.010, section 5.6.2, for packet-switched
channels the BTS shall monitor the delay of the Access Bursts
sent by the MS on PTCCH and respond with timing advance values
for all MS performing the procedure on that PDCH.
According to 3GPP TS 45.002, section 3.3.4.2, PTCCH (Packet Timing
advance control channel) is a packet dedicated channel, that is
used for continuous Timing Advance control (mentioned above).
There are two sub-types of that logical channel:
- PTCCH/U (Uplink): used to transmit random Access Bursts
to allow estimation of the Timing Advance for one MS in
packet transfer mode.
- PTCCH/D (Downlink): used by the network to transmit
Timing Advance updates for several MS.
As per 3GPP TS 45.003, section 5.2, the coding scheme used for
PTCCH/U is the same as for PRACH as specified in subclause 5.3,
while the coding scheme used for PTCCH/D is the same as for
CS-1 as specified in subclause 5.1.1.
The way we used to handle both PTCCH/U and PTCCH/D is absolutely
wrong - it has nothing to do with xCCH coding. Instead, we need
to use rx_pdtch_fn() for Downlink and tx_rach_fn() for Uplink.
Also, since we only have a shared RSL channel number for PDCH
(Osmocom-specific RSL_CHAN_OSMO_PDCH), there should be a way
to distinguish both PDTCH and PTCCH logical channels. Let's
introduce TRX_CH_LID_PTCCH for that.
Change-Id: I2d1e9b8a66f027047f8d7bdc3f82ff9d8ebcc25e
2019-09-30 13:43:11 +00:00
|
|
|
/* Osmocom-specific extension for PTCCH (see 3GPP TS 45.002, section 3.3.4.2).
|
|
|
|
* Shall be used to distinguish PTCCH and PDTCH channels on a PDCH time-slot. */
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CH_LID_PTCCH 0x80
|
trxcon/scheduler: fix handling of PTCCH logical channel
According to 3GPP TS 45.010, section 5.6.2, for packet-switched
channels the BTS shall monitor the delay of the Access Bursts
sent by the MS on PTCCH and respond with timing advance values
for all MS performing the procedure on that PDCH.
According to 3GPP TS 45.002, section 3.3.4.2, PTCCH (Packet Timing
advance control channel) is a packet dedicated channel, that is
used for continuous Timing Advance control (mentioned above).
There are two sub-types of that logical channel:
- PTCCH/U (Uplink): used to transmit random Access Bursts
to allow estimation of the Timing Advance for one MS in
packet transfer mode.
- PTCCH/D (Downlink): used by the network to transmit
Timing Advance updates for several MS.
As per 3GPP TS 45.003, section 5.2, the coding scheme used for
PTCCH/U is the same as for PRACH as specified in subclause 5.3,
while the coding scheme used for PTCCH/D is the same as for
CS-1 as specified in subclause 5.1.1.
The way we used to handle both PTCCH/U and PTCCH/D is absolutely
wrong - it has nothing to do with xCCH coding. Instead, we need
to use rx_pdtch_fn() for Downlink and tx_rach_fn() for Uplink.
Also, since we only have a shared RSL channel number for PDCH
(Osmocom-specific RSL_CHAN_OSMO_PDCH), there should be a way
to distinguish both PDTCH and PTCCH logical channels. Let's
introduce TRX_CH_LID_PTCCH for that.
Change-Id: I2d1e9b8a66f027047f8d7bdc3f82ff9d8ebcc25e
2019-09-30 13:43:11 +00:00
|
|
|
|
2018-03-10 20:16:40 +00:00
|
|
|
/* Is a channel related to PDCH (GPRS) */
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CH_FLAG_PDCH (1 << 0)
|
2018-03-10 20:16:40 +00:00
|
|
|
/* Should a channel be activated automatically */
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CH_FLAG_AUTO (1 << 1)
|
2018-03-10 20:19:33 +00:00
|
|
|
/* Is continuous burst transmission assumed */
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CH_FLAG_CBTX (1 << 2)
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
#define MAX_A5_KEY_LEN (128 / 8)
|
2018-03-10 20:16:40 +00:00
|
|
|
#define TRX_TS_COUNT 8
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_lchan_state;
|
|
|
|
struct l1sched_meas_set;
|
2022-07-04 15:25:27 +00:00
|
|
|
struct l1sched_state;
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_ts;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-04 15:25:27 +00:00
|
|
|
enum l1sched_clck_state {
|
|
|
|
L1SCHED_CLCK_ST_WAIT,
|
|
|
|
L1SCHED_CLCK_ST_OK,
|
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
enum l1sched_burst_type {
|
|
|
|
L1SCHED_BURST_GMSK,
|
|
|
|
L1SCHED_BURST_8PSK,
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-09 15:33:59 +00:00
|
|
|
enum l1sched_ts_prim_type {
|
|
|
|
L1SCHED_PRIM_DATA,
|
|
|
|
L1SCHED_PRIM_RACH8,
|
|
|
|
L1SCHED_PRIM_RACH11,
|
|
|
|
};
|
|
|
|
|
2017-07-04 12:38:50 +00:00
|
|
|
/**
|
|
|
|
* These types define the different channels on a multiframe.
|
|
|
|
* Each channel has queues and can be activated individually.
|
|
|
|
*/
|
2022-07-02 12:00:53 +00:00
|
|
|
enum l1sched_lchan_type {
|
|
|
|
L1SCHED_IDLE = 0,
|
|
|
|
L1SCHED_FCCH,
|
|
|
|
L1SCHED_SCH,
|
|
|
|
L1SCHED_BCCH,
|
|
|
|
L1SCHED_RACH,
|
|
|
|
L1SCHED_CCCH,
|
|
|
|
L1SCHED_TCHF,
|
|
|
|
L1SCHED_TCHH_0,
|
|
|
|
L1SCHED_TCHH_1,
|
|
|
|
L1SCHED_SDCCH4_0,
|
|
|
|
L1SCHED_SDCCH4_1,
|
|
|
|
L1SCHED_SDCCH4_2,
|
|
|
|
L1SCHED_SDCCH4_3,
|
|
|
|
L1SCHED_SDCCH8_0,
|
|
|
|
L1SCHED_SDCCH8_1,
|
|
|
|
L1SCHED_SDCCH8_2,
|
|
|
|
L1SCHED_SDCCH8_3,
|
|
|
|
L1SCHED_SDCCH8_4,
|
|
|
|
L1SCHED_SDCCH8_5,
|
|
|
|
L1SCHED_SDCCH8_6,
|
|
|
|
L1SCHED_SDCCH8_7,
|
|
|
|
L1SCHED_SACCHTF,
|
|
|
|
L1SCHED_SACCHTH_0,
|
|
|
|
L1SCHED_SACCHTH_1,
|
|
|
|
L1SCHED_SACCH4_0,
|
|
|
|
L1SCHED_SACCH4_1,
|
|
|
|
L1SCHED_SACCH4_2,
|
|
|
|
L1SCHED_SACCH4_3,
|
|
|
|
L1SCHED_SACCH8_0,
|
|
|
|
L1SCHED_SACCH8_1,
|
|
|
|
L1SCHED_SACCH8_2,
|
|
|
|
L1SCHED_SACCH8_3,
|
|
|
|
L1SCHED_SACCH8_4,
|
|
|
|
L1SCHED_SACCH8_5,
|
|
|
|
L1SCHED_SACCH8_6,
|
|
|
|
L1SCHED_SACCH8_7,
|
|
|
|
L1SCHED_PDTCH,
|
|
|
|
L1SCHED_PTCCH,
|
|
|
|
L1SCHED_SDCCH4_CBCH,
|
|
|
|
L1SCHED_SDCCH8_CBCH,
|
|
|
|
_L1SCHED_CHAN_MAX
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-06 11:06:07 +00:00
|
|
|
enum l1sched_data_type {
|
|
|
|
L1SCHED_DT_PACKET_DATA,
|
|
|
|
L1SCHED_DT_SIGNALING,
|
|
|
|
L1SCHED_DT_TRAFFIC,
|
|
|
|
L1SCHED_DT_OTHER, /* SCH and RACH */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum l1sched_config_type {
|
|
|
|
/*! Channel combination for a timeslot */
|
|
|
|
L1SCHED_CFG_PCHAN_COMB,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Represents a (re)configuration request */
|
|
|
|
struct l1sched_config_req {
|
|
|
|
enum l1sched_config_type type;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
uint8_t tn;
|
2022-07-11 22:10:32 +00:00
|
|
|
enum gsm_phys_chan_config pchan;
|
2022-07-06 11:06:07 +00:00
|
|
|
} pchan_comb;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-06-14 21:14:34 +00:00
|
|
|
/* Represents a burst to be transmitted */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_burst_req {
|
2021-06-14 21:14:34 +00:00
|
|
|
uint32_t fn;
|
|
|
|
uint8_t tn;
|
|
|
|
uint8_t pwr;
|
|
|
|
|
|
|
|
/* Internally used by the scheduler */
|
|
|
|
uint8_t bid;
|
|
|
|
|
|
|
|
ubit_t burst[EDGE_BURST_LEN];
|
|
|
|
size_t burst_len;
|
|
|
|
};
|
|
|
|
|
2022-07-06 11:06:07 +00:00
|
|
|
typedef int l1sched_lchan_rx_func(struct l1sched_lchan_state *lchan,
|
2022-07-01 18:42:26 +00:00
|
|
|
uint32_t fn, uint8_t bid, const sbit_t *bits,
|
|
|
|
const struct l1sched_meas_set *meas);
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-06 11:06:07 +00:00
|
|
|
typedef int l1sched_lchan_tx_func(struct l1sched_lchan_state *lchan,
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_burst_req *br);
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_lchan_desc {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Human-readable name */
|
2017-07-04 12:38:50 +00:00
|
|
|
const char *name;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Human-readable description */
|
2019-05-27 23:25:24 +00:00
|
|
|
const char *desc;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel Number (like in RSL) */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t chan_nr;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Link ID (like in RSL) */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t link_id;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Sub-slot number (for SDCCH and TCH/H) */
|
2019-09-18 14:38:03 +00:00
|
|
|
uint8_t ss_nr;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! GSMTAP channel type (see GSMTAP_CHANNEL_*) */
|
2019-09-18 14:38:03 +00:00
|
|
|
uint8_t gsmtap_chan_type;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! How much memory do we need to store bursts */
|
2017-07-04 12:38:50 +00:00
|
|
|
size_t burst_buf_size;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel specific flags */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t flags;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Function to call when burst received from PHY */
|
2022-07-01 18:42:26 +00:00
|
|
|
l1sched_lchan_rx_func *rx_fn;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Function to call when data received from L2 */
|
2022-07-01 18:42:26 +00:00
|
|
|
l1sched_lchan_tx_func *tx_fn;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_tdma_frame {
|
2022-07-02 12:00:53 +00:00
|
|
|
/*! Downlink channel (slot) type */
|
|
|
|
enum l1sched_lchan_type dl_chan;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Downlink block ID */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t dl_bid;
|
2022-07-02 12:00:53 +00:00
|
|
|
/*! Uplink channel (slot) type */
|
|
|
|
enum l1sched_lchan_type ul_chan;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Uplink block ID */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t ul_bid;
|
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_tdma_multiframe {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel combination */
|
2017-07-04 12:38:50 +00:00
|
|
|
enum gsm_phys_chan_config chan_config;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Human-readable name */
|
2017-07-04 12:38:50 +00:00
|
|
|
const char *name;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Repeats how many frames */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t period;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Applies to which timeslots */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t slotmask;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Contains which lchans */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint64_t lchan_mask;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Pointer to scheduling structure */
|
2022-07-01 18:42:26 +00:00
|
|
|
const struct l1sched_tdma_frame *frames;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_meas_set {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! TDMA frame number of the first burst this set belongs to */
|
2020-03-02 12:07:35 +00:00
|
|
|
uint32_t fn;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! ToA256 (Timing of Arrival, 1/256 of a symbol) */
|
2020-03-01 19:55:01 +00:00
|
|
|
int16_t toa256;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! RSSI (Received Signal Strength Indication) */
|
2020-03-01 19:55:01 +00:00
|
|
|
int8_t rssi;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Simple ring buffer (up to 8 unique measurements) */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_lchan_meas_hist {
|
|
|
|
struct l1sched_meas_set buf[8];
|
|
|
|
struct l1sched_meas_set *head;
|
2020-03-01 19:55:01 +00:00
|
|
|
};
|
|
|
|
|
2017-07-04 12:38:50 +00:00
|
|
|
/* States each channel on a multiframe */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_lchan_state {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel type */
|
2022-07-02 12:00:53 +00:00
|
|
|
enum l1sched_lchan_type type;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel status */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t active;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Link to a list of channels */
|
2018-01-05 00:24:04 +00:00
|
|
|
struct llist_head list;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Burst type: GMSK or 8PSK */
|
2022-07-01 18:42:26 +00:00
|
|
|
enum l1sched_burst_type burst_type;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Mask of received bursts */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t rx_burst_mask;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Mask of transmitted bursts */
|
2017-07-15 15:46:54 +00:00
|
|
|
uint8_t tx_burst_mask;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Burst buffer for RX */
|
2017-07-04 12:38:50 +00:00
|
|
|
sbit_t *rx_bursts;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Burst buffer for TX */
|
2017-07-04 12:38:50 +00:00
|
|
|
ubit_t *tx_bursts;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! A primitive being sent */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_ts_prim *prim;
|
2017-12-17 20:47:23 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Mode for TCH channels (see GSM48_CMODE_*) */
|
2018-08-15 02:00:16 +00:00
|
|
|
uint8_t tch_mode;
|
2022-07-06 11:06:07 +00:00
|
|
|
/*! Training Sequence Code */
|
|
|
|
uint8_t tsc;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! FACCH/H on downlink */
|
2018-08-12 21:48:14 +00:00
|
|
|
bool dl_ongoing_facch;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! pending FACCH/H blocks on Uplink */
|
2018-08-12 21:48:14 +00:00
|
|
|
uint8_t ul_facch_blocks;
|
2017-12-16 07:53:48 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Downlink measurements history */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_lchan_meas_hist meas_hist;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! AVG measurements of the last received block */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_meas_set meas_avg;
|
2017-12-16 07:53:48 +00:00
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! TDMA loss detection state */
|
2020-03-04 14:22:11 +00:00
|
|
|
struct {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Last processed TDMA frame number */
|
2020-03-04 14:22:11 +00:00
|
|
|
uint32_t last_proc;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Number of processed TDMA frames */
|
2020-03-04 14:22:11 +00:00
|
|
|
unsigned long num_proc;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Number of lost TDMA frames */
|
2020-03-04 14:22:11 +00:00
|
|
|
unsigned long num_lost;
|
|
|
|
} tdma;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! SACCH state */
|
trxcon/scheduler: fix Measurement Reporting on SACCH
According to 3GPP TS 04.08, section 3.4.1, SACCH logical channel
accompanies either a traffic or a signaling channel. It has the
particularity that continuous transmission must occur in both
directions, so on the Uplink direction measurement result messages
are sent at each possible occasion when nothing else has to be sent.
The LAPDm fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
applicable on SACCH channels!
Unfortunately, 3GPP TS 04.08 doesn't clearly state which "else
messages" besides Measurement Reports can be send by the MS on
SACCH channels. However, in sub-clause 3.4.1 it's stated that
the interval between two successive measurement result messages
shall not exceed one L2 frame.
This change introduces a separate handler for SACCH primitives,
which dequeues a SACCH primitive from transmit queue, if present.
Otherwise it dequeues a cached Measurement Report (the last
received one). Finally, if the cache is empty, a "dummy"
measurement report is used. When it's possible,
a non-MR primitive is prioritized.
Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Related: OS#2988
2018-03-22 18:40:03 +00:00
|
|
|
struct {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Cached measurement report (last received) */
|
trxcon/scheduler: fix Measurement Reporting on SACCH
According to 3GPP TS 04.08, section 3.4.1, SACCH logical channel
accompanies either a traffic or a signaling channel. It has the
particularity that continuous transmission must occur in both
directions, so on the Uplink direction measurement result messages
are sent at each possible occasion when nothing else has to be sent.
The LAPDm fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
applicable on SACCH channels!
Unfortunately, 3GPP TS 04.08 doesn't clearly state which "else
messages" besides Measurement Reports can be send by the MS on
SACCH channels. However, in sub-clause 3.4.1 it's stated that
the interval between two successive measurement result messages
shall not exceed one L2 frame.
This change introduces a separate handler for SACCH primitives,
which dequeues a SACCH primitive from transmit queue, if present.
Otherwise it dequeues a cached Measurement Report (the last
received one). Finally, if the cache is empty, a "dummy"
measurement report is used. When it's possible,
a non-MR primitive is prioritized.
Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Related: OS#2988
2018-03-22 18:40:03 +00:00
|
|
|
uint8_t mr_cache[GSM_MACBLOCK_LEN];
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Cache usage counter */
|
trxcon/scheduler: fix Measurement Reporting on SACCH
According to 3GPP TS 04.08, section 3.4.1, SACCH logical channel
accompanies either a traffic or a signaling channel. It has the
particularity that continuous transmission must occur in both
directions, so on the Uplink direction measurement result messages
are sent at each possible occasion when nothing else has to be sent.
The LAPDm fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
applicable on SACCH channels!
Unfortunately, 3GPP TS 04.08 doesn't clearly state which "else
messages" besides Measurement Reports can be send by the MS on
SACCH channels. However, in sub-clause 3.4.1 it's stated that
the interval between two successive measurement result messages
shall not exceed one L2 frame.
This change introduces a separate handler for SACCH primitives,
which dequeues a SACCH primitive from transmit queue, if present.
Otherwise it dequeues a cached Measurement Report (the last
received one). Finally, if the cache is empty, a "dummy"
measurement report is used. When it's possible,
a non-MR primitive is prioritized.
Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Related: OS#2988
2018-03-22 18:40:03 +00:00
|
|
|
uint8_t mr_cache_usage;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Was a MR transmitted last time? */
|
trxcon/scheduler: fix Measurement Reporting on SACCH
According to 3GPP TS 04.08, section 3.4.1, SACCH logical channel
accompanies either a traffic or a signaling channel. It has the
particularity that continuous transmission must occur in both
directions, so on the Uplink direction measurement result messages
are sent at each possible occasion when nothing else has to be sent.
The LAPDm fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
applicable on SACCH channels!
Unfortunately, 3GPP TS 04.08 doesn't clearly state which "else
messages" besides Measurement Reports can be send by the MS on
SACCH channels. However, in sub-clause 3.4.1 it's stated that
the interval between two successive measurement result messages
shall not exceed one L2 frame.
This change introduces a separate handler for SACCH primitives,
which dequeues a SACCH primitive from transmit queue, if present.
Otherwise it dequeues a cached Measurement Report (the last
received one). Finally, if the cache is empty, a "dummy"
measurement report is used. When it's possible,
a non-MR primitive is prioritized.
Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Related: OS#2988
2018-03-22 18:40:03 +00:00
|
|
|
bool mr_tx_last;
|
|
|
|
} sacch;
|
|
|
|
|
2017-12-16 07:53:48 +00:00
|
|
|
/* AMR specific */
|
|
|
|
struct {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! 4 possible codecs for AMR */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t codec[4];
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Number of possible codecs */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t codecs;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Current uplink FT index */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t ul_ft;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Current downlink FT index */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t dl_ft;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Current uplink CMR index */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t ul_cmr;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Current downlink CMR index */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t dl_cmr;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! If AMR loop is enabled */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t amr_loop;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Number of bit error rates */
|
2017-12-16 07:53:48 +00:00
|
|
|
uint8_t ber_num;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Sum of bit error rates */
|
2017-12-16 07:53:48 +00:00
|
|
|
float ber_sum;
|
|
|
|
} amr;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! A5/X encryption state */
|
2017-12-16 07:53:48 +00:00
|
|
|
struct {
|
|
|
|
uint8_t key[MAX_A5_KEY_LEN];
|
|
|
|
uint8_t key_len;
|
|
|
|
uint8_t algo;
|
|
|
|
} a5;
|
2019-12-04 13:20:05 +00:00
|
|
|
|
|
|
|
/* TS that this lchan belongs to */
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_ts *ts;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_ts {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Timeslot index within a frame (0..7) */
|
2017-07-04 12:38:50 +00:00
|
|
|
uint8_t index;
|
|
|
|
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Pointer to multiframe layout */
|
2022-07-01 18:42:26 +00:00
|
|
|
const struct l1sched_tdma_multiframe *mf_layout;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Channel states for logical channels */
|
2018-01-05 00:24:04 +00:00
|
|
|
struct llist_head lchans;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Queue primitives for TX */
|
2017-07-04 12:38:50 +00:00
|
|
|
struct llist_head tx_prims;
|
2022-07-06 11:06:07 +00:00
|
|
|
/*! Backpointer to the scheduler */
|
|
|
|
struct l1sched_state *sched;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
/* Represents one TX primitive in the queue of l1sched_ts */
|
|
|
|
struct l1sched_ts_prim {
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Link to queue of TS */
|
2017-07-12 11:48:18 +00:00
|
|
|
struct llist_head list;
|
2022-07-09 15:33:59 +00:00
|
|
|
/*! Type of primitive */
|
|
|
|
enum l1sched_ts_prim_type type;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Logical channel type */
|
2022-07-02 12:00:53 +00:00
|
|
|
enum l1sched_lchan_type chan;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Payload length */
|
2017-08-12 18:16:24 +00:00
|
|
|
size_t payload_len;
|
2022-07-01 13:19:05 +00:00
|
|
|
/*! Payload */
|
2017-07-12 11:48:18 +00:00
|
|
|
uint8_t payload[0];
|
|
|
|
};
|
|
|
|
|
2022-07-09 15:33:59 +00:00
|
|
|
/*! Represents a RACH (8-bit or 11-bit) primitive */
|
|
|
|
struct l1sched_ts_prim_rach {
|
|
|
|
/*! RA value */
|
|
|
|
uint16_t ra;
|
|
|
|
/*! Training Sequence (only for 11-bit RA) */
|
|
|
|
uint8_t synch_seq;
|
|
|
|
/*! Transmission offset (how many frames to skip) */
|
|
|
|
uint8_t offset;
|
|
|
|
};
|
|
|
|
|
2022-07-04 15:25:27 +00:00
|
|
|
/*! One scheduler instance */
|
|
|
|
struct l1sched_state {
|
|
|
|
/*! Clock state */
|
2022-07-15 22:29:30 +00:00
|
|
|
enum l1sched_clck_state clck_state;
|
2022-07-04 15:25:27 +00:00
|
|
|
/*! Local clock source */
|
|
|
|
struct timespec clock;
|
|
|
|
/*! Count of processed frames */
|
|
|
|
uint32_t fn_counter_proc;
|
|
|
|
/*! Local frame counter advance */
|
|
|
|
uint32_t fn_counter_advance;
|
|
|
|
/*! Count of lost frames */
|
|
|
|
uint32_t fn_counter_lost;
|
|
|
|
/*! Frame callback timer */
|
|
|
|
struct osmo_timer_list clock_timer;
|
|
|
|
/*! Frame callback */
|
|
|
|
void (*clock_cb)(struct l1sched_state *sched);
|
2022-07-06 11:06:07 +00:00
|
|
|
/*! List of timeslots maintained by this scheduler */
|
2022-07-15 21:33:03 +00:00
|
|
|
struct l1sched_ts *ts[TRX_TS_COUNT];
|
2022-07-06 11:06:07 +00:00
|
|
|
/*! BSIC value learned from SCH bursts */
|
|
|
|
uint8_t bsic;
|
2022-07-04 15:25:27 +00:00
|
|
|
};
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
extern const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX];
|
|
|
|
const struct l1sched_tdma_multiframe *l1sched_mframe_layout(
|
2017-07-28 09:36:44 +00:00
|
|
|
enum gsm_phys_chan_config config, int tn);
|
2017-07-04 13:55:12 +00:00
|
|
|
|
|
|
|
/* Scheduler management functions */
|
2022-07-06 11:06:07 +00:00
|
|
|
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance);
|
|
|
|
void l1sched_reset(struct l1sched_state *sched, bool reset_clock);
|
|
|
|
void l1sched_free(struct l1sched_state *sched);
|
2017-07-04 13:55:12 +00:00
|
|
|
|
|
|
|
/* Timeslot management functions */
|
2022-07-06 11:06:07 +00:00
|
|
|
struct l1sched_ts *l1sched_add_ts(struct l1sched_state *sched, int tn);
|
|
|
|
void l1sched_del_ts(struct l1sched_state *sched, int tn);
|
|
|
|
int l1sched_reset_ts(struct l1sched_state *sched, int tn);
|
|
|
|
int l1sched_configure_ts(struct l1sched_state *sched, int tn,
|
2017-07-04 13:55:12 +00:00
|
|
|
enum gsm_phys_chan_config config);
|
2022-07-01 18:42:26 +00:00
|
|
|
int l1sched_start_ciphering(struct l1sched_ts *ts, uint8_t algo,
|
2017-12-17 22:47:28 +00:00
|
|
|
uint8_t *key, uint8_t key_len);
|
2017-07-04 13:55:12 +00:00
|
|
|
|
|
|
|
/* Logical channel management functions */
|
2022-07-01 18:42:26 +00:00
|
|
|
enum gsm_phys_chan_config l1sched_chan_nr2pchan_config(uint8_t chan_nr);
|
|
|
|
enum l1sched_lchan_type l1sched_chan_nr2lchan_type(uint8_t chan_nr,
|
2017-07-29 17:43:52 +00:00
|
|
|
uint8_t link_id);
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
void l1sched_deactivate_all_lchans(struct l1sched_ts *ts);
|
2022-07-06 11:06:07 +00:00
|
|
|
int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr,
|
|
|
|
int active, uint8_t tch_mode, uint8_t tsc);
|
2022-07-01 18:42:26 +00:00
|
|
|
int l1sched_activate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan);
|
|
|
|
int l1sched_deactivate_lchan(struct l1sched_ts *ts, enum l1sched_lchan_type chan);
|
|
|
|
struct l1sched_lchan_state *l1sched_find_lchan(struct l1sched_ts *ts,
|
2022-07-02 12:00:53 +00:00
|
|
|
enum l1sched_lchan_type chan);
|
2017-07-04 14:12:25 +00:00
|
|
|
|
2017-08-12 18:16:24 +00:00
|
|
|
/* Primitive management functions */
|
2022-07-06 11:06:07 +00:00
|
|
|
struct l1sched_ts_prim *l1sched_prim_push(struct l1sched_state *sched,
|
2022-07-09 15:33:59 +00:00
|
|
|
enum l1sched_ts_prim_type type,
|
2022-07-09 14:41:53 +00:00
|
|
|
uint8_t chan_nr, uint8_t link_id,
|
|
|
|
const uint8_t *pl, size_t pl_len);
|
2017-12-17 19:13:41 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_TCH_MODE_IS_SPEECH(mode) \
|
2018-03-10 21:18:06 +00:00
|
|
|
(mode == GSM48_CMODE_SPEECH_V1 \
|
|
|
|
|| mode == GSM48_CMODE_SPEECH_EFR \
|
|
|
|
|| mode == GSM48_CMODE_SPEECH_AMR)
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_TCH_MODE_IS_DATA(mode) \
|
2018-03-10 21:18:06 +00:00
|
|
|
(mode == GSM48_CMODE_DATA_14k5 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_12k0 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_6k0 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_3k6)
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CHAN_IS_TCH(chan) \
|
2022-07-02 12:00:53 +00:00
|
|
|
(chan == L1SCHED_TCHF || chan == L1SCHED_TCHH_0 || chan == L1SCHED_TCHH_1)
|
2018-01-04 00:20:39 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_CHAN_IS_SACCH(chan) \
|
|
|
|
(l1sched_lchan_desc[chan].link_id & L1SCHED_CH_LID_SACCH)
|
2018-03-22 16:04:16 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_PRIM_IS_RACH11(prim) \
|
2022-07-09 15:33:59 +00:00
|
|
|
(prim->type == L1SCHED_PRIM_RACH11)
|
2019-05-29 20:59:16 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_PRIM_IS_RACH8(prim) \
|
2022-07-09 15:33:59 +00:00
|
|
|
(prim->type == L1SCHED_PRIM_RACH8)
|
2019-05-29 20:59:16 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_PRIM_IS_RACH(prim) \
|
|
|
|
(L1SCHED_PRIM_IS_RACH8(prim) || L1SCHED_PRIM_IS_RACH11(prim))
|
2019-05-29 20:59:16 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_PRIM_IS_TCH(prim) \
|
|
|
|
(L1SCHED_CHAN_IS_TCH(prim->chan) && prim->payload_len != GSM_MACBLOCK_LEN)
|
2018-01-04 00:20:39 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define L1SCHED_PRIM_IS_FACCH(prim) \
|
|
|
|
(L1SCHED_CHAN_IS_TCH(prim->chan) && prim->payload_len == GSM_MACBLOCK_LEN)
|
2018-01-04 00:20:39 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
struct l1sched_ts_prim *l1sched_prim_dequeue(struct llist_head *queue,
|
|
|
|
uint32_t fn, struct l1sched_lchan_state *lchan);
|
|
|
|
int l1sched_prim_dummy(struct l1sched_lchan_state *lchan);
|
|
|
|
void l1sched_prim_drop(struct l1sched_lchan_state *lchan);
|
|
|
|
void l1sched_prim_flush_queue(struct llist_head *list);
|
2017-08-12 18:16:24 +00:00
|
|
|
|
2022-07-06 11:06:07 +00:00
|
|
|
int l1sched_handle_rx_burst(struct l1sched_state *sched, uint8_t tn,
|
2020-03-04 14:22:11 +00:00
|
|
|
uint32_t fn, sbit_t *bits, uint16_t nbits,
|
2022-07-01 18:42:26 +00:00
|
|
|
const struct l1sched_meas_set *meas);
|
2017-08-16 07:36:20 +00:00
|
|
|
|
|
|
|
/* Shared declarations for lchan handlers */
|
2022-07-01 18:42:26 +00:00
|
|
|
extern const uint8_t l1sched_nb_training_bits[8][26];
|
2017-08-16 07:36:20 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
const char *l1sched_burst_mask2str(const uint8_t *mask, int bits);
|
|
|
|
size_t l1sched_bad_frame_ind(uint8_t *l2, struct l1sched_lchan_state *lchan);
|
2018-08-14 18:17:10 +00:00
|
|
|
|
|
|
|
/* Interleaved TCH/H block TDMA frame mapping */
|
2022-07-01 18:42:26 +00:00
|
|
|
uint32_t l1sched_tchh_block_dl_first_fn(enum l1sched_lchan_type chan,
|
2018-08-14 18:17:10 +00:00
|
|
|
uint32_t last_fn, bool facch);
|
2022-07-01 18:42:26 +00:00
|
|
|
bool l1sched_tchh_block_map_fn(enum l1sched_lchan_type chan,
|
2018-08-14 18:17:10 +00:00
|
|
|
uint32_t fn, bool ul, bool facch, bool start);
|
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define l1sched_tchh_traffic_start(chan, fn, ul) \
|
|
|
|
l1sched_tchh_block_map_fn(chan, fn, ul, 0, 1)
|
|
|
|
#define l1sched_tchh_traffic_end(chan, fn, ul) \
|
|
|
|
l1sched_tchh_block_map_fn(chan, fn, ul, 0, 0)
|
2018-08-14 18:17:10 +00:00
|
|
|
|
2022-07-01 18:42:26 +00:00
|
|
|
#define l1sched_tchh_facch_start(chan, fn, ul) \
|
|
|
|
l1sched_tchh_block_map_fn(chan, fn, ul, 1, 1)
|
|
|
|
#define l1sched_tchh_facch_end(chan, fn, ul) \
|
|
|
|
l1sched_tchh_block_map_fn(chan, fn, ul, 1, 0)
|
2020-03-01 19:55:01 +00:00
|
|
|
|
|
|
|
/* Measurement history */
|
2022-07-01 18:42:26 +00:00
|
|
|
void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan, const struct l1sched_meas_set *meas);
|
|
|
|
void l1sched_lchan_meas_avg(struct l1sched_lchan_state *lchan, unsigned int n);
|
2022-07-04 15:25:27 +00:00
|
|
|
|
|
|
|
int l1sched_clck_handle(struct l1sched_state *sched, uint32_t fn);
|
|
|
|
void l1sched_clck_reset(struct l1sched_state *sched);
|
2022-07-06 11:06:07 +00:00
|
|
|
|
|
|
|
/* External L1 API, must be implemented by the API user */
|
|
|
|
int l1sched_handle_config_req(struct l1sched_state *sched,
|
|
|
|
const struct l1sched_config_req *cr);
|
|
|
|
int l1sched_handle_burst_req(struct l1sched_state *sched,
|
|
|
|
const struct l1sched_burst_req *br);
|
|
|
|
|
|
|
|
/* External L2 API, must be implemented by the API user */
|
|
|
|
int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
|
|
|
|
const uint8_t *data, size_t data_len,
|
|
|
|
int n_errors, int n_bits_total,
|
|
|
|
enum l1sched_data_type dt);
|
|
|
|
int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
|
|
|
|
uint32_t fn, enum l1sched_data_type dt);
|