diff --git a/src/encoding.cpp b/src/encoding.cpp index e3e1245e..a7d7b169 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -711,10 +711,14 @@ unsigned Encoding::write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc, uint8_t *data) { + struct gprs_rlc_dl_header_egprs_1 *egprs1; + struct gprs_rlc_dl_header_egprs_2 *egprs2; struct gprs_rlc_dl_header_egprs_3 *egprs3; struct rlc_dl_header *gprs; unsigned int e_fbi_header; GprsCodingScheme cs = rlc->cs; + unsigned int offs; + unsigned int bsn_delta; switch(cs.headerTypeData()) { case GprsCodingScheme::HEADER_GPRS_DATA: @@ -733,6 +737,65 @@ int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc, gprs->bsn = rlc->block_info[0].bsn; break; + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1: + egprs1 = static_cast + ((void *)data); + + egprs1->usf = rlc->usf; + egprs1->es_p = rlc->es_p; + egprs1->rrbp = rlc->rrbp; + egprs1->tfi_a = rlc->tfi >> 0; /* 1 bit LSB */ + egprs1->tfi_b = rlc->tfi >> 1; /* 4 bits */ + egprs1->pr = rlc->pr; + egprs1->cps = rlc->cps; + + egprs1->bsn1_a = rlc->block_info[0].bsn >> 0; /* 2 bits LSB */ + egprs1->bsn1_b = rlc->block_info[0].bsn >> 2; /* 8 bits */ + egprs1->bsn1_c = rlc->block_info[0].bsn >> 10; /* 1 bit */ + + bsn_delta = (rlc->block_info[1].bsn - rlc->block_info[0].bsn) & + (RLC_EGPRS_SNS - 1); + + egprs1->bsn2_a = bsn_delta >> 0; /* 7 bits LSB */ + egprs1->bsn2_b = bsn_delta >> 7; /* 3 bits */ + + /* first FBI/E header */ + e_fbi_header = rlc->block_info[0].e ? 0x01 : 0; + e_fbi_header |= rlc->block_info[0].cv == 0 ? 0x02 : 0; /* FBI */ + e_fbi_header <<= 0; + data[5] = (data[5] & 0b11111100) | e_fbi_header; + + /* second FBI/E header */ + e_fbi_header = rlc->block_info[1].e ? 0x01 : 0; + e_fbi_header |= rlc->block_info[1].cv == 0 ? 0x02 : 0; /* FBI */ + offs = rlc->data_offs_bits[1] / 8; + OSMO_ASSERT(rlc->data_offs_bits[1] % 8 == 4); + e_fbi_header <<= 2; + data[offs] = (data[offs] & 0b11110011) | e_fbi_header; + break; + + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2: + egprs2 = static_cast + ((void *)data); + + egprs2->usf = rlc->usf; + egprs2->es_p = rlc->es_p; + egprs2->rrbp = rlc->rrbp; + egprs2->tfi_a = rlc->tfi >> 0; /* 1 bit LSB */ + egprs2->tfi_b = rlc->tfi >> 1; /* 4 bits */ + egprs2->pr = rlc->pr; + egprs2->cps = rlc->cps; + + egprs2->bsn1_a = rlc->block_info[0].bsn >> 0; /* 2 bits LSB */ + egprs2->bsn1_b = rlc->block_info[0].bsn >> 2; /* 8 bits */ + egprs2->bsn1_c = rlc->block_info[0].bsn >> 10; /* 1 bit */ + + e_fbi_header = rlc->block_info[0].e ? 0x01 : 0; + e_fbi_header |= rlc->block_info[0].cv == 0 ? 0x02 : 0; /* FBI */ + e_fbi_header <<= 4; + data[3] = (data[3] & 0b11001111) | e_fbi_header; + break; + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3: egprs3 = static_cast ((void *)data); @@ -758,10 +821,6 @@ int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc, data[4] = (data[4] & 0b11111110) | (e_fbi_header >> 8); break; - case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1: - case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2: - /* TODO: Support both header types */ - /* fall through */ default: LOGP(DRLCMACDL, LOGL_ERROR, "Encoding of uplink %s data blocks not yet supported.\n", diff --git a/src/rlc.cpp b/src/rlc.cpp index e4a9563a..efe42614 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -327,7 +327,8 @@ void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, rdbi->spb = 0; } -unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int with_padding) +unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2, + int with_padding) { switch (GprsCodingScheme::Scheme(cs)) { case GprsCodingScheme::MCS1: return 0b1011 + punct % 2; @@ -335,7 +336,12 @@ unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int with_padding) case GprsCodingScheme::MCS3: return (with_padding ? 0b0110 : 0b0011) + punct % 3; case GprsCodingScheme::MCS4: return 0b0000 + punct % 3; - /* TODO: Add missing MCS */ + case GprsCodingScheme::MCS5: return 0b100 + punct % 2; + case GprsCodingScheme::MCS6: return (with_padding ? 0b010 : 0b000) + + punct % 2; + case GprsCodingScheme::MCS7: return 0b10100 + 3 * (punct % 3) + punct2 % 3; + case GprsCodingScheme::MCS8: return 0b01011 + 3 * (punct % 3) + punct2 % 3; + case GprsCodingScheme::MCS9: return 0b00000 + 4 * (punct % 3) + punct2 % 3; default: ; } diff --git a/src/rlc.h b/src/rlc.h index 3a7f1a1a..8c3a4124 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -106,7 +106,8 @@ void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs); -unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int with_padding); +unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2, + int with_padding); /* * I hold the currently transferred blocks and will provide @@ -300,6 +301,35 @@ struct gprs_rlc_ul_header_egprs_3 { dummy:1; } __attribute__ ((packed)); +struct gprs_rlc_dl_header_egprs_1 { + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_a:1; + uint8_t tfi_b:4, + pr:2, + bsn1_a:2; + uint8_t bsn1_b:8; + uint8_t bsn1_c:1, + bsn2_a:7; + uint8_t bsn2_b:3, + cps:5; +} __attribute__ ((packed)); + +struct gprs_rlc_dl_header_egprs_2 { + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_a:1; + uint8_t tfi_b:4, + pr:2, + bsn1_a:2; + uint8_t bsn1_b:8; + uint8_t bsn1_c:1, + cps:3, + dummy:4; +} __attribute__ ((packed)); + struct gprs_rlc_dl_header_egprs_3 { uint8_t usf:3, es_p:2, diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 03f0cc4d..e567f57d 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -545,7 +545,8 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ rlc.tfi = m_tfi; /* TFI */ - rlc.cps = gprs_rlc_mcs_cps(cs, 0, 0); + /* TODO: Use real puncturing values */ + rlc.cps = gprs_rlc_mcs_cps(cs, 0, 0, 0); rlc.block_info[data_block_idx] = m_rlc.block(index)->block_info; rdbi = &rlc.block_info[data_block_idx];