diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gprs_coding_scheme.h | 8 | ||||
-rw-r--r-- | src/pcu_main.cpp | 6 | ||||
-rw-r--r-- | src/pcu_vty.c | 24 | ||||
-rw-r--r-- | src/rlc.cpp | 31 | ||||
-rw-r--r-- | src/rlc.h | 7 | ||||
-rw-r--r-- | src/tbf.h | 5 | ||||
-rw-r--r-- | src/tbf_dl.cpp | 216 |
7 files changed, 250 insertions, 47 deletions
diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h index 60a8e79a..3b153724 100644 --- a/src/gprs_coding_scheme.h +++ b/src/gprs_coding_scheme.h @@ -113,7 +113,8 @@ public: static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, - const GprsCodingScheme retx_mcs); + const GprsCodingScheme retx_mcs, + const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; @@ -232,8 +233,9 @@ inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b) } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, - const GprsCodingScheme demanded_mcs) + const GprsCodingScheme demanded_mcs, + const unsigned arq_type) { - return egprs_mcs_retx_tbl[EGPRS_ARQ2][mcs.to_num() - 1] + return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; } diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 2d86cda5..e34d534d 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -210,6 +210,12 @@ int main(int argc, char *argv[]) bts->dl_tbf_idle_msec = 2000; bts->llc_idle_ack_csec = 10; + /* + * By default resegmentation is supported in DL + * can also be configured through VTY + */ + bts->dl_arq_type = EGPRS_ARQ1; + msgb_set_talloc_ctx(tall_pcu_ctx); osmo_init_logging(&gprs_log_info); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index ef48027e..535d512b 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -129,6 +129,10 @@ static int config_write_pcu(struct vty *vty) vty_out(vty, " window-size %d %d%s", bts->ws_base, bts->ws_pdch, VTY_NEWLINE); + if (bts->dl_arq_type) + vty_out(vty, " egprs dl arq-type arq2%s", + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -474,6 +478,25 @@ DEFUN(cfg_pcu_no_mcs_max, return CMD_SUCCESS; } +#define DL_STR "downlink specific configuration\n" + +DEFUN(cfg_pcu_dl_arq_type, + cfg_pcu_dl_arq_cmd, + "egprs dl arq-type (spb|arq2)", + EGPRS_STR DL_STR "ARQ options\n" + "enable SPB(ARQ1) support\n" + "enable ARQ2 support") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + if (!strcmp(argv[0], "arq2")) + bts->dl_arq_type = 1; + else + bts->dl_arq_type = 0; + + return CMD_SUCCESS; +} + DEFUN(cfg_pcu_window_size, cfg_pcu_window_size_cmd, "window-size <0-1024> [<0-256>]", @@ -948,6 +971,7 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd); install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_cmd); + install_element(PCU_NODE, &cfg_pcu_dl_arq_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_cmd); install_element(PCU_NODE, &cfg_pcu_mcs_max_cmd); install_element(PCU_NODE, &cfg_pcu_no_mcs_max_cmd); diff --git a/src/rlc.cpp b/src/rlc.cpp index 6770043f..e69d1fce 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -285,7 +285,8 @@ bool gprs_rlc_ul_window::invalidate_bsn(const uint16_t bsn) } static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding, unsigned int header_bits) + GprsCodingScheme cs, bool with_padding, unsigned int header_bits, + const unsigned int spb) { unsigned int i; unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0; @@ -300,7 +301,7 @@ static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, for (i = 0; i < rlc->num_data_blocks; i++) { gprs_rlc_data_block_info_init(&rlc->block_info[i], cs, - with_padding); + with_padding, spb); rlc->data_offs_bits[i] = header_bits + padding_bits + @@ -310,21 +311,25 @@ static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc, } void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsDL()); + cs.numDataHeaderBitsDL(), spb); } void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding) { + /* + * last parameter is sent as 0 since common function used + * for both DL and UL + */ return gprs_rlc_data_header_init(rlc, cs, with_padding, - cs.numDataHeaderBitsUL()); + cs.numDataHeaderBitsUL(), 0); } void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding) + GprsCodingScheme cs, bool with_padding, const unsigned int spb) { unsigned int data_len = cs.maxDataBlockBytes(); if (with_padding) @@ -336,7 +341,7 @@ void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, rdbi->e = 1; rdbi->cv = 15; rdbi->pi = 0; - rdbi->spb = 0; + rdbi->spb = spb; } unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, @@ -411,8 +416,18 @@ void gprs_rlc_mcs_cps_decode(unsigned int cps, enum egprs_puncturing_values gprs_get_punct_scheme( enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current) + const GprsCodingScheme &cs_current, + const enum egprs_rlcmac_dl_spb spb) { + + /* + * 10.4.8b of TS 44.060 + * If it is second segment of the block + * dont change the puncturing scheme + */ + if (spb == EGPRS_RLCMAC_DL_SEC_SEG) + return punct; + /* TS 44.060 9.3.2.1.1 */ if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) && (GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) { @@ -213,18 +213,19 @@ struct gprs_rlc_data { }; void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc, GprsCodingScheme cs, bool with_padding); void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi, - GprsCodingScheme cs, bool with_padding); + GprsCodingScheme cs, bool with_padding, const unsigned int spb); unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values punct, enum egprs_puncturing_values punct2, int with_padding); void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs, int *punct, int *punct2, int *with_padding); enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values punct, const GprsCodingScheme &cs, - const GprsCodingScheme &cs_current_trans); + const GprsCodingScheme &cs_current_trans, + const enum egprs_rlcmac_dl_spb spb); void gprs_update_punct_scheme(enum egprs_puncturing_values *punct, const GprsCodingScheme &cs); /* @@ -421,6 +421,11 @@ protected: int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res); void schedule_next_frame(); + enum egprs_rlc_dl_reseg_bsn_state egprs_dl_get_data + (int bsn, uint8_t **block_data); + unsigned int get_egprs_dl_spb_status(int bsn); + enum egprs_rlcmac_dl_spb get_egprs_dl_spb(int bsn); + struct osmo_timer_list m_llc_timer; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 07a747a4..a24cc21b 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -375,21 +375,28 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn, return -1; if (is_egprs_enabled()) { + /* Table 8.1.1.2 and Table 8.1.1.1 of 44.060 */ m_rlc.block(bsn)->cs_current_trans = - GprsCodingScheme::get_retx_mcs( - m_rlc.block(bsn)->cs_last, ms()->current_cs_dl()); + GprsCodingScheme::get_retx_mcs( + m_rlc.block(bsn)->cs_init, + ms()->current_cs_dl(), + bts->bts_data()->dl_arq_type); LOGP(DRLCMACDL, LOGL_DEBUG, - "- current_cs_dl(%d) demanded_mcs(%d) cs_trans(%d)\n", - m_rlc.block(bsn)->cs_last.to_num(), - ms()->current_cs_dl().to_num(), - m_rlc.block(bsn)->cs_current_trans.to_num()); + "- initial_cs_dl(%d) last_mcs(%d)" + " demanded_mcs(%d) cs_trans(%d)" + " arq_type(%d) bsn(%d)\n", + m_rlc.block(bsn)->cs_init.to_num(), + m_rlc.block(bsn)->cs_last.to_num(), + ms()->current_cs_dl().to_num(), + m_rlc.block(bsn)->cs_current_trans.to_num(), + bts->bts_data()->dl_arq_type, bsn); /* TODO: Need to remove this check when MCS-8 -> MCS-6 * transistion is handled. * Refer commit be881c028fc4da00c4046ecd9296727975c206a3 */ - if (m_rlc.block(bsn)->cs_last == GprsCodingScheme::MCS8) + if (m_rlc.block(bsn)->cs_init == GprsCodingScheme::MCS8) m_rlc.block(bsn)->cs_current_trans = GprsCodingScheme::MCS8; } else @@ -523,6 +530,11 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, GprsCodingScheme cs) data = rlc_data->prepare(block_data_len); rlc_data->cs_last = cs; rlc_data->cs_current_trans = cs; + + /* Initialise the variable related to DL SPB */ + rlc_data->spb_status.block_status_dl = EGPRS_RESEG_DL_DEFAULT; + rlc_data->cs_init = cs; + rlc_data->len = block_data_len; rdbi = &(rlc_data->block_info); @@ -616,7 +628,8 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( unsigned num_bsns; enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)]; bool need_padding = false; - + enum egprs_rlcmac_dl_spb spb = EGPRS_RLCMAC_DL_NO_RETX; + unsigned int spb_status = get_egprs_dl_spb_status(index); /* * TODO: This is an experimental work-around to put 2 BSN into * MSC-7 to MCS-9 encoded messages. It just sends the same BSN @@ -626,6 +639,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( * the current limit. */ cs = m_rlc.block(index)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init; bsns[0] = index; num_bsns = 1; @@ -634,7 +648,17 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( num_bsns += 1; } - if (num_bsns == 1) { + /* + * if the intial mcs is 8 and retransmission mcs is either 6 or 3 + * we have to include the padding of 6 octets in first segment + */ + if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) && + (GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 || + GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) { + if (spb_status == EGPRS_RESEG_DL_DEFAULT || + spb_status == EGPRS_RESEG_SECOND_SEG_SENT) + need_padding = true; + } else if (num_bsns == 1) { /* TODO: remove the conditional when MCS-6 padding isn't * failing to be decoded by MEs anymore */ /* TODO: support of MCS-8 -> MCS-6 transition should be @@ -646,7 +670,14 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( cs.decToSingleBlock(&need_padding); } - gprs_rlc_data_info_init_dl(&rlc, cs, need_padding); + spb = get_egprs_dl_spb(index); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d" + "(BSN1 %d BSN2 %d)\n", + need_padding, + spb_status, spb, index, index2); + + gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb); rlc.usf = 7; /* will be set at scheduler */ rlc.pr = 0; /* FIXME: power reduction */ @@ -665,10 +696,9 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( data_block_idx++) { int bsn; - GprsCodingScheme cs_enc; uint8_t *block_data; gprs_rlc_data_block_info *rdbi, *block_info; - enum egprs_puncturing_values punct_scheme; + enum egprs_rlc_dl_reseg_bsn_state reseg_status; /* Check if there are more blocks than BSNs */ if (data_block_idx < num_bsns) @@ -676,38 +706,43 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( else bsn = bsns[0]; - cs_enc = m_rlc.block(bsn)->cs_current_trans; - /* get data and header from current block */ - block_data = m_rlc.block(bsn)->block; - /* Get current puncturing scheme from block */ - punct_scheme = gprs_get_punct_scheme( + + m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme( m_rlc.block(bsn)->next_ps, - m_rlc.block(bsn)->cs_last, cs); + m_rlc.block(bsn)->cs_last, cs, spb); if (cs.isEgprs()) { - OSMO_ASSERT(punct_scheme >= EGPRS_PS_1); - OSMO_ASSERT(punct_scheme <= EGPRS_PS_3); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1); + OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3); } - punct[data_block_idx] = punct_scheme; + punct[data_block_idx] = m_rlc.block(bsn)->next_ps; rdbi = &rlc.block_info[data_block_idx]; block_info = &m_rlc.block(bsn)->block_info; - if(rdbi->data_len != m_rlc.block(bsn)->len) { - LOGP(DRLCMACDL, LOGL_ERROR, - "ERROR: Expected len = %d for %s instead of " - "%d in data unit %d (BSN %d, %s)\n", - rdbi->data_len, cs.name(), m_rlc.block(bsn)->len, - data_block_idx, bsn, cs_enc.name()); - OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len); - } + /* + * get data and header from current block + * function returns the reseg status + */ + reseg_status = egprs_dl_get_data(bsn, &block_data); + m_rlc.block(bsn)->spb_status.block_status_dl = reseg_status; - /* TODO: Need to handle 2 same bsns - * in header type 1 + /* + * If it is first segment of the split block set the state of + * bsn to nacked. If it is the first segment dont update the + * next ps value of bsn. since next segment also needs same cps */ - gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, - cs); + if (spb == EGPRS_RLCMAC_DL_FIRST_SEG) + m_window.m_v_b.mark_nacked(bsn); + else { + /* + * TODO: Need to handle 2 same bsns + * in header type 1 + */ + gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps, + cs); + } m_rlc.block(bsn)->cs_last = cs; rdbi->e = block_info->e; @@ -1169,3 +1204,118 @@ bool gprs_rlcmac_dl_tbf::keep_open(unsigned fn) const keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec); return frames_since_last_drain(fn) <= keep_time_frames; } + +/* + * This function returns the pointer to data which needs + * to be copied. Also updates the status of the block related to + * Split block handling in the RLC/MAC block. + */ +enum egprs_rlc_dl_reseg_bsn_state + gprs_rlcmac_dl_tbf::egprs_dl_get_data(int bsn, uint8_t **block_data) +{ + gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state *block_status_dl = + &rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + *block_data = &rlc_data->block[0]; + + /* + * Table 10.3a.0.1 of 44.060 + * MCS6,9: second segment starts at 74/2 = 37 + * MCS5,7: second segment starts at 56/2 = 28 + * MCS8: second segment starts at 31 + * MCS4: second segment starts at 44/2 = 22 + */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + if (*block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + switch (GprsCodingScheme::Scheme(cs_init)) { + case GprsCodingScheme::MCS6 : + case GprsCodingScheme::MCS9 : + *block_data = &rlc_data->block[37]; + break; + case GprsCodingScheme::MCS7 : + case GprsCodingScheme::MCS5 : + *block_data = &rlc_data->block[28]; + break; + case GprsCodingScheme::MCS8 : + *block_data = &rlc_data->block[31]; + break; + case GprsCodingScheme::MCS4 : + *block_data = &rlc_data->block[22]; + break; + default: + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "--%s hit invalid condition. headerType(%d) " + " blockstatus(%d) cs(%s) PLEASE FIX!\n", name(), + cs_current_trans.headerTypeData(), + *block_status_dl, cs_init.name()); + break; + + } + return EGPRS_RESEG_SECOND_SEG_SENT; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RESEG_FIRST_SEG_SENT; + } + } + return EGPRS_RESEG_DL_DEFAULT; +} + +/* + * This function returns the status of split block + * for RLC/MAC block. + */ +unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(const int bsn) +{ + const gprs_rlc_data *rlc_data = m_rlc.block(bsn); + + return rlc_data->spb_status.block_status_dl; +} + +/* + * This function returns the spb value to be sent OTA + * for RLC/MAC block. + */ +enum egprs_rlcmac_dl_spb gprs_rlcmac_dl_tbf::get_egprs_dl_spb(const int bsn) +{ + struct gprs_rlc_data *rlc_data = m_rlc.block(bsn); + egprs_rlc_dl_reseg_bsn_state block_status_dl = + rlc_data->spb_status.block_status_dl; + + GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans; + GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init; + + /* Table 10.4.8b.1 of 44.060 */ + if (cs_current_trans.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) { + /* + * if we are sending the second segment the spb should be 3 + * other wise it should be 2 + */ + if (block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) { + return EGPRS_RLCMAC_DL_SEC_SEG; + } else if ((cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) || + (cs_init.headerTypeData() == + GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } else if ((GprsCodingScheme::Scheme(cs_init) == + GprsCodingScheme::MCS4) && + (GprsCodingScheme::Scheme(cs_current_trans) == + GprsCodingScheme::MCS1)) { + return EGPRS_RLCMAC_DL_FIRST_SEG; + } + } + /* Non SPB cases 0 is reurned */ + return EGPRS_RLCMAC_DL_NO_RETX; +} |