rlc/tbf: Move v_b into DL window
Move functions resend_needed(), mark_for_resend(), update(), move_window(), state(), count_unacked() out of v_b directly into the UL window and provide a function get_state in v_b to access the v_b elements.
This commit is contained in:
parent
55844795be
commit
146514e180
51
src/rlc.cpp
51
src/rlc.cpp
|
@ -46,24 +46,24 @@ void gprs_rlc_v_b::reset()
|
||||||
mark_invalid(i);
|
mark_invalid(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gprs_rlc_v_b::resend_needed(const gprs_rlc_dl_window &w)
|
int gprs_rlc_dl_window::resend_needed()
|
||||||
{
|
{
|
||||||
for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
|
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||||
if (is_nacked(bsn) || is_resend(bsn))
|
if (m_v_b.is_nacked(bsn) || m_v_b.is_resend(bsn))
|
||||||
return bsn;
|
return bsn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gprs_rlc_v_b::mark_for_resend(const gprs_rlc_dl_window &w)
|
int gprs_rlc_dl_window::mark_for_resend()
|
||||||
{
|
{
|
||||||
int resend = 0;
|
int resend = 0;
|
||||||
|
|
||||||
for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
|
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||||
if (is_unacked(bsn)) {
|
if (m_v_b.is_unacked(bsn)) {
|
||||||
/* mark to be re-send */
|
/* mark to be re-send */
|
||||||
mark_resend(bsn);
|
m_v_b.mark_resend(bsn);
|
||||||
resend += 1;
|
resend += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@ int gprs_rlc_v_b::mark_for_resend(const gprs_rlc_dl_window &w)
|
||||||
return resend;
|
return resend;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gprs_rlc_v_b::count_unacked(const gprs_rlc_dl_window &w)
|
int gprs_rlc_dl_window::count_unacked()
|
||||||
{
|
{
|
||||||
uint16_t unacked = 0;
|
uint16_t unacked = 0;
|
||||||
uint16_t bsn;
|
uint16_t bsn;
|
||||||
|
|
||||||
for (bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
|
for (bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||||
if (!is_acked(bsn))
|
if (!m_v_b.is_acked(bsn))
|
||||||
unacked += 1;
|
unacked += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,40 +89,39 @@ static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn, uint16_t mod_sns)
|
||||||
return (ssn - 1 - bitnum) & mod_sns;
|
return (ssn - 1 - bitnum) & mod_sns;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gprs_rlc_v_b::update(BTS *bts, char *show_rbb, uint8_t ssn,
|
void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint8_t ssn,
|
||||||
const gprs_rlc_dl_window &w,
|
|
||||||
uint16_t *lost, uint16_t *received)
|
uint16_t *lost, uint16_t *received)
|
||||||
{
|
{
|
||||||
/* SSN - 1 is in range V(A)..V(S)-1 */
|
/* SSN - 1 is in range V(A)..V(S)-1 */
|
||||||
for (int bitpos = 0; bitpos < w.ws(); bitpos++) {
|
for (int bitpos = 0; bitpos < ws(); bitpos++) {
|
||||||
uint16_t bsn = bitnum_to_bsn(bitpos, ssn, w.mod_sns());
|
uint16_t bsn = bitnum_to_bsn(bitpos, ssn, mod_sns());
|
||||||
|
|
||||||
if (bsn == ((w.v_a() - 1) & w.mod_sns()))
|
if (bsn == ((v_a() - 1) & mod_sns()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (show_rbb[w.ws() - 1 - bitpos] == 'R') {
|
if (show_rbb[ws() - 1 - bitpos] == 'R') {
|
||||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
|
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
|
||||||
if (!is_acked(bsn))
|
if (!m_v_b.is_acked(bsn))
|
||||||
*received += 1;
|
*received += 1;
|
||||||
mark_acked(bsn);
|
m_v_b.mark_acked(bsn);
|
||||||
} else {
|
} else {
|
||||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
|
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
|
||||||
mark_nacked(bsn);
|
m_v_b.mark_nacked(bsn);
|
||||||
bts->rlc_nacked();
|
bts->rlc_nacked();
|
||||||
*lost += 1;
|
*lost += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int gprs_rlc_v_b::move_window(const gprs_rlc_dl_window &w)
|
int gprs_rlc_dl_window::move_window()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint16_t bsn;
|
uint16_t bsn;
|
||||||
int moved = 0;
|
int moved = 0;
|
||||||
|
|
||||||
for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
|
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = (bsn + 1) & mod_sns()) {
|
||||||
if (is_acked(bsn)) {
|
if (m_v_b.is_acked(bsn)) {
|
||||||
mark_invalid(bsn);
|
m_v_b.mark_invalid(bsn);
|
||||||
moved += 1;
|
moved += 1;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
@ -131,14 +130,14 @@ int gprs_rlc_v_b::move_window(const gprs_rlc_dl_window &w)
|
||||||
return moved;
|
return moved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gprs_rlc_v_b::state(char *show_v_b, const gprs_rlc_dl_window &w)
|
void gprs_rlc_dl_window::state(char *show_v_b)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint16_t bsn;
|
uint16_t bsn;
|
||||||
|
|
||||||
for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
|
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = (bsn + 1) & mod_sns()) {
|
||||||
uint16_t index = bsn & mod_sns_half();
|
uint16_t index = bsn & mod_sns_half();
|
||||||
show_v_b[i] = m_v_b[index];
|
show_v_b[i] = m_v_b.get_state(index);
|
||||||
if (show_v_b[i] == 0)
|
if (show_v_b[i] == 0)
|
||||||
show_v_b[i] = ' ';
|
show_v_b[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
84
src/rlc.h
84
src/rlc.h
|
@ -53,6 +53,36 @@ struct gprs_rlc {
|
||||||
gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
|
gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: for GPRS/EDGE maybe make sns a template parameter
|
||||||
|
* so we create specialized versions...
|
||||||
|
*/
|
||||||
|
struct gprs_rlc_v_b {
|
||||||
|
/* Check for an individual frame */
|
||||||
|
bool is_unacked(int bsn) const;
|
||||||
|
bool is_nacked(int bsn) const;
|
||||||
|
bool is_acked(int bsn) const;
|
||||||
|
bool is_resend(int bsn) const;
|
||||||
|
bool is_invalid(int bsn) const;
|
||||||
|
char get_state(int bsn) const;
|
||||||
|
|
||||||
|
/* Mark a RLC frame for something */
|
||||||
|
void mark_unacked(int bsn);
|
||||||
|
void mark_nacked(int bsn);
|
||||||
|
void mark_acked(int bsn);
|
||||||
|
void mark_resend(int bsn);
|
||||||
|
void mark_invalid(int bsn);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_state(int bsn, const char state) const;
|
||||||
|
void mark(int bsn, const char state);
|
||||||
|
|
||||||
|
char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: The UL/DL code could/should share a baseclass but
|
* TODO: The UL/DL code could/should share a baseclass but
|
||||||
|
@ -77,8 +107,19 @@ struct gprs_rlc_dl_window {
|
||||||
const uint16_t v_a() const;
|
const uint16_t v_a() const;
|
||||||
const int16_t distance() const;
|
const int16_t distance() const;
|
||||||
|
|
||||||
|
/* Methods to manage reception */
|
||||||
|
int resend_needed();
|
||||||
|
int mark_for_resend();
|
||||||
|
void update(BTS *bts, char *show_rbb, uint8_t ssn,
|
||||||
|
uint16_t *lost, uint16_t *received);
|
||||||
|
int move_window();
|
||||||
|
void state(char *show_rbb);
|
||||||
|
int count_unacked();
|
||||||
|
|
||||||
uint16_t m_v_s; /* send state */
|
uint16_t m_v_s; /* send state */
|
||||||
uint16_t m_v_a; /* ack state */
|
uint16_t m_v_a; /* ack state */
|
||||||
|
|
||||||
|
gprs_rlc_v_b m_v_b;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gprs_rlc_v_n {
|
struct gprs_rlc_v_n {
|
||||||
|
@ -123,43 +164,6 @@ struct gprs_rlc_ul_window {
|
||||||
gprs_rlc_v_n m_v_n;
|
gprs_rlc_v_n m_v_n;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: for GPRS/EDGE maybe make sns a template parameter
|
|
||||||
* so we create specialized versions...
|
|
||||||
*/
|
|
||||||
struct gprs_rlc_v_b {
|
|
||||||
int resend_needed(const gprs_rlc_dl_window& window);
|
|
||||||
int mark_for_resend(const gprs_rlc_dl_window& window);
|
|
||||||
void update(BTS *bts, char *show_rbb, uint8_t ssn,
|
|
||||||
const gprs_rlc_dl_window& window,
|
|
||||||
uint16_t *lost, uint16_t *received);
|
|
||||||
int move_window(const gprs_rlc_dl_window& window);
|
|
||||||
void state(char *show_rbb, const gprs_rlc_dl_window& window);
|
|
||||||
int count_unacked(const gprs_rlc_dl_window& window);
|
|
||||||
|
|
||||||
/* Check for an individual frame */
|
|
||||||
bool is_unacked(int bsn) const;
|
|
||||||
bool is_nacked(int bsn) const;
|
|
||||||
bool is_acked(int bsn) const;
|
|
||||||
bool is_resend(int bsn) const;
|
|
||||||
bool is_invalid(int bsn) const;
|
|
||||||
|
|
||||||
/* Mark a RLC frame for something */
|
|
||||||
void mark_unacked(int bsn);
|
|
||||||
void mark_nacked(int bsn);
|
|
||||||
void mark_acked(int bsn);
|
|
||||||
void mark_resend(int bsn);
|
|
||||||
void mark_invalid(int bsn);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_state(int bsn, const char state) const;
|
|
||||||
void mark(int bsn, const char state);
|
|
||||||
|
|
||||||
char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/* TS 04.60 10.2.2 */
|
/* TS 04.60 10.2.2 */
|
||||||
struct rlc_ul_header {
|
struct rlc_ul_header {
|
||||||
|
@ -229,6 +233,11 @@ inline bool gprs_rlc_v_b::is_invalid(int bsn) const
|
||||||
return is_state(bsn, 'I');
|
return is_state(bsn, 'I');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline char gprs_rlc_v_b::get_state(int bsn) const
|
||||||
|
{
|
||||||
|
return m_v_b[bsn & mod_sns_half()];
|
||||||
|
}
|
||||||
|
|
||||||
inline void gprs_rlc_v_b::mark_resend(int bsn)
|
inline void gprs_rlc_v_b::mark_resend(int bsn)
|
||||||
{
|
{
|
||||||
return mark(bsn, 'X');
|
return mark(bsn, 'X');
|
||||||
|
@ -254,7 +263,6 @@ inline void gprs_rlc_v_b::mark_invalid(int bsn)
|
||||||
return mark(bsn, 'I');
|
return mark(bsn, 'I');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const uint16_t gprs_rlc_dl_window::sns() const
|
inline const uint16_t gprs_rlc_dl_window::sns() const
|
||||||
{
|
{
|
||||||
return RLC_MAX_SNS;
|
return RLC_MAX_SNS;
|
||||||
|
|
18
src/tbf.cpp
18
src/tbf.cpp
|
@ -834,11 +834,11 @@ struct msgb *gprs_rlcmac_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts)
|
||||||
|
|
||||||
do_resend:
|
do_resend:
|
||||||
/* check if there is a block with negative acknowledgement */
|
/* check if there is a block with negative acknowledgement */
|
||||||
int resend_bsn = dir.dl.v_b.resend_needed(dir.dl.window);
|
int resend_bsn = dir.dl.window.resend_needed();
|
||||||
if (resend_bsn >= 0) {
|
if (resend_bsn >= 0) {
|
||||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
|
LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
|
||||||
/* re-send block with negative aknowlegement */
|
/* re-send block with negative aknowlegement */
|
||||||
dir.dl.v_b.mark_unacked(resend_bsn);
|
dir.dl.window.m_v_b.mark_unacked(resend_bsn);
|
||||||
bts->rlc_resent();
|
bts->rlc_resent();
|
||||||
return create_dl_acked_block(fn, ts, resend_bsn, false);
|
return create_dl_acked_block(fn, ts, resend_bsn, false);
|
||||||
}
|
}
|
||||||
|
@ -873,7 +873,7 @@ do_resend:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cycle through all unacked blocks */
|
/* cycle through all unacked blocks */
|
||||||
int resend = dir.dl.v_b.mark_for_resend(dir.dl.window);
|
int resend = dir.dl.window.mark_for_resend();
|
||||||
|
|
||||||
/* At this point there should be at least one unacked block
|
/* At this point there should be at least one unacked block
|
||||||
* to be resent. If not, this is an software error. */
|
* to be resent. If not, this is an software error. */
|
||||||
|
@ -1052,7 +1052,7 @@ struct msgb *gprs_rlcmac_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts
|
||||||
#warning "move this up?"
|
#warning "move this up?"
|
||||||
rlc_data->len = block_length;
|
rlc_data->len = block_length;
|
||||||
/* raise send state and set ack state array */
|
/* raise send state and set ack state array */
|
||||||
dir.dl.v_b.mark_unacked(bsn);
|
dir.dl.window.m_v_b.mark_unacked(bsn);
|
||||||
dir.dl.window.increment_send();
|
dir.dl.window.increment_send();
|
||||||
|
|
||||||
return create_dl_acked_block(fn, ts, bsn, first_fin_ack);
|
return create_dl_acked_block(fn, ts, bsn, first_fin_ack);
|
||||||
|
@ -1364,17 +1364,17 @@ int gprs_rlcmac_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
|
||||||
return 1; /* indicate to free TBF */
|
return 1; /* indicate to free TBF */
|
||||||
}
|
}
|
||||||
|
|
||||||
dir.dl.v_b.update(bts, show_rbb, ssn, dir.dl.window,
|
dir.dl.window.update(bts, show_rbb, ssn,
|
||||||
&lost, &received);
|
&lost, &received);
|
||||||
|
|
||||||
/* report lost and received packets */
|
/* report lost and received packets */
|
||||||
gprs_rlcmac_received_lost(this, received, lost);
|
gprs_rlcmac_received_lost(this, received, lost);
|
||||||
|
|
||||||
/* raise V(A), if possible */
|
/* raise V(A), if possible */
|
||||||
dir.dl.window.raise(dir.dl.v_b.move_window(dir.dl.window));
|
dir.dl.window.raise(dir.dl.window.move_window());
|
||||||
|
|
||||||
/* show receive state array in debug (V(A)..V(S)-1) */
|
/* show receive state array in debug (V(A)..V(S)-1) */
|
||||||
dir.dl.v_b.state(show_v_b, dir.dl.window);
|
dir.dl.window.state(show_v_b);
|
||||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
|
LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
|
||||||
"(V(S)-1=%d) A=Acked N=Nacked U=Unacked "
|
"(V(S)-1=%d) A=Acked N=Nacked U=Unacked "
|
||||||
"X=Resend-Unacked I=Invalid\n",
|
"X=Resend-Unacked I=Invalid\n",
|
||||||
|
@ -1397,7 +1397,7 @@ int gprs_rlcmac_tbf::maybe_start_new_window()
|
||||||
|
|
||||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
|
LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
|
||||||
/* range V(A)..V(S)-1 */
|
/* range V(A)..V(S)-1 */
|
||||||
received = dir.dl.v_b.count_unacked(dir.dl.window);
|
received = dir.dl.window.count_unacked();
|
||||||
|
|
||||||
/* report all outstanding packets as received */
|
/* report all outstanding packets as received */
|
||||||
gprs_rlcmac_received_lost(this, received, 0);
|
gprs_rlcmac_received_lost(this, received, 0);
|
||||||
|
@ -1721,7 +1721,7 @@ void gprs_rlcmac_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
|
||||||
|
|
||||||
/* reset rlc states */
|
/* reset rlc states */
|
||||||
memset(&dir.dl, 0, sizeof(dir.dl));
|
memset(&dir.dl, 0, sizeof(dir.dl));
|
||||||
dir.dl.v_b.reset();
|
dir.dl.window.m_v_b.reset();
|
||||||
|
|
||||||
/* keep to flags */
|
/* keep to flags */
|
||||||
state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
|
state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
|
||||||
|
|
|
@ -168,7 +168,6 @@ struct gprs_rlcmac_tbf {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
gprs_rlc_dl_window window;
|
gprs_rlc_dl_window window;
|
||||||
gprs_rlc_v_b v_b;
|
|
||||||
int32_t tx_counter; /* count all transmitted blocks */
|
int32_t tx_counter; /* count all transmitted blocks */
|
||||||
uint8_t wait_confirm; /* wait for CCCH IMM.ASS cnf */
|
uint8_t wait_confirm; /* wait for CCCH IMM.ASS cnf */
|
||||||
} dl;
|
} dl;
|
||||||
|
|
|
@ -322,9 +322,8 @@ static void test_rlc_dl_ul_basic()
|
||||||
char show_rbb[65];
|
char show_rbb[65];
|
||||||
BTS dummy_bts;
|
BTS dummy_bts;
|
||||||
gprs_rlc_dl_window dl_win = { 0, };
|
gprs_rlc_dl_window dl_win = { 0, };
|
||||||
gprs_rlc_v_b v_b;
|
|
||||||
|
|
||||||
v_b.reset();
|
dl_win.m_v_b.reset();
|
||||||
|
|
||||||
OSMO_ASSERT(dl_win.window_empty());
|
OSMO_ASSERT(dl_win.window_empty());
|
||||||
OSMO_ASSERT(!dl_win.window_stalled());
|
OSMO_ASSERT(!dl_win.window_stalled());
|
||||||
|
@ -345,7 +344,7 @@ static void test_rlc_dl_ul_basic()
|
||||||
Decoding::extract_rbb(rbb_cmp, show_rbb);
|
Decoding::extract_rbb(rbb_cmp, show_rbb);
|
||||||
printf("show_rbb: %s\n", show_rbb);
|
printf("show_rbb: %s\n", show_rbb);
|
||||||
|
|
||||||
v_b.update(&dummy_bts, show_rbb, 35, dl_win, &lost, &recv);
|
dl_win.update(&dummy_bts, show_rbb, 35, &lost, &recv);
|
||||||
OSMO_ASSERT(lost == 0);
|
OSMO_ASSERT(lost == 0);
|
||||||
OSMO_ASSERT(recv == 35);
|
OSMO_ASSERT(recv == 35);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue