aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2016-02-05 17:07:12 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2016-02-08 00:45:34 +0100
commiteb08f86c0278bc6c6d1ba42c82c66d564a5f7c06 (patch)
treea7dd857508dfdca199acf7a55d5fa02390afde29
parentf2f24b09593bb91e84538e7f6c9e51dd642bf5e0 (diff)
edge: Add bitvec based DL window updating methods
The current methods are based on the GRPS specific RBB and SSN values and formats which are not compatible with EGPRS. Add a second set of similar methods with the same semantics but which are based on a bitvec and the first BSN instead. The following methods are affected: - gprs_rlc_dl_window::update - gprs_rlcmac_dl_tbf::rcvd_dl_ack - gprs_rlcmac_dl_tbf::update_window Sponsored-by: On-Waves ehf
-rw-r--r--src/rlc.cpp31
-rw-r--r--src/rlc.h4
-rw-r--r--src/tbf.h2
-rw-r--r--src/tbf_dl.cpp81
4 files changed, 118 insertions, 0 deletions
diff --git a/src/rlc.cpp b/src/rlc.cpp
index 1a8efdf6..6d3cfd59 100644
--- a/src/rlc.cpp
+++ b/src/rlc.cpp
@@ -114,6 +114,37 @@ static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn)
return (ssn - 1 - bitnum);
}
+void gprs_rlc_dl_window::update(BTS *bts, const struct bitvec *rbb,
+ uint16_t first_bsn, uint16_t *lost,
+ uint16_t *received)
+{
+ unsigned num_blocks = rbb->cur_bit;
+ unsigned bsn;
+
+ /* first_bsn is in range V(A)..V(S) */
+
+ for (unsigned int bitpos = 0; bitpos < num_blocks; bitpos++) {
+ bool is_ack;
+ bsn = mod_sns(first_bsn + bitpos);
+ if (bsn == mod_sns(v_a() - 1))
+ break;
+
+ is_ack = bitvec_get_bit_pos(rbb, bitpos) == 1;
+
+ if (is_ack) {
+ LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
+ if (!m_v_b.is_acked(bsn))
+ *received += 1;
+ m_v_b.mark_acked(bsn);
+ } else {
+ LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
+ m_v_b.mark_nacked(bsn);
+ bts->rlc_nacked();
+ *lost += 1;
+ }
+ }
+}
+
void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint16_t ssn,
uint16_t *lost, uint16_t *received)
{
diff --git a/src/rlc.h b/src/rlc.h
index 76af4e10..3f599d47 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -32,6 +32,7 @@
#define RLC_EGPRS_MAX_WS 1024 /* min window size */
#define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */
#define RLC_MAX_SNS RLC_EGPRS_SNS
+#define RLC_MAX_WS RLC_EGPRS_MAX_WS
#define RLC_MAX_LEN 74 /* MCS-9 data unit */
struct BTS;
@@ -173,6 +174,9 @@ struct gprs_rlc_dl_window {
int mark_for_resend();
void update(BTS *bts, char *show_rbb, uint16_t ssn,
uint16_t *lost, uint16_t *received);
+ void update(BTS *bts, const struct bitvec *rbb,
+ uint16_t first_bsn, uint16_t *lost,
+ uint16_t *received);
int move_window();
void show_state(char *show_rbb);
int count_unacked();
diff --git a/src/tbf.h b/src/tbf.h
index cd982739..11e1fc73 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -344,6 +344,7 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
const uint8_t *data, const uint16_t len);
int rcvd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb);
+ int rcvd_dl_ack(uint8_t final_ack, unsigned first_bsn, struct bitvec *rbb);
struct msgb *create_dl_acked_block(uint32_t fn, uint8_t ts);
void request_dl_ack();
bool need_control_ts() const;
@@ -395,6 +396,7 @@ protected:
struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts,
const int index);
int update_window(const uint8_t ssn, const uint8_t *rbb);
+ int update_window(unsigned first_bsn, const struct bitvec *rbb);
int maybe_start_new_window();
bool dl_window_stalled() const;
void reuse_tbf();
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index e742c799..161ec26f 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -717,6 +717,75 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn,
return lost * 100 / (lost + received);
}
+int gprs_rlcmac_dl_tbf::update_window(unsigned first_bsn,
+ const struct bitvec *rbb)
+{
+ int16_t dist; /* must be signed */
+ uint16_t lost = 0, received = 0;
+ char show_v_b[RLC_MAX_SNS + 1];
+ char show_rbb[RLC_MAX_SNS + 1];
+ int error_rate;
+ struct ana_result ana_res;
+ unsigned num_blocks = rbb->cur_bit;
+ unsigned behind_last_bsn = m_window.mod_sns(first_bsn + num_blocks);
+
+ Decoding::extract_rbb(rbb, show_rbb);
+ /* show received array in debug */
+ LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\""
+ "(BSN=%d) R=ACK I=NACK\n", first_bsn,
+ show_rbb, m_window.mod_sns(behind_last_bsn - 1));
+
+ /* apply received array to receive state (first_bsn..behind_last_bsn-1) */
+ if (num_blocks > 0) {
+ /* calculate distance of ssn from V(S) */
+ dist = m_window.mod_sns(m_window.v_s() - behind_last_bsn);
+ /* check if distance is less than distance V(A)..V(S) */
+ if (dist >= m_window.distance()) {
+ /* this might happpen, if the downlink assignment
+ * was not received by ms and the ack refers
+ * to previous TBF
+ * FIXME: we should implement polling for
+ * control ack!
+ * TODO: check whether this FIXME still makes sense
+ */
+ LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of "
+ "V(A)..V(S) range %s Free TBF!\n", tbf_name(this));
+ return 1; /* indicate to free TBF */
+ }
+ }
+
+ error_rate = analyse_errors(show_rbb, behind_last_bsn, &ana_res);
+
+ if (bts_data()->cs_adj_enabled && ms())
+ ms()->update_error_rate(this, error_rate);
+
+ m_window.update(bts, rbb, first_bsn, &lost, &received);
+
+ /* report lost and received packets */
+ gprs_rlcmac_received_lost(this, received, lost);
+
+ /* Used to measure the leak rate */
+ gprs_bssgp_update_bytes_received(ana_res.received_bytes,
+ ana_res.received_packets + ana_res.lost_packets);
+
+ /* raise V(A), if possible */
+ m_window.raise(m_window.move_window());
+
+ /* show receive state array in debug (V(A)..V(S)-1) */
+ m_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",
+ m_window.v_a(), show_v_b,
+ m_window.v_s_mod(-1));
+
+ if (state_is(GPRS_RLCMAC_FINISHED) && m_window.window_empty()) {
+ LOGP(DRLCMACDL, LOGL_NOTICE, "Received acknowledge of "
+ "all blocks, but without final ack "
+ "inidcation (don't worry)\n");
+ }
+ return 0;
+}
int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
{
@@ -825,6 +894,18 @@ int gprs_rlcmac_dl_tbf::release()
}
+int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, unsigned first_bsn,
+ struct bitvec *rbb)
+{
+ LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this));
+
+ if (!final_ack)
+ return update_window(first_bsn, rbb);
+
+ LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
+ return maybe_start_new_window();
+}
+
int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb)
{
LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this));