aboutsummaryrefslogtreecommitdiffstats
path: root/src/rlc_window_ul.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rlc_window_ul.cpp')
-rw-r--r--src/rlc_window_ul.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/rlc_window_ul.cpp b/src/rlc_window_ul.cpp
new file mode 100644
index 00000000..32810d1b
--- /dev/null
+++ b/src/rlc_window_ul.cpp
@@ -0,0 +1,125 @@
+/* RLC Window (UL TBF), 3GPP TS 44.060
+ *
+ * Copyright (C) 2013 by Holger Hans Peter Freyther
+ * Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "gprs_debug.h"
+#include "rlc_window_ul.h"
+
+extern "C" {
+#include <osmocom/core/utils.h>
+#include <osmocom/core/bitvec.h>
+#include <osmocom/core/logging.h>
+}
+
+void gprs_rlc_v_n::reset()
+{
+ for (size_t i = 0; i < ARRAY_SIZE(m_v_n); ++i)
+ m_v_n[i] = GPRS_RLC_UL_BSN_INVALID;
+}
+
+/* Raise V(R) to highest received sequence number not received. */
+void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn)
+{
+ uint16_t offset_v_r;
+ offset_v_r = mod_sns(bsn + 1 - v_r());
+ /* Positive offset, so raise. */
+ if (offset_v_r < (sns() >> 1)) {
+ while (offset_v_r--) {
+ const uint16_t _v_r = v_r();
+ const uint16_t bsn_no_longer_in_ws = mod_sns(_v_r - ws());
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Mark BSN %u as INVALID\n", bsn_no_longer_in_ws);
+ m_v_n.mark_invalid(bsn_no_longer_in_ws);
+ if (offset_v_r) {/* all except the received block */
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Mark BSN %u as MISSING\n", _v_r);
+ m_v_n.mark_missing(_v_r);
+ }
+ raise_v_r_to(1);
+ }
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", v_r());
+ }
+}
+
+/*
+ * 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()
+{
+ uint16_t count = 0;
+
+ while (v_q() != v_r()) {
+ 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(), mod_sns(v_q() + 1));
+ raise_v_q(1);
+ count += 1;
+ }
+
+ return count;
+}
+
+void gprs_rlc_ul_window::receive_bsn(const uint16_t bsn)
+{
+ m_v_n.mark_received(bsn);
+ raise_v_r(bsn);
+}
+
+bool gprs_rlc_ul_window::invalidate_bsn(const uint16_t bsn)
+{
+ bool was_valid = m_v_n.is_received(bsn);
+ m_v_n.mark_missing(bsn);
+
+ return was_valid;
+}
+
+
+/* Update the receive block bitmap */
+uint16_t gprs_rlc_ul_window::update_egprs_rbb(uint8_t *rbb)
+{
+ uint16_t i;
+ uint16_t bsn;
+ uint16_t bitmask = 0x80;
+ int8_t pos = 0;
+ int8_t bit_pos = 0;
+ for (i = 0, bsn = (v_q()+1); ((bsn < (v_r())) && (i < ws())); i++,
+ bsn = this->mod_sns(bsn + 1)) {
+ if (m_v_n.is_received(bsn)) {
+ rbb[pos] = rbb[pos] | bitmask;
+ } else {
+ rbb[pos] = rbb[pos] & (~bitmask);
+ }
+ bitmask = bitmask >> 1;
+ bit_pos++;
+ bit_pos = bit_pos % 8;
+ if (bit_pos == 0) {
+ pos++;
+ bitmask = 0x80;
+ }
+ }
+ return i;
+}
+
+/* Update the receive block bitmap */
+void gprs_rlc_ul_window::update_rbb(char *rbb)
+{
+ int i;
+ for (i=0; i < ws(); i++) {
+ if (m_v_n.is_received((ssn()-1-i) & mod_sns()))
+ rbb[ws()-1-i] = 'R';
+ else
+ rbb[ws()-1-i] = 'I';
+ }
+} \ No newline at end of file