Merge remote-tracking branch 'sysmocom/window-rework' into sysmocom/master
This commit is contained in:
commit
85c1ea5cb6
|
@ -382,7 +382,7 @@ void Encoding::write_packet_uplink_ack(struct gprs_rlcmac_bts *bts,
|
|||
|
||||
char rbb[65];
|
||||
|
||||
tbf->dir.ul.window.update_rbb(&tbf->dir.ul.v_n, rbb);
|
||||
tbf->dir.ul.window.update_rbb(rbb);
|
||||
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "Encoding Ack/Nack for %s "
|
||||
"(final=%d)\n", tbf_name(tbf), final);
|
||||
|
|
93
src/rlc.cpp
93
src/rlc.cpp
|
@ -46,24 +46,24 @@ void gprs_rlc_v_b::reset()
|
|||
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()) {
|
||||
if (is_nacked(bsn) || is_resend(bsn))
|
||||
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||
if (m_v_b.is_nacked(bsn) || m_v_b.is_resend(bsn))
|
||||
return bsn;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (uint16_t bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
|
||||
if (is_unacked(bsn)) {
|
||||
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||
if (m_v_b.is_unacked(bsn)) {
|
||||
/* mark to be re-send */
|
||||
mark_resend(bsn);
|
||||
m_v_b.mark_resend(bsn);
|
||||
resend += 1;
|
||||
}
|
||||
}
|
||||
|
@ -71,13 +71,13 @@ int gprs_rlc_v_b::mark_for_resend(const gprs_rlc_dl_window &w)
|
|||
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 bsn;
|
||||
|
||||
for (bsn = w.v_a(); bsn != w.v_s(); bsn = (bsn + 1) & w.mod_sns()) {
|
||||
if (!is_acked(bsn))
|
||||
for (bsn = v_a(); bsn != v_s(); bsn = (bsn + 1) & mod_sns()) {
|
||||
if (!m_v_b.is_acked(bsn))
|
||||
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;
|
||||
}
|
||||
|
||||
void gprs_rlc_v_b::update(BTS *bts, char *show_rbb, uint8_t ssn,
|
||||
const gprs_rlc_dl_window &w,
|
||||
void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint8_t ssn,
|
||||
uint16_t *lost, uint16_t *received)
|
||||
{
|
||||
/* SSN - 1 is in range V(A)..V(S)-1 */
|
||||
for (int bitpos = 0; bitpos < w.ws(); bitpos++) {
|
||||
uint16_t bsn = bitnum_to_bsn(bitpos, ssn, w.mod_sns());
|
||||
for (int bitpos = 0; bitpos < ws(); bitpos++) {
|
||||
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;
|
||||
|
||||
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);
|
||||
if (!is_acked(bsn))
|
||||
if (!m_v_b.is_acked(bsn))
|
||||
*received += 1;
|
||||
mark_acked(bsn);
|
||||
m_v_b.mark_acked(bsn);
|
||||
} else {
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
|
||||
mark_nacked(bsn);
|
||||
m_v_b.mark_nacked(bsn);
|
||||
bts->rlc_nacked();
|
||||
*lost += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int gprs_rlc_v_b::move_window(const gprs_rlc_dl_window &w)
|
||||
int gprs_rlc_dl_window::move_window()
|
||||
{
|
||||
int i;
|
||||
uint16_t bsn;
|
||||
int moved = 0;
|
||||
|
||||
for (i = 0, bsn = w.v_a(); bsn != w.v_s(); i++, bsn = (bsn + 1) & w.mod_sns()) {
|
||||
if (is_acked(bsn)) {
|
||||
mark_invalid(bsn);
|
||||
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = (bsn + 1) & mod_sns()) {
|
||||
if (m_v_b.is_acked(bsn)) {
|
||||
m_v_b.mark_invalid(bsn);
|
||||
moved += 1;
|
||||
} else
|
||||
break;
|
||||
|
@ -131,31 +130,45 @@ int gprs_rlc_v_b::move_window(const gprs_rlc_dl_window &w)
|
|||
return moved;
|
||||
}
|
||||
|
||||
void gprs_rlc_v_b::state(char *show_v_b, const gprs_rlc_dl_window &w)
|
||||
void gprs_rlc_dl_window::show_state(char *show_v_b)
|
||||
{
|
||||
int i;
|
||||
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();
|
||||
show_v_b[i] = m_v_b[index];
|
||||
if (show_v_b[i] == 0)
|
||||
show_v_b[i] = ' ';
|
||||
switch(m_v_b.get_state(index)) {
|
||||
case GPRS_RLC_DL_BSN_INVALID:
|
||||
show_v_b[i] = 'I';
|
||||
break;
|
||||
case GPRS_RLC_DL_BSN_ACKED:
|
||||
show_v_b[i] = 'A';
|
||||
break;
|
||||
case GPRS_RLC_DL_BSN_RESEND:
|
||||
show_v_b[i] = 'X';
|
||||
break;
|
||||
case GPRS_RLC_DL_BSN_NACKED:
|
||||
show_v_b[i] = 'N';
|
||||
break;
|
||||
default:
|
||||
show_v_b[i] = '?';
|
||||
}
|
||||
}
|
||||
show_v_b[i] = '\0';
|
||||
}
|
||||
|
||||
void gprs_rlc_v_n::reset()
|
||||
{
|
||||
memset(m_v_n, 0x0, sizeof(m_v_n));
|
||||
for (size_t i = 0; i < ARRAY_SIZE(m_v_n); ++i)
|
||||
m_v_n[i] = GPRS_RLC_UL_BSN_INVALID;
|
||||
}
|
||||
|
||||
/* Update the receive block bitmap */
|
||||
void gprs_rlc_ul_window::update_rbb(const gprs_rlc_v_n *v_n, char *rbb)
|
||||
void gprs_rlc_ul_window::update_rbb(char *rbb)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < ws(); i++) {
|
||||
if (v_n->is_received(ssn()-1-i))
|
||||
if (m_v_n.is_received(ssn()-1-i))
|
||||
rbb[ws()-1-i] = 'R';
|
||||
else
|
||||
rbb[ws()-1-i] = 'I';
|
||||
|
@ -163,7 +176,7 @@ void gprs_rlc_ul_window::update_rbb(const gprs_rlc_v_n *v_n, char *rbb)
|
|||
}
|
||||
|
||||
/* Raise V(R) to highest received sequence number not received. */
|
||||
void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn, gprs_rlc_v_n *v_n)
|
||||
void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn)
|
||||
{
|
||||
uint16_t offset_v_r;
|
||||
offset_v_r = (bsn + 1 - v_r()) & mod_sns();
|
||||
|
@ -171,8 +184,8 @@ void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn, gprs_rlc_v_n *v_n)
|
|||
if (offset_v_r < (sns() >> 1)) {
|
||||
while (offset_v_r--) {
|
||||
if (offset_v_r) /* all except the received block */
|
||||
v_n->mark_missing(v_r());
|
||||
raise_v_r(1);
|
||||
m_v_n.mark_missing(v_r());
|
||||
raise_v_r_to(1);
|
||||
}
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", v_r());
|
||||
}
|
||||
|
@ -182,12 +195,12 @@ void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn, gprs_rlc_v_n *v_n)
|
|||
* Raise V(Q) if possible. This is looped until there is a gap
|
||||
* (non received block) or the window is empty.
|
||||
*/
|
||||
uint16_t gprs_rlc_ul_window::raise_v_q(gprs_rlc_v_n *v_n)
|
||||
uint16_t gprs_rlc_ul_window::raise_v_q()
|
||||
{
|
||||
uint16_t count = 0;
|
||||
|
||||
while (v_q() != v_r()) {
|
||||
if (!v_n->is_received(v_q()))
|
||||
if (!m_v_n.is_received(v_q()))
|
||||
break;
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
|
||||
"V(Q) to %d\n", v_q(), (v_q() + 1) & mod_sns());
|
||||
|
@ -197,3 +210,11 @@ uint16_t gprs_rlc_ul_window::raise_v_q(gprs_rlc_v_n *v_n)
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint16_t gprs_rlc_ul_window::receive_bsn(const uint16_t bsn)
|
||||
{
|
||||
m_v_n.mark_received(bsn);
|
||||
raise_v_r(bsn);
|
||||
|
||||
return raise_v_q();
|
||||
}
|
||||
|
|
184
src/rlc.h
184
src/rlc.h
|
@ -28,6 +28,23 @@
|
|||
class BTS;
|
||||
struct gprs_rlc_v_n;
|
||||
|
||||
/* The state of a BSN in the send/receive window */
|
||||
enum gprs_rlc_ul_bsn_state {
|
||||
GPRS_RLC_UL_BSN_INVALID,
|
||||
GPRS_RLC_UL_BSN_RECEIVED,
|
||||
GPRS_RLC_UL_BSN_MISSING,
|
||||
GPRS_RLC_UL_BSN_MAX,
|
||||
};
|
||||
|
||||
enum gprs_rlc_dl_bsn_state {
|
||||
GPRS_RLC_DL_BSN_INVALID,
|
||||
GPRS_RLC_DL_BSN_NACKED,
|
||||
GPRS_RLC_DL_BSN_ACKED,
|
||||
GPRS_RLC_DL_BSN_UNACKED,
|
||||
GPRS_RLC_DL_BSN_RESEND,
|
||||
GPRS_RLC_DL_BSN_MAX,
|
||||
};
|
||||
|
||||
|
||||
static inline uint16_t mod_sns_half()
|
||||
{
|
||||
|
@ -53,6 +70,36 @@ struct gprs_rlc {
|
|||
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;
|
||||
gprs_rlc_dl_bsn_state 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 gprs_rlc_dl_bsn_state state) const;
|
||||
void mark(int bsn, const gprs_rlc_dl_bsn_state state);
|
||||
|
||||
gprs_rlc_dl_bsn_state m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TODO: The UL/DL code could/should share a baseclass but
|
||||
|
@ -77,8 +124,34 @@ struct gprs_rlc_dl_window {
|
|||
const uint16_t v_a() 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 show_state(char *show_rbb);
|
||||
int count_unacked();
|
||||
|
||||
uint16_t m_v_s; /* send state */
|
||||
uint16_t m_v_a; /* ack state */
|
||||
|
||||
gprs_rlc_v_b m_v_b;
|
||||
};
|
||||
|
||||
struct gprs_rlc_v_n {
|
||||
void reset();
|
||||
|
||||
void mark_received(int bsn);
|
||||
void mark_missing(int bsn);
|
||||
|
||||
bool is_received(int bsn) const;
|
||||
|
||||
gprs_rlc_ul_bsn_state state(int bsn) const;
|
||||
private:
|
||||
bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
|
||||
void mark(int bsn, const gprs_rlc_ul_bsn_state state);
|
||||
gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
|
||||
};
|
||||
|
||||
struct gprs_rlc_ul_window {
|
||||
|
@ -93,67 +166,19 @@ struct gprs_rlc_ul_window {
|
|||
|
||||
bool is_in_window(uint8_t bsn) const;
|
||||
|
||||
void update_rbb(const gprs_rlc_v_n *v_n, char *rbb);
|
||||
void raise_v_r(int moves);
|
||||
void raise_v_r(const uint16_t bsn, gprs_rlc_v_n *v_n);
|
||||
uint16_t raise_v_q(gprs_rlc_v_n *v_n);
|
||||
void update_rbb(char *rbb);
|
||||
void raise_v_r_to(int moves);
|
||||
void raise_v_r(const uint16_t bsn);
|
||||
uint16_t raise_v_q();
|
||||
|
||||
void raise_v_q(int);
|
||||
|
||||
uint16_t receive_bsn(const uint16_t bsn);
|
||||
|
||||
uint16_t m_v_r; /* receive state */
|
||||
uint16_t m_v_q; /* receive window state */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
};
|
||||
|
||||
struct gprs_rlc_v_n {
|
||||
void reset();
|
||||
|
||||
void mark_received(int bsn);
|
||||
void mark_missing(int bsn);
|
||||
|
||||
bool is_received(int bsn) const;
|
||||
|
||||
char state(int bsn) const;
|
||||
private:
|
||||
bool is_state(int bsn, const char state) const;
|
||||
void mark(int bsn, const char state);
|
||||
char m_v_n[RLC_MAX_SNS/2]; /* receive state array */
|
||||
gprs_rlc_v_n m_v_n;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
@ -190,67 +215,71 @@ struct rlc_li_field {
|
|||
} __attribute__ ((packed));
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_state(int bsn, const char type) const
|
||||
inline bool gprs_rlc_v_b::is_state(int bsn, const gprs_rlc_dl_bsn_state type) const
|
||||
{
|
||||
return m_v_b[bsn & mod_sns_half()] == type;
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_b::mark(int bsn, const char type)
|
||||
inline void gprs_rlc_v_b::mark(int bsn, const gprs_rlc_dl_bsn_state type)
|
||||
{
|
||||
m_v_b[bsn & mod_sns_half()] = type;
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_nacked(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'N');
|
||||
return is_state(bsn, GPRS_RLC_DL_BSN_NACKED);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_acked(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'A');
|
||||
return is_state(bsn, GPRS_RLC_DL_BSN_ACKED);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_unacked(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'U');
|
||||
return is_state(bsn, GPRS_RLC_DL_BSN_UNACKED);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_resend(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'X');
|
||||
return is_state(bsn, GPRS_RLC_DL_BSN_RESEND);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_b::is_invalid(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'I');
|
||||
return is_state(bsn, GPRS_RLC_DL_BSN_INVALID);
|
||||
}
|
||||
|
||||
inline gprs_rlc_dl_bsn_state 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)
|
||||
{
|
||||
return mark(bsn, 'X');
|
||||
return mark(bsn, GPRS_RLC_DL_BSN_RESEND);
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_b::mark_unacked(int bsn)
|
||||
{
|
||||
return mark(bsn, 'U');
|
||||
return mark(bsn, GPRS_RLC_DL_BSN_UNACKED);
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_b::mark_acked(int bsn)
|
||||
{
|
||||
return mark(bsn, 'A');
|
||||
return mark(bsn, GPRS_RLC_DL_BSN_ACKED);
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_b::mark_nacked(int bsn)
|
||||
{
|
||||
return mark(bsn, 'N');
|
||||
return mark(bsn, GPRS_RLC_DL_BSN_NACKED);
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_b::mark_invalid(int bsn)
|
||||
{
|
||||
return mark(bsn, 'I');
|
||||
return mark(bsn, GPRS_RLC_DL_BSN_INVALID);
|
||||
}
|
||||
|
||||
|
||||
inline const uint16_t gprs_rlc_dl_window::sns() const
|
||||
{
|
||||
return RLC_MAX_SNS;
|
||||
|
@ -347,7 +376,7 @@ inline const uint16_t gprs_rlc_ul_window::ssn() const
|
|||
return m_v_r;
|
||||
}
|
||||
|
||||
inline void gprs_rlc_ul_window::raise_v_r(int moves)
|
||||
inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
|
||||
{
|
||||
m_v_r = (m_v_r + moves) & mod_sns();
|
||||
}
|
||||
|
@ -359,35 +388,32 @@ inline void gprs_rlc_ul_window::raise_v_q(int incr)
|
|||
|
||||
inline void gprs_rlc_v_n::mark_received(int bsn)
|
||||
{
|
||||
return mark(bsn, 'R');
|
||||
return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_n::mark_missing(int bsn)
|
||||
{
|
||||
return mark(bsn, 'N');
|
||||
return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_n::is_received(int bsn) const
|
||||
{
|
||||
return is_state(bsn, 'R');
|
||||
return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
|
||||
}
|
||||
|
||||
inline bool gprs_rlc_v_n::is_state(int bsn, const char type) const
|
||||
inline bool gprs_rlc_v_n::is_state(int bsn, gprs_rlc_ul_bsn_state type) const
|
||||
{
|
||||
return m_v_n[bsn & mod_sns_half()] == type;
|
||||
}
|
||||
|
||||
inline void gprs_rlc_v_n::mark(int bsn, const char type)
|
||||
inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
|
||||
{
|
||||
m_v_n[bsn & mod_sns_half()] = type;
|
||||
}
|
||||
|
||||
inline char gprs_rlc_v_n::state(int bsn) const
|
||||
inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
|
||||
{
|
||||
char bit = m_v_n[bsn & mod_sns_half()];
|
||||
if (bit == '\0')
|
||||
return ' ';
|
||||
return bit;
|
||||
return m_v_n[bsn & mod_sns_half()];
|
||||
}
|
||||
|
||||
inline gprs_rlc_data *gprs_rlc::block(int bsn)
|
||||
|
|
24
src/tbf.cpp
24
src/tbf.cpp
|
@ -834,11 +834,11 @@ struct msgb *gprs_rlcmac_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts)
|
|||
|
||||
do_resend:
|
||||
/* 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) {
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
|
||||
/* 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();
|
||||
return create_dl_acked_block(fn, ts, resend_bsn, false);
|
||||
}
|
||||
|
@ -873,7 +873,7 @@ do_resend:
|
|||
}
|
||||
|
||||
/* 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
|
||||
* 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?"
|
||||
rlc_data->len = block_length;
|
||||
/* 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();
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
dir.dl.v_b.update(bts, show_rbb, ssn, dir.dl.window,
|
||||
dir.dl.window.update(bts, show_rbb, ssn,
|
||||
&lost, &received);
|
||||
|
||||
/* report lost and received packets */
|
||||
gprs_rlcmac_received_lost(this, received, lost);
|
||||
|
||||
/* 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) */
|
||||
dir.dl.v_b.state(show_v_b, dir.dl.window);
|
||||
dir.dl.window.show_state(show_v_b);
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
|
||||
"(V(S)-1=%d) A=Acked N=Nacked U=Unacked "
|
||||
"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");
|
||||
/* 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 */
|
||||
gprs_rlcmac_received_lost(this, received, 0);
|
||||
|
@ -1606,14 +1606,12 @@ int gprs_rlcmac_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t len
|
|||
rh->bsn, dir.ul.window.v_q(),
|
||||
(dir.ul.window.v_q() + ws - 1) & mod_sns);
|
||||
|
||||
dir.ul.v_n.mark_received(rh->bsn);
|
||||
dir.ul.window.raise_v_r(rh->bsn, &dir.ul.v_n);
|
||||
|
||||
/* Raise V(Q) if possible, and retrieve LLC frames from blocks.
|
||||
* This is looped until there is a gap (non received block) or
|
||||
* the window is empty.*/
|
||||
const uint16_t v_q_beg = dir.ul.window.v_q();
|
||||
const uint16_t count = dir.ul.window.raise_v_q(&dir.ul.v_n);
|
||||
|
||||
const uint16_t count = dir.ul.window.receive_bsn(rh->bsn);
|
||||
|
||||
/* Retrieve LLC frames from blocks that are ready */
|
||||
for (uint16_t i = 0; i < count; ++i) {
|
||||
|
@ -1723,7 +1721,7 @@ void gprs_rlcmac_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
|
|||
|
||||
/* reset rlc states */
|
||||
memset(&dir.dl, 0, sizeof(dir.dl));
|
||||
dir.dl.v_b.reset();
|
||||
dir.dl.window.m_v_b.reset();
|
||||
|
||||
/* keep to flags */
|
||||
state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
|
||||
|
|
|
@ -168,13 +168,11 @@ struct gprs_rlcmac_tbf {
|
|||
union {
|
||||
struct {
|
||||
gprs_rlc_dl_window window;
|
||||
gprs_rlc_v_b v_b;
|
||||
int32_t tx_counter; /* count all transmitted blocks */
|
||||
uint8_t wait_confirm; /* wait for CCCH IMM.ASS cnf */
|
||||
} dl;
|
||||
struct {
|
||||
gprs_rlc_ul_window window;
|
||||
gprs_rlc_v_n v_n;
|
||||
int32_t rx_counter; /* count all received blocks */
|
||||
uint8_t n3103; /* N3103 counter */
|
||||
uint8_t usf[8]; /* list USFs per PDCH (timeslot) */
|
||||
|
|
|
@ -132,15 +132,15 @@ static void test_rlc_v_n()
|
|||
vn.reset();
|
||||
|
||||
OSMO_ASSERT(!vn.is_received(0x23));
|
||||
OSMO_ASSERT(vn.state(0x23) == ' ');
|
||||
OSMO_ASSERT(vn.state(0x23) == GPRS_RLC_UL_BSN_INVALID);
|
||||
|
||||
vn.mark_received(0x23);
|
||||
OSMO_ASSERT(vn.is_received(0x23));
|
||||
OSMO_ASSERT(vn.state(0x23) == 'R');
|
||||
OSMO_ASSERT(vn.state(0x23) == GPRS_RLC_UL_BSN_RECEIVED);
|
||||
|
||||
vn.mark_missing(0x23);
|
||||
OSMO_ASSERT(!vn.is_received(0x23));
|
||||
OSMO_ASSERT(vn.state(0x23) == 'N');
|
||||
OSMO_ASSERT(vn.state(0x23) == GPRS_RLC_UL_BSN_MISSING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,24 +193,23 @@ static void test_rlc_dl_ul_basic()
|
|||
|
||||
{
|
||||
gprs_rlc_ul_window ul_win = { 0, };
|
||||
gprs_rlc_v_n v_n;
|
||||
int count;
|
||||
const char *rbb;
|
||||
char win_rbb[65];
|
||||
uint8_t bin_rbb[8];
|
||||
win_rbb[64] = '\0';
|
||||
|
||||
v_n.reset();
|
||||
ul_win.m_v_n.reset();
|
||||
|
||||
OSMO_ASSERT(ul_win.is_in_window(0));
|
||||
OSMO_ASSERT(ul_win.is_in_window(63));
|
||||
OSMO_ASSERT(!ul_win.is_in_window(64));
|
||||
|
||||
OSMO_ASSERT(!v_n.is_received(0));
|
||||
OSMO_ASSERT(!ul_win.m_v_n.is_received(0));
|
||||
|
||||
rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII";
|
||||
OSMO_ASSERT(ul_win.ssn() == 0);
|
||||
ul_win.update_rbb(&v_n, win_rbb);
|
||||
ul_win.update_rbb(win_rbb);
|
||||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
Encoding::encode_rbb(win_rbb, bin_rbb);
|
||||
printf("rbb: %s\n", osmo_hexdump(bin_rbb, sizeof(bin_rbb)));
|
||||
|
@ -219,17 +218,15 @@ static void test_rlc_dl_ul_basic()
|
|||
|
||||
/* simulate to have received 0, 1 and 5 */
|
||||
OSMO_ASSERT(ul_win.is_in_window(0));
|
||||
v_n.mark_received(0);
|
||||
ul_win.raise_v_r(0, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
OSMO_ASSERT(v_n.is_received(0));
|
||||
count = ul_win.receive_bsn(0);
|
||||
OSMO_ASSERT(ul_win.m_v_n.is_received(0));
|
||||
OSMO_ASSERT(ul_win.v_q() == 1);
|
||||
OSMO_ASSERT(ul_win.v_r() == 1);
|
||||
OSMO_ASSERT(count == 1);
|
||||
|
||||
rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR";
|
||||
OSMO_ASSERT(ul_win.ssn() == 1);
|
||||
ul_win.update_rbb(&v_n, win_rbb);
|
||||
ul_win.update_rbb(win_rbb);
|
||||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
Encoding::encode_rbb(win_rbb, bin_rbb);
|
||||
printf("rbb: %s\n", osmo_hexdump(bin_rbb, sizeof(bin_rbb)));
|
||||
|
@ -237,17 +234,15 @@ static void test_rlc_dl_ul_basic()
|
|||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
|
||||
OSMO_ASSERT(ul_win.is_in_window(1));
|
||||
v_n.mark_received(1);
|
||||
ul_win.raise_v_r(1, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
OSMO_ASSERT(v_n.is_received(0));
|
||||
count = ul_win.receive_bsn(1);
|
||||
OSMO_ASSERT(ul_win.m_v_n.is_received(0));
|
||||
OSMO_ASSERT(ul_win.v_q() == 2);
|
||||
OSMO_ASSERT(ul_win.v_r() == 2);
|
||||
OSMO_ASSERT(count == 1);
|
||||
|
||||
rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRR";
|
||||
OSMO_ASSERT(ul_win.ssn() == 2);
|
||||
ul_win.update_rbb(&v_n, win_rbb);
|
||||
ul_win.update_rbb(win_rbb);
|
||||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
Encoding::encode_rbb(win_rbb, bin_rbb);
|
||||
printf("rbb: %s\n", osmo_hexdump(bin_rbb, sizeof(bin_rbb)));
|
||||
|
@ -255,17 +250,15 @@ static void test_rlc_dl_ul_basic()
|
|||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
|
||||
OSMO_ASSERT(ul_win.is_in_window(5));
|
||||
v_n.mark_received(5);
|
||||
ul_win.raise_v_r(5, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
OSMO_ASSERT(v_n.is_received(0));
|
||||
count = ul_win.receive_bsn(5);
|
||||
OSMO_ASSERT(ul_win.m_v_n.is_received(0));
|
||||
OSMO_ASSERT(ul_win.v_q() == 2);
|
||||
OSMO_ASSERT(ul_win.v_r() == 6);
|
||||
OSMO_ASSERT(count == 0);
|
||||
|
||||
rbb = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRRIIIR";
|
||||
OSMO_ASSERT(ul_win.ssn() == 6);
|
||||
ul_win.update_rbb(&v_n, win_rbb);
|
||||
ul_win.update_rbb(win_rbb);
|
||||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
Encoding::encode_rbb(win_rbb, bin_rbb);
|
||||
printf("rbb: %s\n", osmo_hexdump(bin_rbb, sizeof(bin_rbb)));
|
||||
|
@ -274,18 +267,16 @@ static void test_rlc_dl_ul_basic()
|
|||
|
||||
OSMO_ASSERT(ul_win.is_in_window(65));
|
||||
OSMO_ASSERT(ul_win.is_in_window(2));
|
||||
OSMO_ASSERT(v_n.is_received(5));
|
||||
v_n.mark_received(65);
|
||||
ul_win.raise_v_r(65, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
OSMO_ASSERT(ul_win.m_v_n.is_received(5));
|
||||
count = ul_win.receive_bsn(65);
|
||||
OSMO_ASSERT(count == 0);
|
||||
OSMO_ASSERT(v_n.is_received(5));
|
||||
OSMO_ASSERT(ul_win.m_v_n.is_received(5));
|
||||
OSMO_ASSERT(ul_win.v_q() == 2);
|
||||
OSMO_ASSERT(ul_win.v_r() == 66);
|
||||
|
||||
rbb = "IIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR";
|
||||
OSMO_ASSERT(ul_win.ssn() == 66);
|
||||
ul_win.update_rbb(&v_n, win_rbb);
|
||||
ul_win.update_rbb(win_rbb);
|
||||
OSMO_ASSERT_STR_EQ(win_rbb, rbb);
|
||||
Encoding::encode_rbb(win_rbb, bin_rbb);
|
||||
printf("rbb: %s\n", osmo_hexdump(bin_rbb, sizeof(bin_rbb)));
|
||||
|
@ -294,33 +285,25 @@ static void test_rlc_dl_ul_basic()
|
|||
|
||||
OSMO_ASSERT(ul_win.is_in_window(2));
|
||||
OSMO_ASSERT(!ul_win.is_in_window(66));
|
||||
v_n.mark_received(2);
|
||||
ul_win.raise_v_r(2, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
count = ul_win.receive_bsn(2);
|
||||
OSMO_ASSERT(count == 1);
|
||||
OSMO_ASSERT(ul_win.v_q() == 3);
|
||||
OSMO_ASSERT(ul_win.v_r() == 66);
|
||||
|
||||
OSMO_ASSERT(ul_win.is_in_window(66));
|
||||
v_n.mark_received(66);
|
||||
ul_win.raise_v_r(66, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
count = ul_win.receive_bsn(66);
|
||||
OSMO_ASSERT(count == 0);
|
||||
OSMO_ASSERT(ul_win.v_q() == 3);
|
||||
OSMO_ASSERT(ul_win.v_r() == 67);
|
||||
|
||||
for (int i = 3; i <= 67; ++i) {
|
||||
v_n.mark_received(i);
|
||||
ul_win.raise_v_r(i, &v_n);
|
||||
ul_win.raise_v_q(&v_n);
|
||||
ul_win.receive_bsn(i);
|
||||
}
|
||||
|
||||
OSMO_ASSERT(ul_win.v_q() == 68);
|
||||
OSMO_ASSERT(ul_win.v_r() == 68);
|
||||
|
||||
v_n.mark_received(68);
|
||||
ul_win.raise_v_r(68, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
count = ul_win.receive_bsn(68);
|
||||
OSMO_ASSERT(ul_win.v_q() == 69);
|
||||
OSMO_ASSERT(ul_win.v_r() == 69);
|
||||
OSMO_ASSERT(count == 1);
|
||||
|
@ -328,9 +311,7 @@ static void test_rlc_dl_ul_basic()
|
|||
/* now test the wrapping */
|
||||
OSMO_ASSERT(ul_win.is_in_window(4));
|
||||
OSMO_ASSERT(!ul_win.is_in_window(5));
|
||||
v_n.mark_received(4);
|
||||
ul_win.raise_v_r(4, &v_n);
|
||||
count = ul_win.raise_v_q(&v_n);
|
||||
count = ul_win.receive_bsn(4);
|
||||
OSMO_ASSERT(count == 0);
|
||||
}
|
||||
|
||||
|
@ -341,9 +322,8 @@ static void test_rlc_dl_ul_basic()
|
|||
char show_rbb[65];
|
||||
BTS dummy_bts;
|
||||
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_stalled());
|
||||
|
@ -364,7 +344,7 @@ static void test_rlc_dl_ul_basic()
|
|||
Decoding::extract_rbb(rbb_cmp, 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(recv == 35);
|
||||
|
||||
|
|
Loading…
Reference in New Issue