2017-07-04 12:38:50 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#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>
|
|
|
|
#include <osmocom/core/linuxlist.h>
|
|
|
|
|
|
|
|
#include "logging.h"
|
|
|
|
#include "scheduler.h"
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2018-03-22 16:02:25 +00:00
|
|
|
#define TRX_CH_LID_DEDIC 0x00
|
|
|
|
#define TRX_CH_LID_SACCH 0x40
|
|
|
|
|
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. */
|
|
|
|
#define TRX_CH_LID_PTCCH 0x80
|
|
|
|
|
2018-03-10 20:16:40 +00:00
|
|
|
/* Is a channel related to PDCH (GPRS) */
|
2017-07-04 12:38:50 +00:00
|
|
|
#define TRX_CH_FLAG_PDCH (1 << 0)
|
2018-03-10 20:16:40 +00:00
|
|
|
/* Should a channel be activated automatically */
|
2017-07-04 12:38:50 +00:00
|
|
|
#define TRX_CH_FLAG_AUTO (1 << 1)
|
2018-03-10 20:19:33 +00:00
|
|
|
/* Is continuous burst transmission assumed */
|
|
|
|
#define TRX_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
|
|
|
|
|
|
|
/* Forward declaration to avoid mutual include */
|
2017-07-31 07:27:30 +00:00
|
|
|
struct trx_lchan_state;
|
2017-07-04 12:38:50 +00:00
|
|
|
struct trx_instance;
|
|
|
|
struct trx_ts;
|
|
|
|
|
|
|
|
enum trx_burst_type {
|
|
|
|
TRX_BURST_GMSK,
|
|
|
|
TRX_BURST_8PSK,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These types define the different channels on a multiframe.
|
|
|
|
* Each channel has queues and can be activated individually.
|
|
|
|
*/
|
|
|
|
enum trx_lchan_type {
|
|
|
|
TRXC_IDLE = 0,
|
|
|
|
TRXC_FCCH,
|
|
|
|
TRXC_SCH,
|
|
|
|
TRXC_BCCH,
|
|
|
|
TRXC_RACH,
|
|
|
|
TRXC_CCCH,
|
|
|
|
TRXC_TCHF,
|
|
|
|
TRXC_TCHH_0,
|
|
|
|
TRXC_TCHH_1,
|
|
|
|
TRXC_SDCCH4_0,
|
|
|
|
TRXC_SDCCH4_1,
|
|
|
|
TRXC_SDCCH4_2,
|
|
|
|
TRXC_SDCCH4_3,
|
|
|
|
TRXC_SDCCH8_0,
|
|
|
|
TRXC_SDCCH8_1,
|
|
|
|
TRXC_SDCCH8_2,
|
|
|
|
TRXC_SDCCH8_3,
|
|
|
|
TRXC_SDCCH8_4,
|
|
|
|
TRXC_SDCCH8_5,
|
|
|
|
TRXC_SDCCH8_6,
|
|
|
|
TRXC_SDCCH8_7,
|
|
|
|
TRXC_SACCHTF,
|
|
|
|
TRXC_SACCHTH_0,
|
|
|
|
TRXC_SACCHTH_1,
|
|
|
|
TRXC_SACCH4_0,
|
|
|
|
TRXC_SACCH4_1,
|
|
|
|
TRXC_SACCH4_2,
|
|
|
|
TRXC_SACCH4_3,
|
|
|
|
TRXC_SACCH8_0,
|
|
|
|
TRXC_SACCH8_1,
|
|
|
|
TRXC_SACCH8_2,
|
|
|
|
TRXC_SACCH8_3,
|
|
|
|
TRXC_SACCH8_4,
|
|
|
|
TRXC_SACCH8_5,
|
|
|
|
TRXC_SACCH8_6,
|
|
|
|
TRXC_SACCH8_7,
|
|
|
|
TRXC_PDTCH,
|
|
|
|
TRXC_PTCCH,
|
trxcon/scheduler: add CCCH/SDCCH mframe layouts with CBCH
According to GSM TS 05.02, section 3.3.5, Cell Broadcast Channel
(CBCH) is a downlink only channel, which is used to carry the
short message service cell broadcast (SMSCB). CBCH is optional,
and uses the same physical channel as SDCCH. More precisely,
CBCH replaces sub-slot number 2 of SDCCH channels when enabled.
This change introduces the CBCH enabled multi-frame layouts,
and two separate logical channel types:
- GSM_PCHAN_CCCH_SDCCH4_CBCH (lchan TRXC_SDCCH4_CBCH),
- GSM_PCHAN_SDCCH8_SACCH8C_CBCH (lchan TRXC_SDCCH8_CBCH).
Both logical channels are separately identified using
the following Osmocom specific cbits:
- TRXC_SDCCH4_CBCH - 0x18 (0b11000),
- TRXC_SDCCH8_CBCH - 0x19 (0b11001).
The reason of this separation is that we somehow need to
distinguish between CBCH on C0/TS0, and CBCH on CX/TS0.
Unlike TRXC_SDCCH8_CBCH, TRXC_SDCCH4_CBCH is enabled
automatically (TRX_CH_FLAG_AUTO), so CBCH messages
can be decoded on C0 while being in idle mode.
Change-Id: Iad9905fc3a8a012ff1ada26ff95af384816f9873
2018-09-15 14:34:41 +00:00
|
|
|
TRXC_SDCCH4_CBCH,
|
|
|
|
TRXC_SDCCH8_CBCH,
|
2017-07-04 12:38:50 +00:00
|
|
|
_TRX_CHAN_MAX
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef int trx_lchan_rx_func(struct trx_instance *trx,
|
2017-07-31 07:27:30 +00:00
|
|
|
struct trx_ts *ts, struct trx_lchan_state *lchan,
|
|
|
|
uint32_t fn, uint8_t bid, sbit_t *bits,
|
2018-03-02 14:24:57 +00:00
|
|
|
int8_t rssi, int16_t toa256);
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2017-07-12 10:58:31 +00:00
|
|
|
typedef int trx_lchan_tx_func(struct trx_instance *trx,
|
2017-07-31 07:27:30 +00:00
|
|
|
struct trx_ts *ts, struct trx_lchan_state *lchan,
|
2017-07-31 08:03:51 +00:00
|
|
|
uint32_t fn, uint8_t bid);
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
struct trx_lchan_desc {
|
|
|
|
/*! \brief Human-readable name */
|
|
|
|
const char *name;
|
2019-05-27 23:25:24 +00:00
|
|
|
/*! \brief Human-readable description */
|
|
|
|
const char *desc;
|
|
|
|
|
2017-07-04 12:38:50 +00:00
|
|
|
/*! \brief Channel Number (like in RSL) */
|
|
|
|
uint8_t chan_nr;
|
|
|
|
/*! \brief Link ID (like in RSL) */
|
|
|
|
uint8_t link_id;
|
2019-09-18 14:38:03 +00:00
|
|
|
/*! \brief Sub-slot number (for SDCCH and TCH/H) */
|
|
|
|
uint8_t ss_nr;
|
|
|
|
/*! \brief GSMTAP channel type (see GSMTAP_CHANNEL_*) */
|
|
|
|
uint8_t gsmtap_chan_type;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
/*! \brief How much memory do we need to store bursts */
|
|
|
|
size_t burst_buf_size;
|
|
|
|
/*! \brief Channel specific flags */
|
|
|
|
uint8_t flags;
|
|
|
|
|
|
|
|
/*! \brief Function to call when burst received from PHY */
|
|
|
|
trx_lchan_rx_func *rx_fn;
|
|
|
|
/*! \brief Function to call when data received from L2 */
|
|
|
|
trx_lchan_tx_func *tx_fn;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct trx_frame {
|
|
|
|
/*! \brief Downlink TRX channel type */
|
|
|
|
enum trx_lchan_type dl_chan;
|
|
|
|
/*! \brief Downlink block ID */
|
|
|
|
uint8_t dl_bid;
|
|
|
|
/*! \brief Uplink TRX channel type */
|
|
|
|
enum trx_lchan_type ul_chan;
|
|
|
|
/*! \brief Uplink block ID */
|
|
|
|
uint8_t ul_bid;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct trx_multiframe {
|
|
|
|
/*! \brief Channel combination */
|
|
|
|
enum gsm_phys_chan_config chan_config;
|
|
|
|
/*! \brief Human-readable name */
|
|
|
|
const char *name;
|
|
|
|
/*! \brief Repeats how many frames */
|
|
|
|
uint8_t period;
|
|
|
|
/*! \brief Applies to which timeslots */
|
|
|
|
uint8_t slotmask;
|
|
|
|
/*! \brief Contains which lchans */
|
|
|
|
uint64_t lchan_mask;
|
|
|
|
/*! \brief Pointer to scheduling structure */
|
|
|
|
const struct trx_frame *frames;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* States each channel on a multiframe */
|
|
|
|
struct trx_lchan_state {
|
|
|
|
/*! \brief Channel type */
|
|
|
|
enum trx_lchan_type type;
|
|
|
|
/*! \brief Channel status */
|
|
|
|
uint8_t active;
|
2018-01-05 00:24:04 +00:00
|
|
|
/*! \brief Link to a list of channels */
|
|
|
|
struct llist_head list;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
|
|
|
/*! \brief Burst type: GMSK or 8PSK */
|
|
|
|
enum trx_burst_type burst_type;
|
|
|
|
/*! \brief Frame number of first burst */
|
|
|
|
uint32_t rx_first_fn;
|
|
|
|
/*! \brief Mask of received bursts */
|
|
|
|
uint8_t rx_burst_mask;
|
2017-07-15 15:46:54 +00:00
|
|
|
/*! \brief Mask of transmitted bursts */
|
|
|
|
uint8_t tx_burst_mask;
|
2017-07-04 12:38:50 +00:00
|
|
|
/*! \brief Burst buffer for RX */
|
|
|
|
sbit_t *rx_bursts;
|
|
|
|
/*! \brief Burst buffer for TX */
|
|
|
|
ubit_t *tx_bursts;
|
|
|
|
|
2017-12-17 20:47:23 +00:00
|
|
|
/*! \brief A primitive being sent */
|
|
|
|
struct trx_ts_prim *prim;
|
|
|
|
|
2018-08-15 02:00:16 +00:00
|
|
|
/*! \brief Mode for TCH channels (see GSM48_CMODE_*) */
|
|
|
|
uint8_t tch_mode;
|
2017-07-04 12:38:50 +00:00
|
|
|
|
2017-12-16 07:53:48 +00:00
|
|
|
/*! \brief FACCH/H on downlink */
|
2018-08-12 21:48:14 +00:00
|
|
|
bool dl_ongoing_facch;
|
|
|
|
/*! \brief pending FACCH/H blocks on Uplink */
|
|
|
|
uint8_t ul_facch_blocks;
|
2017-12-16 07:53:48 +00:00
|
|
|
|
2017-07-04 12:38:50 +00:00
|
|
|
struct {
|
2019-01-21 07:58:25 +00:00
|
|
|
/*! \brief Number of measurements */
|
|
|
|
unsigned int num;
|
2017-12-16 07:53:48 +00:00
|
|
|
/*! \brief Sum of RSSI values */
|
|
|
|
float rssi_sum;
|
2017-07-04 12:38:50 +00:00
|
|
|
/*! \brief Sum of TOA values */
|
2018-03-02 14:24:57 +00:00
|
|
|
int32_t toa256_sum;
|
2017-07-04 12:38:50 +00:00
|
|
|
} meas;
|
2017-12-16 07:53:48 +00:00
|
|
|
|
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
|
|
|
/*! \brief SACCH state */
|
|
|
|
struct {
|
|
|
|
/*! \brief Cached measurement report (last received) */
|
|
|
|
uint8_t mr_cache[GSM_MACBLOCK_LEN];
|
|
|
|
/*! \brief Cache usage counter */
|
|
|
|
uint8_t mr_cache_usage;
|
|
|
|
/*! \brief Was a MR transmitted last time? */
|
|
|
|
bool mr_tx_last;
|
|
|
|
} sacch;
|
|
|
|
|
2017-12-16 07:53:48 +00:00
|
|
|
/* AMR specific */
|
|
|
|
struct {
|
|
|
|
/*! \brief 4 possible codecs for AMR */
|
|
|
|
uint8_t codec[4];
|
|
|
|
/*! \brief Number of possible codecs */
|
|
|
|
uint8_t codecs;
|
|
|
|
/*! \brief Current uplink FT index */
|
|
|
|
uint8_t ul_ft;
|
|
|
|
/*! \brief Current downlink FT index */
|
|
|
|
uint8_t dl_ft;
|
|
|
|
/*! \brief Current uplink CMR index */
|
|
|
|
uint8_t ul_cmr;
|
|
|
|
/*! \brief Current downlink CMR index */
|
|
|
|
uint8_t dl_cmr;
|
|
|
|
/*! \brief If AMR loop is enabled */
|
|
|
|
uint8_t amr_loop;
|
|
|
|
/*! \brief Number of bit error rates */
|
|
|
|
uint8_t ber_num;
|
|
|
|
/*! \brief Sum of bit error rates */
|
|
|
|
float ber_sum;
|
|
|
|
} amr;
|
|
|
|
|
|
|
|
/*! \brief A5/X encryption state */
|
|
|
|
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 */
|
|
|
|
struct trx_ts *ts;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct trx_ts {
|
|
|
|
/*! \brief Timeslot index within a frame (0..7) */
|
|
|
|
uint8_t index;
|
|
|
|
/*! \brief Last received frame number */
|
|
|
|
uint32_t mf_last_fn;
|
|
|
|
|
|
|
|
/*! \brief Pointer to multiframe layout */
|
|
|
|
const struct trx_multiframe *mf_layout;
|
|
|
|
/*! \brief Channel states for logical channels */
|
2018-01-05 00:24:04 +00:00
|
|
|
struct llist_head lchans;
|
2017-07-04 12:38:50 +00:00
|
|
|
/*! \brief Queue primitives for TX */
|
|
|
|
struct llist_head tx_prims;
|
2019-12-04 13:20:05 +00:00
|
|
|
/* backpointer to its TRX */
|
|
|
|
struct trx_instance *trx;
|
2017-07-04 12:38:50 +00:00
|
|
|
};
|
|
|
|
|
2017-07-12 11:48:18 +00:00
|
|
|
/* Represents one TX primitive in the queue of trx_ts */
|
|
|
|
struct trx_ts_prim {
|
|
|
|
/*! \brief Link to queue of TS */
|
|
|
|
struct llist_head list;
|
|
|
|
/*! \brief Logical channel type */
|
|
|
|
enum trx_lchan_type chan;
|
2017-08-12 18:16:24 +00:00
|
|
|
/*! \brief Payload length */
|
|
|
|
size_t payload_len;
|
2017-07-12 11:48:18 +00:00
|
|
|
/*! \brief Payload */
|
|
|
|
uint8_t payload[0];
|
|
|
|
};
|
|
|
|
|
2017-07-04 12:38:50 +00:00
|
|
|
extern const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX];
|
|
|
|
const struct trx_multiframe *sched_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 */
|
2017-11-23 13:05:00 +00:00
|
|
|
int sched_trx_init(struct trx_instance *trx, uint32_t fn_advance);
|
2019-01-15 10:53:02 +00:00
|
|
|
int sched_trx_reset(struct trx_instance *trx, bool reset_clock);
|
2017-07-04 13:55:12 +00:00
|
|
|
int sched_trx_shutdown(struct trx_instance *trx);
|
|
|
|
|
|
|
|
/* Timeslot management functions */
|
2017-07-28 09:36:44 +00:00
|
|
|
struct trx_ts *sched_trx_add_ts(struct trx_instance *trx, int tn);
|
|
|
|
void sched_trx_del_ts(struct trx_instance *trx, int tn);
|
|
|
|
int sched_trx_reset_ts(struct trx_instance *trx, int tn);
|
|
|
|
int sched_trx_configure_ts(struct trx_instance *trx, int tn,
|
2017-07-04 13:55:12 +00:00
|
|
|
enum gsm_phys_chan_config config);
|
2017-12-17 22:47:28 +00:00
|
|
|
int sched_trx_start_ciphering(struct trx_ts *ts, uint8_t algo,
|
|
|
|
uint8_t *key, uint8_t key_len);
|
2017-07-04 13:55:12 +00:00
|
|
|
|
|
|
|
/* Logical channel management functions */
|
2017-07-15 08:20:35 +00:00
|
|
|
enum gsm_phys_chan_config sched_trx_chan_nr2pchan_config(uint8_t chan_nr);
|
2017-07-29 17:43:52 +00:00
|
|
|
enum trx_lchan_type sched_trx_chan_nr2lchan_type(uint8_t chan_nr,
|
|
|
|
uint8_t link_id);
|
|
|
|
|
2017-07-15 08:20:35 +00:00
|
|
|
void sched_trx_deactivate_all_lchans(struct trx_ts *ts);
|
2018-04-02 17:57:55 +00:00
|
|
|
int sched_trx_set_lchans(struct trx_ts *ts, uint8_t chan_nr, int active, uint8_t tch_mode);
|
2017-07-04 13:55:12 +00:00
|
|
|
int sched_trx_activate_lchan(struct trx_ts *ts, enum trx_lchan_type chan);
|
|
|
|
int sched_trx_deactivate_lchan(struct trx_ts *ts, enum trx_lchan_type chan);
|
|
|
|
struct trx_lchan_state *sched_trx_find_lchan(struct trx_ts *ts,
|
|
|
|
enum trx_lchan_type chan);
|
2017-07-04 14:12:25 +00:00
|
|
|
|
2017-08-12 18:16:24 +00:00
|
|
|
/* Primitive management functions */
|
2018-09-27 22:28:36 +00:00
|
|
|
int sched_prim_init(void *ctx, struct trx_ts_prim **prim,
|
2017-08-12 18:16:24 +00:00
|
|
|
size_t pl_len, uint8_t chan_nr, uint8_t link_id);
|
2017-12-17 19:13:41 +00:00
|
|
|
int sched_prim_push(struct trx_instance *trx,
|
2017-08-12 18:16:24 +00:00
|
|
|
struct trx_ts_prim *prim, uint8_t chan_nr);
|
2017-12-17 19:13:41 +00:00
|
|
|
|
2018-03-10 21:18:06 +00:00
|
|
|
#define TCH_MODE_IS_SPEECH(mode) \
|
|
|
|
(mode == GSM48_CMODE_SPEECH_V1 \
|
|
|
|
|| mode == GSM48_CMODE_SPEECH_EFR \
|
|
|
|
|| mode == GSM48_CMODE_SPEECH_AMR)
|
|
|
|
|
|
|
|
#define TCH_MODE_IS_DATA(mode) \
|
|
|
|
(mode == GSM48_CMODE_DATA_14k5 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_12k0 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_6k0 \
|
|
|
|
|| mode == GSM48_CMODE_DATA_3k6)
|
|
|
|
|
2018-01-04 00:20:39 +00:00
|
|
|
#define CHAN_IS_TCH(chan) \
|
|
|
|
(chan == TRXC_TCHF || chan == TRXC_TCHH_0 || chan == TRXC_TCHH_1)
|
|
|
|
|
2018-03-22 16:04:16 +00:00
|
|
|
#define CHAN_IS_SACCH(chan) \
|
|
|
|
(trx_lchan_desc[chan].link_id & TRX_CH_LID_SACCH)
|
|
|
|
|
2019-05-29 20:59:16 +00:00
|
|
|
/* FIXME: we need a better way to identify / distinguish primitives */
|
|
|
|
#define PRIM_IS_RACH11(prim) \
|
|
|
|
(prim->payload_len == sizeof(struct l1ctl_ext_rach_req))
|
|
|
|
|
|
|
|
#define PRIM_IS_RACH8(prim) \
|
|
|
|
(prim->payload_len == sizeof(struct l1ctl_rach_req))
|
|
|
|
|
|
|
|
#define PRIM_IS_RACH(prim) \
|
|
|
|
(PRIM_IS_RACH8(prim) || PRIM_IS_RACH11(prim))
|
|
|
|
|
2018-01-04 00:20:39 +00:00
|
|
|
#define PRIM_IS_TCH(prim) \
|
2018-08-13 21:52:01 +00:00
|
|
|
(CHAN_IS_TCH(prim->chan) && prim->payload_len != GSM_MACBLOCK_LEN)
|
2018-01-04 00:20:39 +00:00
|
|
|
|
|
|
|
#define PRIM_IS_FACCH(prim) \
|
2018-08-13 21:52:01 +00:00
|
|
|
(CHAN_IS_TCH(prim->chan) && prim->payload_len == GSM_MACBLOCK_LEN)
|
2018-01-04 00:20:39 +00:00
|
|
|
|
2017-12-17 20:47:23 +00:00
|
|
|
struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,
|
2018-09-27 19:47:54 +00:00
|
|
|
uint32_t fn, struct trx_lchan_state *lchan);
|
2018-03-10 21:18:06 +00:00
|
|
|
int sched_prim_dummy(struct trx_lchan_state *lchan);
|
2017-12-17 20:47:23 +00:00
|
|
|
void sched_prim_drop(struct trx_lchan_state *lchan);
|
2017-12-17 19:13:41 +00:00
|
|
|
void sched_prim_flush_queue(struct llist_head *list);
|
2017-08-12 18:16:24 +00:00
|
|
|
|
2017-07-28 09:36:44 +00:00
|
|
|
int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
|
2018-03-02 14:24:57 +00:00
|
|
|
uint32_t burst_fn, sbit_t *bits, uint16_t nbits,
|
|
|
|
int8_t rssi, int16_t toa256);
|
2017-12-17 22:45:27 +00:00
|
|
|
int sched_trx_handle_tx_burst(struct trx_instance *trx,
|
|
|
|
struct trx_ts *ts, struct trx_lchan_state *lchan,
|
|
|
|
uint32_t fn, ubit_t *bits);
|
2017-08-16 07:36:20 +00:00
|
|
|
|
|
|
|
/* Shared declarations for lchan handlers */
|
|
|
|
extern const uint8_t sched_nb_training_bits[8][26];
|
|
|
|
|
2020-02-29 18:27:46 +00:00
|
|
|
const char *burst_mask2str(const uint8_t *mask, int bits);
|
2018-08-15 00:56:42 +00:00
|
|
|
size_t sched_bad_frame_ind(uint8_t *l2, struct trx_lchan_state *lchan);
|
2018-03-09 08:24:20 +00:00
|
|
|
int sched_send_dt_ind(struct trx_instance *trx, struct trx_ts *ts,
|
2017-12-16 09:21:05 +00:00
|
|
|
struct trx_lchan_state *lchan, uint8_t *l2, size_t l2_len,
|
2018-03-09 08:24:20 +00:00
|
|
|
int bit_error_count, bool dec_failed, bool traffic);
|
|
|
|
int sched_send_dt_conf(struct trx_instance *trx, struct trx_ts *ts,
|
|
|
|
struct trx_lchan_state *lchan, uint32_t fn, bool traffic);
|
2019-09-18 14:38:03 +00:00
|
|
|
int sched_gsmtap_send(enum trx_lchan_type lchan_type, uint32_t fn, uint8_t tn,
|
|
|
|
uint16_t band_arfcn, int8_t signal_dbm, uint8_t snr,
|
|
|
|
const uint8_t *data, size_t data_len);
|
2018-08-14 18:17:10 +00:00
|
|
|
|
|
|
|
/* Interleaved TCH/H block TDMA frame mapping */
|
|
|
|
uint32_t sched_tchh_block_dl_first_fn(enum trx_lchan_type chan,
|
|
|
|
uint32_t last_fn, bool facch);
|
|
|
|
bool sched_tchh_block_map_fn(enum trx_lchan_type chan,
|
|
|
|
uint32_t fn, bool ul, bool facch, bool start);
|
|
|
|
|
|
|
|
#define sched_tchh_traffic_start(chan, fn, ul) \
|
|
|
|
sched_tchh_block_map_fn(chan, fn, ul, 0, 1)
|
|
|
|
#define sched_tchh_traffic_end(chan, fn, ul) \
|
|
|
|
sched_tchh_block_map_fn(chan, fn, ul, 0, 0)
|
|
|
|
|
|
|
|
#define sched_tchh_facch_start(chan, fn, ul) \
|
|
|
|
sched_tchh_block_map_fn(chan, fn, ul, 1, 1)
|
|
|
|
#define sched_tchh_facch_end(chan, fn, ul) \
|
|
|
|
sched_tchh_block_map_fn(chan, fn, ul, 1, 0)
|