mirror of https://github.com/PentHertz/srsLTE.git
lib,rlc_am_nr: added processing of ACKs from status report
This commit is contained in:
parent
ec93cc7238
commit
b794593469
|
@ -191,6 +191,11 @@ public:
|
|||
protected:
|
||||
std::unique_ptr<rlc_am_base_tx> tx_base = {};
|
||||
std::unique_ptr<rlc_am_base_rx> rx_base = {};
|
||||
|
||||
public:
|
||||
// Getters for TX/RX entities. Useful for testing.
|
||||
rlc_am_base_rx* get_rx() { return rx_base.get(); }
|
||||
rlc_am_base_tx* get_tx() { return tx_base.get(); }
|
||||
};
|
||||
|
||||
} // namespace srsran
|
||||
|
|
|
@ -35,7 +35,41 @@ namespace srsran {
|
|||
class rlc_am_nr_tx;
|
||||
class rlc_am_nr_rx;
|
||||
|
||||
// Transmitter sub-class
|
||||
/****************************************************************************
|
||||
* Tx state variables
|
||||
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.1
|
||||
***************************************************************************/
|
||||
struct rlc_am_nr_tx_state_t {
|
||||
/*
|
||||
* TX_Next_Ack: This state variable holds the value of the SN of the next RLC SDU for which a positive
|
||||
* acknowledgment is to be received in-sequence, and it serves as the lower edge of the transmitting window. It is
|
||||
* initially set to 0, and is updated whenever the AM RLC entity receives a positive acknowledgment for an RLC SDU
|
||||
* with SN = TX_Next_Ack.
|
||||
*/
|
||||
uint32_t tx_next_ack;
|
||||
/*
|
||||
* TX_Next: This state variable holds the value of the SN to be assigned for the next newly generated AMD PDU. It is
|
||||
* initially set to 0, and is updated whenever the AM RLC entity constructs an AMD PDU with SN = TX_Next and
|
||||
* contains an RLC SDU or the last segment of a RLC SDU.
|
||||
*/
|
||||
uint32_t tx_next;
|
||||
/*
|
||||
* POLL_SN: This state variable holds the value of the highest SN of the AMD PDU among the AMD PDUs submitted to
|
||||
* lower layer when POLL_SN is set according to sub clause 5.3.3.2. It is initially set to 0.
|
||||
*/
|
||||
uint32_t poll_sn;
|
||||
/*
|
||||
* PDU_WITHOUT_POLL: This counter is initially set to 0. It counts the number of AMD PDUs sent since the most recent
|
||||
* poll bit was transmitted.
|
||||
*/
|
||||
uint32_t pdu_without_poll;
|
||||
/*
|
||||
* BYTE_WITHOUT_POLL: This counter is initially set to 0. It counts the number of data bytes sent since the most
|
||||
* recent poll bit was transmitted.
|
||||
*/
|
||||
uint32_t byte_without_poll;
|
||||
};
|
||||
|
||||
class rlc_am_nr_tx : public rlc_am::rlc_am_base_tx
|
||||
{
|
||||
public:
|
||||
|
@ -80,17 +114,16 @@ private:
|
|||
* Tx state variables
|
||||
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.1
|
||||
***************************************************************************/
|
||||
struct rlc_nr_tx_state_t {
|
||||
uint32_t tx_next_ack;
|
||||
uint32_t tx_next;
|
||||
uint32_t poll_sn;
|
||||
uint32_t pdu_without_poll;
|
||||
uint32_t byte_without_poll;
|
||||
} st = {};
|
||||
struct rlc_am_nr_tx_state_t st = {};
|
||||
|
||||
using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu<rlc_am_nr_pdu_header_t>;
|
||||
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
|
||||
public:
|
||||
// Getters/Setters
|
||||
rlc_am_nr_tx_state_t get_tx_state() { return st; } // This should only be used for testing.
|
||||
uint32_t get_tx_window_size() { return tx_window.size(); } // This should only be used for testing.
|
||||
};
|
||||
|
||||
// Receiver sub-class
|
||||
|
|
|
@ -237,6 +237,21 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
* - consider the RLC SDU or the RLC SDU segment for which a negative acknowledgement was received for
|
||||
* retransmission.
|
||||
*/
|
||||
// Process ACKs
|
||||
uint32_t stop_sn = status.N_nack == 0
|
||||
? st.tx_next
|
||||
: status.nacks[0].nack_sn; // Stop processing ACKs at the first NACK, if it exists.
|
||||
if (status.ack_sn >= st.tx_next_ack) {
|
||||
for (uint32_t sn = st.tx_next_ack; sn < stop_sn; sn++) {
|
||||
if (tx_window.has_sn(sn)) {
|
||||
tx_window.remove_pdu(sn);
|
||||
st.tx_next_ack = sn + 1;
|
||||
} else {
|
||||
logger->error("Missing ACKed SN from TX window");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Process N_acks
|
||||
for (uint32_t nack_idx = 0; nack_idx < status.N_nack; nack_idx++) {
|
||||
if (st.tx_next_ack <= status.nacks[nack_idx].nack_sn && status.nacks[nack_idx].nack_sn <= st.tx_next) {
|
||||
|
|
|
@ -72,6 +72,11 @@ int basic_test()
|
|||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
|
||||
|
||||
rlc_am_nr_tx* tx1 = dynamic_cast<rlc_am_nr_tx*>(rlc1.get_tx());
|
||||
rlc_am_nr_rx* rx1 = dynamic_cast<rlc_am_nr_rx*>(rlc1.get_rx());
|
||||
rlc_am_nr_tx* tx2 = dynamic_cast<rlc_am_nr_tx*>(rlc2.get_tx());
|
||||
rlc_am_nr_rx* rx2 = dynamic_cast<rlc_am_nr_rx*>(rlc2.get_rx());
|
||||
|
||||
// before configuring entity
|
||||
TESTASSERT(0 == rlc1.get_buffer_state());
|
||||
|
||||
|
@ -106,6 +111,10 @@ int basic_test()
|
|||
// Write status PDU to RLC1
|
||||
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
|
||||
|
||||
// Check TX_NEXT_ACK
|
||||
rlc_am_nr_tx_state_t st = tx1->get_tx_state();
|
||||
TESTASSERT_EQ(5, st.tx_next_ack);
|
||||
TESTASSERT_EQ(0, tx1->get_tx_window_size());
|
||||
// Check statistics
|
||||
TESTASSERT(rx_is_tx(rlc1.get_metrics(), rlc2.get_metrics()));
|
||||
return SRSRAN_SUCCESS;
|
||||
|
|
Loading…
Reference in New Issue