libosmo-abis/include/osmocom/trau/trau_pcu_ericsson.h

304 lines
9.9 KiB
C

#pragma once
enum time_adj_val {
TIME_ADJ_NONE,
TIME_ADJ_DELAY_250us,
TIME_ADJ_ADVANCE_250us,
};
enum er_cs_or_hdr {
CS_OR_HDR_AB = 0,
CS_OR_HDR_CS1 = 1,
CS_OR_HDR_CS2 = 2,
CS_OR_HDR_CS3 = 3,
CS_OR_HDR_CS4 = 4,
CS_OR_HDR_HDR1 = 5,
CS_OR_HDR_HDR2 = 6,
CS_OR_HDR_HDR3 = 7,
};
/* Block Quality / Soft Frame Quality */
enum er_block_qual {
ER_SFQ_00_09 = 0,
ER_SFQ_10_19 = 1,
ER_SFQ_20_29 = 2,
ER_SFQ_30_39 = 3,
ER_SFQ_40_49 = 4,
ER_SFQ_50_59 = 5,
ER_SFQ_60_69 = 6,
ER_SFQ_70_MORE = 7,
};
enum er_ul_chan_mode {
/* no demodulation, ignore uplink */
ER_UL_CHMOD_VOID = 0,
/* normal burst, GMSK only */
ER_UL_CHMOD_NB_GMSK = 1,
/* normal burst, MCS1..MCS9 or CS1 */
ER_UL_CHMOD_NB_UNKN = 2,
/* Access Burst (only TS0 and 8bit) */
ER_UL_CHMOD_AB = 3,
/* Access Burst (TS0/1/2) */
ER_UL_CHMOD_AB_UNKN = 4,
};
/* Access burst data */
struct er_gprs_ab {
uint8_t ab_type;
uint8_t rxlev;
uint16_t acc_delay;
uint16_t data;
union {
struct {
uint8_t crc;
uint8_t burst_qual;
uint8_t frame_qual;
} type_1;
struct {
uint8_t abi;
uint8_t type;
} type_2;
} u;
};
/* CCU->PCU SYNC */
struct er_ccu_sync_ind {
/* Time Adjustment Value (requested) */
enum time_adj_val tav;
/* Downlink Frame Error */
bool dfe;
/* Downlink Block Error (bad MAC block from PCU) */
bool dbe;
/* PCU Sequene Counter (will lag, must be compensated) */
uint32_t pseq;
/* Adjusted Frame Number, Uplink */
uint32_t afn_ul;
/* Adjusted Frame Number, Downlink */
uint32_t afn_dl;
};
/* PCU->CCU SYNC */
struct er_pcu_sync_ind {
/* Time Adjustment Value (acknowledged) */
enum time_adj_val tav;
bool ul_frame_err;
/* PCU Sequene Counter (PCU will sync to this value) */
uint32_t pseq;
/* Optional, ignored by CCU */
uint32_t ss;
/* Optional, ignored by CCU */
uint32_t fn_ul;
/* Optional, ignored by CCU */
uint32_t fn_ss;
/* Optional, ignored by CCU */
uint32_t fn_dl;
/* Optional, ignored by CCU */
uint32_t ls;
};
/* PCU->CCU DATA */
struct er_pcu_data_ind {
/* Time Adjustment Value (acknowledged) */
enum time_adj_val tav;
/* Uplink Frame Error */
bool ul_frame_err;
/* Coding Scheme */
enum er_cs_or_hdr cs_hdr;
/* Modulation to be applied on coresponding uplink frame, also used to retrieve
* extraordinary ccu_sync_ind frames and ccu_data_ind frames wth Access bursts data. */
enum er_ul_chan_mode ul_chan_mode;
/* Attenuation of transmission power, 16 steps, 2dB each */
uint8_t atten_db;
/* Timing offset (timing advance) */
uint8_t timing_offset;
/* MAC block */
uint8_t data[155];
};
/* CCU->PCU DATA */
struct er_ccu_data_ind {
/* Time Adjustment Value (requested) */
enum time_adj_val tav;
/* Downlink Block Error (bad MAC block from PCU) */
bool dbe;
/* Coding Scheme */
enum er_cs_or_hdr cs_hdr;
/* Receive level 63 steps, see also GSM 05.08, section 8.1.4 */
uint8_t rx_lev;
/* Estimated Access Delay Deviation (bits, uplink only) */
int8_t est_acc_del_dev;
/* Data integrity checks (uplink only) */
union {
struct {
/* Soft Frame Quality */
enum er_block_qual block_qual;
/* Parity Check */
bool parity_ok;
} gprs;
struct {
uint8_t mean_bep;
uint8_t cv_bep;
bool hdr_good;
bool data_good[2];
} egprs;
} u;
/* MAC block */
uint8_t data[155];
/* MAC block length
* (uplink only, for downlink cs_hdr and MAC block header will be used
* to determine the length.) */
uint8_t data_len;
/* Access burst data (in case an access block was received) */
struct er_gprs_ab ab[4];
};
enum er_gprs_trau_frame_type {
ER_GPRS_TRAU_FT_NONE,
ER_GPRS_TRAU_FT_SYNC,
ER_GPRS_TRAU_FT_DATA,
};
struct er_gprs_trau_frame {
enum er_gprs_trau_frame_type type;
union {
struct er_ccu_sync_ind ccu_sync_ind;
struct er_ccu_data_ind ccu_data_ind;
struct er_pcu_sync_ind pcu_sync_ind;
struct er_pcu_data_ind pcu_data_ind;
} u;
};
#define ER_GPRS_TRAU_FRAME_LEN_16K 324 /* 320 +/-4 bit for time alignment */
#define ER_GPRS_TRAU_FRAME_LEN_64K 1296 /* 1280 +/-16 bit for time alignment */
int er_gprs_trau_frame_encode_16k(ubit_t *bits, struct er_gprs_trau_frame *fr);
int er_gprs_trau_frame_decode_16k(struct er_gprs_trau_frame *fr, const ubit_t *bits);
int er_gprs_trau_frame_encode_64k(ubit_t *bits, struct er_gprs_trau_frame *fr);
int er_gprs_trau_frame_decode_64k(struct er_gprs_trau_frame *fr, const ubit_t *bits);
/*
* Idle pattern
* ============
* An inactive CCU will send an idle pattern, which is a sequence of alternating ones and zeros (101010101...) The
* idle pattern indicates that the CCU available but in idle state. To leave the idle state a channel activation
* via RSL must be carried out. It is not possible to "wake up" an idle CCU by just sending TRAU frames to it.
*
*
* Synchronization procedure
* =========================
* When the PDCH is activated, the CCU becomes active at its designated E1 timeslot/subslot. It sends out ccu_sync_ind
* frames and expects pcu_sync_ind frames from the PCU. When the CCU does not receive any pcu_sync_ind frames, the CCU
* becomes inactive until the PDCH is activated again.
*
* CCU is synchronized to the PCU by sending pcu_sync_ind frames with an incrementing PSEQ sequence number to the CCU.
* The PSEQ has no relation to the actual frame number. It just counts the TRAU frames sent over the E1 link. When
* the CCU receives a valid pcu_sync_ind it will synchronize its local PSEQ counter to the received PSEQ and respond
* back with a ccu_sync_ind that echos the PSEQ and also contains the current GSM frame numbers. The synchronization
* is then complete and the PCU may start sending pcu_data_ind.
*
* PCU CCU
* | |
* |--------pcu_sync_ind-------->|
* |<-------idle pattern---------|
* |--------pcu_sync_ind-------->|
* |<-------idle pattern---------|
* |--------pcu_sync_ind-------->|
* |<-------idle pattern---------|
* |--------pcu_sync_ind-------->|
* |<-------ccu_sync_ind---------|
* |--------pcu_sync_ind-------->|
* |<-------ccu_sync_ind---------|
* |--------pcu_sync_ind-------->|
* |<-------ccu_sync_ind---------|
* |--------pcu_data_ind-------->|
* |<-------ccu_data_ind---------|
* |--------pcu_data_ind-------->|
* |<-------ccu_data_ind---------|
*
* While pcu_data_ind and ccu_data_ind frames are passed over the link the PCU has no way to get the current PSEQ or
* any GSM frame number from the CCU. It must calculate those values locally. However, it is possible to request
* a ccu_sync_ind from the CCU at any time by setting the requested demodulation to ER_UL_CHMOD_VOID in one
* pcu_data_ind. It should be pointed out that the requested ccu_sync_ind will steal one pcu_data_ind. The requested
* ccu_sync_ind message will also only contain the GSM frame numbers but not the PSEQ value. If the GSM frame numbers
* in the received ccu_sync_ind are deviating from the local frame numbers, the synchronization procedure can be
* carried out again.
*
* PCU CCU
* | |
* |--------pcu_data_ind-------->|
* |<-------ccu_data_ind---------|
* |--------pcu_data_ind-------->|
* |<-------ccu_data_ind---------|
* |--------pcu_data_ind-------->| (ER_UL_CHMOD_VOID)
* |<-------ccu_sync_ind---------|
* |--------pcu_data_ind-------->|
* |<-------ccu_data_ind---------|
*
* It also should be mentioned that due to link latency, there will naturally be a gap between the PCU local PSEQ and
* the PSEQ reported by the CCU. This information is important since it must be used to compensate the GSM frame
* numbers.
*
* The procedure is very similar to what is described in US Patent No. 5,978,368 from Nov.2, 1999
*
* Usage of Timing Adjustment (TAV) parameter
* ==========================================
* The time adjustment is controlled by the CCU. The TAV value received in TRAU frames that originate from the CCU is
* the ordered timing adjustment. The TAV value in TRAU frames that originate from the PCU is the acknowledged time
* adjustment. When a timing adjustment is requested by the CCU, the PCU acknowledges it by sending the requested
* value back. The timing adjustment is performed immediately within the same frame by appending or removing bits
* at the end. This delays or advances the timing of the subsequent frame.
*
* The procedure is very similar to the one described in: GSM 08.60, section 4.6.1.2
*
*
* Usable coding schemes in uplink
* ===============================
* To understand which coding schemes are usable one must understand that the first CCU implementation for Ericsson
* RBS only supported CS1 and CS2 on 16K I.460 subslots. CS1 and CS2 were not supported due to the bandwidth limitation
* of the 16k subslots. In order to support higher bandwidth, in particular EDGE, a new CCU implementation was
* introduced. This newer implementation uses full 64K E1 timeslots and has full EDGE support MCS1-MCS9.
*
* Interestingly though, the newer CCU implementation seems to lack support for CS3-CS4. At least it was not possible
* To receive any CS3 or CS4 blocks from the CCU, while CS1 and CS2 work fine. In case the PCU is instructed to use
* CS3 or CS4 in downlink nothing is received. Since the CCU also demodulates noise and even sends the demodulation
* results back to the PCU there should have been at least some invalid CS3 and CS4 blocks in the demodulation results
* from time to time but also here no CS3 or CS4 blocks were observed. This leads to the vague assumption that the GPRS
* part of the CCU presumably never got updated and only EDGE support was added.
*
* It was also discovered that CS1 and CS2 only appear when the CCU is instructed to receive GMSK only
* (ER_UL_CHMOD_NB_GMSK). When the CCU is instructed to receive GMSK and PSK (ER_UL_CHMOD_NB_UNKN) CS2 does not appear.
* EGPRS related blocks (CS_OR_HDR_HDR1-3) appear in both situations. Since CS1 also plays a role in EGPRS it might be
* that the CCU is filtering non EDGE related blocks when ER_UL_CHMOD_NB_UNKN is used.
*
* The observations above were made with an RRUS 02 B3
*/