aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gprs_coding_scheme.h8
-rw-r--r--src/pcu_main.cpp6
-rw-r--r--src/pcu_vty.c24
-rw-r--r--src/rlc.cpp31
-rw-r--r--src/rlc.h7
-rw-r--r--src/tbf.h5
-rw-r--r--src/tbf_dl.cpp216
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)) {
diff --git a/src/rlc.h b/src/rlc.h
index b1a1fbad..b6934183 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -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);
/*
diff --git a/src/tbf.h b/src/tbf.h
index 1bd78782..2a1bfe83 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -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;
+}