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
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index e742c79..161ec26 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -717,6 +717,75 @@
 	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::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));