Commit 79242aaf authored by fnabet's avatar fnabet

RLC AM Tx changes

parent 5551c5e5
...@@ -43,6 +43,109 @@ ...@@ -43,6 +43,109 @@
#include "DL-AM-RLC.h" #include "DL-AM-RLC.h"
//-----------------------------------------------------------------------------
uint32_t
rlc_am_get_status_pdu_buffer_occupancy(
rlc_am_entity_t * const rlc_pP){
//Compute Max Status PDU size according to what has been received and not received in the window [vrR vrMS[
// minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1
uint32_t nb_bits_to_transmit = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS;
mem_block_t *cursor_p = rlc_pP->receiver_buffer.head;
rlc_am_pdu_info_t *pdu_info_cursor_p = NULL;
int waited_so = 0;
rlc_sn_t sn_cursor = rlc_pP->vr_r;
rlc_sn_t sn_prev = rlc_pP->vr_r;
rlc_sn_t sn_end = rlc_pP->vr_ms;
boolean_t segment_loop_end = false;
if (sn_prev != sn_end)
{
while ((RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)) && (cursor_p != NULL))
{
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
sn_cursor = pdu_info_cursor_p->sn;
// Add holes between sn_prev and sn_cursor
while ((sn_prev != sn_cursor) && (sn_prev != sn_end))
{
/* Add 1 NACK_SN + E1 + E2 */
nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1));
sn_prev = RLC_AM_NEXT_SN(sn_prev);
} //end while (sn_prev != sn_cursor)
/* Handle case sn_cursor is partially received */
/* Each gap will add NACK_SN + E1 + E2 + SOStart + SOEnd */
if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) && (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)))
{
/* Check lsf */
segment_loop_end = (pdu_info_cursor_p->lsf == 1);
/* Fill for [0 SO[ if SO not null */
if (pdu_info_cursor_p->so) {
nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
/* Go to next segment */
cursor_p = cursor_p->next;
if (cursor_p != NULL)
{
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
}
else {
waited_so = pdu_info_cursor_p->payload_size;
}
/* Fill following gaps if any */
while (!segment_loop_end)
{
if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor))
{
/* Check lsf */
segment_loop_end = (pdu_info_cursor_p->lsf == 1);
if (waited_so < pdu_info_cursor_p->so) {
nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
}
else {
/* contiguous segment: only update waited_so */
/* Assuming so and payload_size updated according to duplication removal done at reception ... */
waited_so += pdu_info_cursor_p->payload_size;
}
/* Go to next received PDU or PDU Segment */
cursor_p = cursor_p->next;
if (cursor_p != NULL)
{
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
}
else
{
/* Fill last gap assuming LSF is not received */
nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
segment_loop_end = true;
}
} // end while (!segment_loop_end)
} // end if segments
else
{
/* Go to next received PDU or PDU Segment */
cursor_p = cursor_p->next;
}
sn_prev = RLC_AM_NEXT_SN(sn_cursor);
}
} // end if (sn_prev != sn_end)
// round up to the greatest byte
return ((nb_bits_to_transmit + 7) >> 3);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
uint32_t uint32_t
rlc_am_get_buffer_occupancy_in_bytes ( rlc_am_get_buffer_occupancy_in_bytes (
...@@ -54,26 +157,24 @@ rlc_am_get_buffer_occupancy_in_bytes ( ...@@ -54,26 +157,24 @@ rlc_am_get_buffer_occupancy_in_bytes (
// priority of control trafic // priority of control trafic
rlc_pP->status_buffer_occupancy = 0; rlc_pP->status_buffer_occupancy = 0;
if (rlc_pP->status_requested) { if ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK)) {
if (rlc_pP->t_status_prohibit.running == 0) { rlc_pP->status_buffer_occupancy = rlc_am_get_status_pdu_buffer_occupancy(rlc_pP);
#if TRACE_RLC_AM_BO #if TRACE_RLC_AM_BO
if (((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3) > 0) { LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n",
LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->status_buffer_occupancy);
((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3));
}
#endif #endif
rlc_pP->status_buffer_occupancy = ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3);
}
} }
// data traffic // data traffic
if (rlc_pP->nb_sdu_no_segmented <= 1) { if (rlc_pP->nb_sdu_no_segmented <= 1) {
max_li_overhead = 0; max_li_overhead = 0;
} else { } else {
max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/
uint32_t num_li = rlc_pP->nb_sdu_no_segmented - 1;
max_li_overhead = num_li + (num_li >> 1) + (num_li & 1);
} }
if (rlc_pP->sdu_buffer_occupancy == 0) { if (rlc_pP->sdu_buffer_occupancy == 0) {
...@@ -372,6 +473,7 @@ rlc_am_get_pdus ( ...@@ -372,6 +473,7 @@ rlc_am_get_pdus (
} }
}*/ }*/
// THEN TRY TO SEND RETRANS PDU // THEN TRY TO SEND RETRANS PDU
// BUG FIX : they can be PDU to ReTx due to received NACK or 1 PDU (SN = vtS - 1) to ReTx due TPoll Expiry if Buffer Occupancy is null
if (rlc_pP->first_retrans_pdu_sn >= 0) { if (rlc_pP->first_retrans_pdu_sn >= 0) {
rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; rlc_am_tx_data_pdu_management_t* tx_data_pdu_management;
......
...@@ -72,24 +72,11 @@ ...@@ -72,24 +72,11 @@
# define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16 # define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16
/** @} */ /** @} */
/* Common to Data and Status PDU */ #define RLC_AM_POLL_PDU_INFINITE 0xFFFF
#define RLC_AM_SN_BITS 10 #define RLC_AM_POLL_BYTE_INFINITE 0xFFFFFFFF
#define RLC_AM_PDU_D_C_BITS 1
#define RLC_AM_PDU_E_BITS 1
/* STATUS PDU */
#define RLC_AM_STATUS_PDU_CPT_STATUS 0
#define RLC_AM_STATUS_PDU_CPT_OFFSET 4
#define RLC_AM_STATUS_PDU_CPT_LENGTH 3
#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET 2
#define RLC_AM_STATUS_PDU_SO_LENGTH 15
#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES 0x7FFF
/* MACRO DEFINITIONS */ /* MACRO DEFINITIONS */
#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) #define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1))
#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1)) #define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1))
...@@ -99,10 +86,52 @@ ...@@ -99,10 +86,52 @@
#define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO)) #define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO))
#define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO)) #define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO))
#define RLC_SET_BIT(x,offset) ((x) |= (1 << (offset)))
#define RLC_GET_BIT(x,offset) (((x) & (1 << (offset))) >> (offset))
#define RLC_CLEAR_BIT(x,offset) ((x) &= ~(1 << (offset)))
#define RLC_SET_EVENT(x,event) ((x) |= (event)) #define RLC_SET_EVENT(x,event) ((x) |= (event))
#define RLC_GET_EVENT(x,event) ((x) & (event)) #define RLC_GET_EVENT(x,event) ((x) & (event))
#define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event))) #define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event)))
/* Common to Data and Status PDU */
#define RLC_AM_SN_BITS 10
#define RLC_AM_PDU_D_C_BITS 1
#define RLC_AM_PDU_E_BITS 1
#define RLC_AM_PDU_FI_BITS 2
#define RLC_AM_PDU_POLL_BITS 1
#define RLC_AM_PDU_RF_BITS 1
#define EURL_AM_PDU_LSF_BITS 1
/* AM Data PDU */
#define RLC_AM_PDU_E_OFFSET 2
#define RLC_AM_PDU_FI_OFFSET (RLC_AM_PDU_E_OFFSET + RLC_AM_PDU_E_BITS)
#define RLC_AM_PDU_POLL_OFFSET (RLC_AM_PDU_FI_OFFSET + RLC_AM_PDU_FI_BITS)
#define RLC_AM_PDU_RF_OFFSET (RLC_AM_PDU_POLL_OFFSET + RLC_AM_PDU_POLL_BITS)
#define RLC_AM_PDU_D_C_OFFSET (RLC_AM_PDU_RF_OFFSET + RLC_AM_PDU_RF_BITS)
#define RLC_AM_PDU_SET_E(px) (RLC_SET_BIT((px),RLC_AM_PDU_E_OFFSET))
#define RLC_AM_PDU_SET_D_C(px) (RLC_SET_BIT((px),RLC_AM_PDU_D_C_OFFSET))
#define RLC_AM_PDU_SET_RF(px) (RLC_SET_BIT((px),RLC_AM_PDU_RF_OFFSET))
#define RLC_AM_PDU_SET_POLL(px) (RLC_SET_BIT((px),RLC_AM_PDU_POLL_OFFSET))
#define RLC_AM_PDU_CLEAR_POLL(px) (RLC_CLEAR_BIT((px),RLC_AM_PDU_POLL_OFFSET))
/* STATUS PDU */
#define RLC_AM_STATUS_PDU_CPT_STATUS 0
#define RLC_AM_STATUS_PDU_CPT_OFFSET 4
#define RLC_AM_STATUS_PDU_CPT_LENGTH 3
#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET 2
#define RLC_AM_STATUS_PDU_SO_LENGTH 15
#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES 0x7FFF
/* Uplink STATUS PDU trigger events */ /* Uplink STATUS PDU trigger events */
#define RLC_AM_STATUS_NOT_TRIGGERED 0 #define RLC_AM_STATUS_NOT_TRIGGERED 0
#define RLC_AM_STATUS_TRIGGERED_POLL 0x01 /* Status Report is triggered by a received poll */ #define RLC_AM_STATUS_TRIGGERED_POLL 0x01 /* Status Report is triggered by a received poll */
......
...@@ -69,17 +69,15 @@ typedef struct rlc_am_entity_s { ...@@ -69,17 +69,15 @@ typedef struct rlc_am_entity_s {
pthread_mutex_t lock_input_sdus; pthread_mutex_t lock_input_sdus;
rlc_am_tx_sdu_management_t *input_sdus; /*!< \brief Input SDU buffer (for SDUs coming from upper layers). */ rlc_am_tx_sdu_management_t *input_sdus; /*!< \brief Input SDU buffer (for SDUs coming from upper layers). */
signed int nb_sdu; /*!< \brief Total number of valid rlc_am_tx_sdu_management_t in input_sdus[]. */ signed int nb_sdu; /*!< \brief Total number of valid rlc_am_tx_sdu_management_t in input_sdus[]. */
signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. */ signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. nb_sdu_no_segmented = next_sdu_index - current_sdu_index */
signed int next_sdu_index; /*!< \brief Next SDU index in input_sdus array where for a new incoming SDU. */ signed int next_sdu_index; /*!< \brief Next SDU index in input_sdus array where for a new incoming SDU. */
signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented. */ signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented which is not segmented or partially segmented. */
rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer; /*!< \brief Retransmission buffer. */ rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer; /*!< \brief Retransmission buffer. */
signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */
signed int retrans_num_bytes; /*!< \brief Number of bytes in the retransmission buffer. */ signed int retrans_num_bytes; /*!< \brief Number of bytes in the retransmission buffer. */
signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */ signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */
unsigned int num_nack_so; /*!< \brief Number of segment offsets asked to be retransmitted by peer RLC entity. */
unsigned int num_nack_sn; /*!< \brief Number of segment asked to be retransmitted by peer RLC entity. */
boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */
//--------------------------------------------------------------------- //---------------------------------------------------------------------
...@@ -137,7 +135,7 @@ typedef struct rlc_am_entity_s { ...@@ -137,7 +135,7 @@ typedef struct rlc_am_entity_s {
//----------------------------- //-----------------------------
uint16_t max_retx_threshold; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to limit the number of retransmissions of an AMD PDU. */ uint16_t max_retx_threshold; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to limit the number of retransmissions of an AMD PDU. */
uint16_t poll_pdu; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollPDU PDUs. */ uint16_t poll_pdu; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollPDU PDUs. */
uint16_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */ uint32_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// STATISTICS // STATISTICS
...@@ -176,7 +174,7 @@ typedef struct rlc_am_entity_s { ...@@ -176,7 +174,7 @@ typedef struct rlc_am_entity_s {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// OUTPUTS // OUTPUTS
//--------------------------------------------------------------------- //---------------------------------------------------------------------
sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of bytes requested by lower layer for next transmission. */ sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of remaining bytes available for transmission of any RLC PDU indicated by lower layer */
list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */ list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */
list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */ list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */
rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */ rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */
......
...@@ -56,6 +56,8 @@ void rlc_am_free_in_sdu( ...@@ -56,6 +56,8 @@ void rlc_am_free_in_sdu(
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE;
} }
// TODO : this loop is useless as UL SDUs are transmitted and acknowledged in sequence
// even with PDCP UL SDU discard functionality
while ((rlcP->current_sdu_index != rlcP->next_sdu_index) && while ((rlcP->current_sdu_index != rlcP->next_sdu_index) &&
(rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) { (rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) {
rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE;
......
...@@ -55,7 +55,6 @@ void rlc_am_nack_pdu ( ...@@ -55,7 +55,6 @@ void rlc_am_nack_pdu (
int sdu_index; int sdu_index;
if (mb_p != NULL) { if (mb_p != NULL) {
rlc_pP->num_nack_sn += 1;
assert(so_startP <= so_endP); assert(so_startP <= so_endP);
//----------------------------------------- //-----------------------------------------
...@@ -69,10 +68,6 @@ void rlc_am_nack_pdu ( ...@@ -69,10 +68,6 @@ void rlc_am_nack_pdu (
rlc_am_clear_holes(ctxt_pP, rlc_pP, snP); rlc_am_clear_holes(ctxt_pP, rlc_pP, snP);
} }
if (!((so_startP == 0) && (so_endP == 0x7FFF))) {
rlc_pP->num_nack_so += 1;
}
rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP); rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP);
if (rlc_pP->first_retrans_pdu_sn < 0) { if (rlc_pP->first_retrans_pdu_sn < 0) {
...@@ -283,7 +278,7 @@ mem_block_t* rlc_am_retransmit_get_copy ( ...@@ -283,7 +278,7 @@ mem_block_t* rlc_am_retransmit_get_copy (
pdu_mngt->flags.retransmit = 0; pdu_mngt->flags.retransmit = 0;
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size); rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size,false);
return mb_copy; return mb_copy;
} else { } else {
return NULL; return NULL;
...@@ -745,7 +740,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( ...@@ -745,7 +740,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment(
return NULL; return NULL;
} }
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size); rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size,false);
return mb_sub_segment_p; return mb_sub_segment_p;
} else { } else {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n", LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n",
...@@ -843,10 +838,12 @@ void rlc_am_retransmit_any_pdu( ...@@ -843,10 +838,12 @@ void rlc_am_retransmit_any_pdu(
// no need for update rlc_pP->nb_bytes_requested_by_mac // no need for update rlc_pP->nb_bytes_requested_by_mac
pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn);
pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]);
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size); rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size,false);
pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; //BugFix: polling is checked and done in function above !
rlc_pP->c_pdu_without_poll = 0; //pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20;
rlc_pP->c_byte_without_poll = 0; //BugFix : pdu_without_poll and byte_without_poll are reset only if a Poll is transmitted
//rlc_pP->c_pdu_without_poll = 0;
//rlc_pP->c_byte_without_poll = 0;
//rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_data_pdu += 1;
...@@ -877,7 +874,7 @@ void rlc_am_retransmit_any_pdu( ...@@ -877,7 +874,7 @@ void rlc_am_retransmit_any_pdu(
rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF); rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF);
pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac); pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac);
pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]);
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size); rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size,false);
pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20;
rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_pdu_without_poll = 0;
rlc_pP->c_byte_without_poll = 0; rlc_pP->c_byte_without_poll = 0;
......
...@@ -39,7 +39,8 @@ void rlc_am_pdu_polling ( ...@@ -39,7 +39,8 @@ void rlc_am_pdu_polling (
const protocol_ctxt_t* const ctxt_pP, const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t *const rlc_pP, rlc_am_entity_t *const rlc_pP,
rlc_am_pdu_sn_10_t *const pdu_pP, rlc_am_pdu_sn_10_t *const pdu_pP,
const int16_t payload_sizeP) const int16_t payload_sizeP,
boolean_t is_new_pdu)
{ {
// 5.2.2 Polling // 5.2.2 Polling
// An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity. // An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity.
...@@ -68,41 +69,50 @@ void rlc_am_pdu_polling ( ...@@ -68,41 +69,50 @@ void rlc_am_pdu_polling (
// - start t-PollRetransmit; // - start t-PollRetransmit;
// - else: // - else:
// - restart t-PollRetransmit; // - restart t-PollRetransmit;
rlc_pP->c_pdu_without_poll += 1;
rlc_pP->c_byte_without_poll += payload_sizeP; if (is_new_pdu) {
if (rlc_pP->poll_pdu != RLC_AM_POLL_PDU_INFINITE) {
rlc_pP->c_pdu_without_poll += 1;
}
if (rlc_pP->poll_byte != RLC_AM_POLL_BYTE_INFINITE) {
rlc_pP->c_byte_without_poll += payload_sizeP;
}
}
if ( if (
(rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) || ((is_new_pdu) && ((rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) ||
(rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) || (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte))) ||
((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) || ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) ||
(rlc_pP->vt_s == rlc_pP->vt_ms) || (rlc_pP->vt_s == rlc_pP->vt_ms) ||
(rlc_pP->force_poll == TRUE) (rlc_pP->force_poll == true)
) { ) {
rlc_pP->force_poll = FALSE; rlc_pP->force_poll = false;
if (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) { if ((is_new_pdu) && (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu)) {
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM PDU THRESHOLD %d HAS BEEN REACHED\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM PDU THRESHOLD %d HAS BEEN REACHED\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->poll_pdu); rlc_pP->poll_pdu);
} else }
if (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) { if ((is_new_pdu) && (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte)) {
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM BYTES THRESHOLD %d HAS BEEN REACHED\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM BYTES THRESHOLD %d HAS BEEN REACHED\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->poll_byte); rlc_pP->poll_byte);
} else }
if ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) { if ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) {
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX BUFFERS ARE EMPTY\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX BUFFERS ARE EMPTY\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
} else }
if (rlc_pP->vt_s == rlc_pP->vt_ms) { if (rlc_pP->vt_s == rlc_pP->vt_ms) {
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE OF WINDOW STALLING\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE OF WINDOW STALLING\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
} }
pdu_pP->b1 = pdu_pP->b1 | 0x20; RLC_AM_PDU_SET_POLL(pdu_pP->b1);
rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_pdu_without_poll = 0;
rlc_pP->c_byte_without_poll = 0; rlc_pP->c_byte_without_poll = 0;
// vt_s shall have been updated before in case of new transmission
rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
//optimisation if (!rlc_pP->t_poll_retransmit.running) { //optimisation if (!rlc_pP->t_poll_retransmit.running) {
rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
...@@ -110,7 +120,8 @@ void rlc_am_pdu_polling ( ...@@ -110,7 +120,8 @@ void rlc_am_pdu_polling (
//optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out; //optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out;
//optimisation } //optimisation }
} else { } else {
pdu_pP->b1 = pdu_pP->b1 & 0xDF; // Not sure this is necessary
RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -178,7 +189,9 @@ void rlc_am_segment_10 ( ...@@ -178,7 +189,9 @@ void rlc_am_segment_10 (
if (rlc_pP->nb_sdu_no_segmented <= 1) { if (rlc_pP->nb_sdu_no_segmented <= 1) {
max_li_overhead = 0; max_li_overhead = 0;
} else { } else {
max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/
test_num_li = rlc_pP->nb_sdu_no_segmented - 1;
max_li_overhead = test_num_li + (test_num_li >> 1) + (test_num_li & 1);
} }
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] max_li_overhead %d\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] max_li_overhead %d\n",
...@@ -485,11 +498,11 @@ void rlc_am_segment_10 ( ...@@ -485,11 +498,11 @@ void rlc_am_segment_10 (
fi = fi + 1; fi = fi + 1;
} }
pdu_p->b1 = pdu_p->b1 | (fi << 3); pdu_p->b1 = pdu_p->b1 | (fi << RLC_AM_PDU_FI_OFFSET);
// set fist e bit // set fist e bit
if (fill_num_li > 0) { if (fill_num_li > 0) {
pdu_p->b1 = pdu_p->b1 | 0x04; RLC_AM_PDU_SET_E(pdu_p->b1);
} }
LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] SEND PDU SN %04d SIZE %d BYTES PAYLOAD SIZE %d BYTES\n", LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] SEND PDU SN %04d SIZE %d BYTES PAYLOAD SIZE %d BYTES\n",
...@@ -501,8 +514,9 @@ void rlc_am_segment_10 ( ...@@ -501,8 +514,9 @@ void rlc_am_segment_10 (
rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_data_pdu += 1;
rlc_pP->stat_tx_data_bytes += (data_pdu_size - pdu_remaining_size); rlc_pP->stat_tx_data_bytes += (data_pdu_size - pdu_remaining_size);
//pdu_p->sn = rlc_pP->vt_s; // set DATA/CONTROL field is DATA PDU(1)
pdu_p->b1 = pdu_p->b1 | 0x80; // DATA/CONTROL field is DATA PDU RLC_AM_PDU_SET_D_C(pdu_p->b1);
// set sn = rlc_pP->vt_s;
pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_s >> 8); pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_s >> 8);
pdu_p->b2 = rlc_pP->vt_s & 0xFF; pdu_p->b2 = rlc_pP->vt_s & 0xFF;
rlc_pP->vt_s = (rlc_pP->vt_s+1) & RLC_AM_SN_MASK; rlc_pP->vt_s = (rlc_pP->vt_s+1) & RLC_AM_SN_MASK;
...@@ -511,13 +525,14 @@ void rlc_am_segment_10 ( ...@@ -511,13 +525,14 @@ void rlc_am_segment_10 (
pdu_tb_req_p->tb_size = data_pdu_size - pdu_remaining_size; pdu_tb_req_p->tb_size = data_pdu_size - pdu_remaining_size;
//#warning "why 3000: changed to RLC_SDU_MAX_SIZE " //#warning "why 3000: changed to RLC_SDU_MAX_SIZE "
assert(pdu_tb_req_p->tb_size < RLC_SDU_MAX_SIZE ); assert(pdu_tb_req_p->tb_size < RLC_SDU_MAX_SIZE );
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size); rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size,true);
//list_add_tail_eurecom (pdu_mem_p, &rlc_pP->segmentation_pdu_list); //list_add_tail_eurecom (pdu_mem_p, &rlc_pP->segmentation_pdu_list);
pdu_mngt_p->mem_block = pdu_mem_p; pdu_mngt_p->mem_block = pdu_mem_p;
pdu_mngt_p->first_byte = (unsigned char*)pdu_p; pdu_mngt_p->first_byte = (unsigned char*)pdu_p;
pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size; pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size;
pdu_mngt_p->retx_count = -1; pdu_mngt_p->retx_count = -1;
pdu_mngt_p->flags.transmitted = 1;
rlc_pP->retrans_num_pdus += 1; rlc_pP->retrans_num_pdus += 1;
rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size; rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size;
......
...@@ -51,14 +51,14 @@ ...@@ -51,14 +51,14 @@
# endif # endif
# endif # endif
/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP) /*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu)
* \brief Set or not the poll bit in the PDU header depending on RLC AM protocol variables. * \brief Set or not the poll bit in the PDU header depending on RLC AM protocol variables.
* \param[in] ctxt_pP Running context. * \param[in] ctxt_pP Running context.
* \param[in] rlcP RLC AM protocol instance pointer. * \param[in] rlcP RLC AM protocol instance pointer.
* \param[in] pduP Pointer on the header of the PDU in order to be able to set the poll bit if necessary. * \param[in] pduP Pointer on the header of the PDU in order to be able to set the poll bit if necessary.
* \param[in] payload_sizeP Size of the payload of the PDU. * \param[in] payload_sizeP Size of the payload of the PDU.
*/ */
protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP);) protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu);)
/*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlcP) /*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlcP)
* \brief Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit). * \brief Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit).
......
...@@ -309,8 +309,6 @@ rlc_am_receive_process_control_pdu( ...@@ -309,8 +309,6 @@ rlc_am_receive_process_control_pdu(
assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU); assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU);
if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) { if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) {
rlc_pP->num_nack_so = 0;
rlc_pP->num_nack_sn = 0;
if (rlc_pP->control_pdu_info.num_nack == 0) { if (rlc_pP->control_pdu_info.num_nack == 0) {
while (sn_cursor != ack_sn) { while (sn_cursor != ack_sn) {
...@@ -462,7 +460,6 @@ rlc_am_send_status_pdu( ...@@ -462,7 +460,6 @@ rlc_am_send_status_pdu(
mem_block_t *tb_p = NULL; mem_block_t *tb_p = NULL;
sdu_size_t pdu_size = 0; sdu_size_t pdu_size = 0;
boolean_t status_report_completed = false; boolean_t status_report_completed = false;
boolean_t lsf_received = false;
boolean_t segment_loop_end = false; boolean_t segment_loop_end = false;
memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t)); memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t));
...@@ -479,30 +476,20 @@ rlc_am_send_status_pdu( ...@@ -479,30 +476,20 @@ rlc_am_send_status_pdu(
control_pdu_info.ack_sn = rlc_pP->vr_ms; control_pdu_info.ack_sn = rlc_pP->vr_ms;
status_report_completed = true; status_report_completed = true;
#if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d ALL ACK WITH ACK_SN %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
__LINE__,
rlc_pP->vr_ms);
#endif
} }
else if (cursor_p != NULL) { else if ((cursor_p != NULL) && ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)) <= nb_bits_to_transmit)) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
sn_cursor = pdu_info_cursor_p->sn; sn_cursor = pdu_info_cursor_p->sn;
// Not very clear why this is needed /* Set E1 bit for the presence of first NACK_SN/E1/E2 */
// commenting control_pdu_info.e1 = 1;
#if 0
while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) {
cursor_p = cursor_p->next;
previous_sn_cursor = sn_cursor;
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
sn_cursor = pdu_info_cursor_p->sn;
#if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d FIND VR(R) <= SN sn_cursor %04d -> %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
__LINE__,
previous_sn_cursor,
sn_cursor);
#endif
}
#endif
// 12 bits = size of NACK_SN field + E1, E2 bits // 12 bits = size of NACK_SN field + E1, E2 bits
// 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits // 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits
...@@ -512,20 +499,17 @@ rlc_am_send_status_pdu( ...@@ -512,20 +499,17 @@ rlc_am_send_status_pdu(
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
sn_cursor = pdu_info_cursor_p->sn; sn_cursor = pdu_info_cursor_p->sn;
all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received; all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;
// E1 bit is set at the end
/* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */ /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */
while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) { while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) {
if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) { if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) {
/* Fill NACK_SN infos */ /* Fill NACK_SN infos */
if (control_pdu_info.num_nack) {
/* Set E1 of previous NACK_SN */
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1;
}
control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack; control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 0; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 0;
/* Set E1 for next NACK_SN. The last one will be cleared */
control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1;
control_pdu_info.num_nack += 1; control_pdu_info.num_nack += 1;
nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1));
#if TRACE_RLC_AM_STATUS_CREATION #if TRACE_RLC_AM_STATUS_CREATION
...@@ -541,45 +525,52 @@ rlc_am_send_status_pdu( ...@@ -541,45 +525,52 @@ rlc_am_send_status_pdu(
/* latest value of sn_nack shall be used as ACK_SN */ /* latest value of sn_nack shall be used as ACK_SN */
control_pdu_info.ack_sn = sn_nack; control_pdu_info.ack_sn = sn_nack;
status_report_completed = true; status_report_completed = true;
#if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NOT ENOUGH TBS STOP WITH ACK_SN %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
__LINE__,
sn_nack);
#endif
break; break;
} }
} }
/* Now process all Segments of sn_cursor if PDU not fully received */ /* Now process all Segments of sn_cursor if PDU not fully received */
if ((!status_report_completed) && (all_segments_received == 0) && (sn_nack != rlc_pP->vr_ms)) { if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) {
AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id); AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id);
/* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */ /* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */
if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
/* Set E1 of previous NACK_SN */
if (control_pdu_info.num_nack) {
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1;
}
/* Init loop flags */ /* Init loop flags */
lsf_received = false; /* Check lsf */
segment_loop_end = false; segment_loop_end = (pdu_info_cursor_p->lsf == 1);
/* Init first SO Start according to first segment */ /* Init first SO Start according to first segment */
if (pdu_info_cursor_p->so) { if (pdu_info_cursor_p->so) {
waited_so = 0;
/* Fill the first SO */ /* Fill the first SO */
control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1;
control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1;
/* Set E1 for next NACK_SN. The last one will be cleared */
control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1;
control_pdu_info.num_nack += 1; control_pdu_info.num_nack += 1;
nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
#if TRACE_RLC_AM_STATUS_CREATION #if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
__LINE__, __LINE__,
previous_sn_cursor, sn_cursor,
waited_so, 0,
0x7FFF); pdu_info_cursor_p->so - 1);
#endif #endif
waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
/* Go to next segment */ /* Go to next segment */
cursor_p = cursor_p->next; cursor_p = cursor_p->next;
if (cursor_p != NULL)
{
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
} }
else { else {
waited_so = pdu_info_cursor_p->payload_size; waited_so = pdu_info_cursor_p->payload_size;
...@@ -587,79 +578,73 @@ rlc_am_send_status_pdu( ...@@ -587,79 +578,73 @@ rlc_am_send_status_pdu(
/* Find the first discontinuity and then fill SOStart/SOEnd */ /* Find the first discontinuity and then fill SOStart/SOEnd */
while (!segment_loop_end) { while (!segment_loop_end) {
if (cursor_p != NULL) { if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; /* PDU segment is for the same SN*/
/* Check lsf */
if (pdu_info_cursor_p->sn == sn_cursor) { segment_loop_end = (pdu_info_cursor_p->lsf == 1);
/* PDU segment is for the same SN*/
if (waited_so < pdu_info_cursor_p->so) { if (waited_so < pdu_info_cursor_p->so) {
/* SO is greater than previous received portion : gap identified to fill */ /* SO is greater than previous received portion : gap identified to fill */
if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
/* Set E1 of previous NACK_SN */ control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor;
if (control_pdu_info.num_nack) { control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so;
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so;
} control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1;
/* Set E1 for next NACK_SN. The last one will be cleared */
control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; control_pdu_info.num_nack += 1;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so; nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; #if TRACE_RLC_AM_STATUS_CREATION
control_pdu_info.num_nack += 1; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n",
nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
} __LINE__,
else { sn_cursor,
/* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ waited_so,
control_pdu_info.ack_sn = sn_cursor; pdu_info_cursor_p->so);
status_report_completed = true; #endif
segment_loop_end = true; }
break; else {
} /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
control_pdu_info.ack_sn = sn_cursor;
} status_report_completed = true;
else { segment_loop_end = true;
/* Assuming so and payload_size updated according to duplication removal done at reception ... */ break;
waited_so += pdu_info_cursor_p->payload_size; }
} }
else {
} //end if (pdu_info_cursor_p->sn == sn_cursor) /* contiguous segment: only update waited_so */
else if (!lsf_received) { /* Assuming so and payload_size updated according to duplication removal done at reception ... */
/* We just switched to next SN, fill last gap if not end received */ waited_so += pdu_info_cursor_p->payload_size;
if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { }
/* Set E1 of previously received NACK */
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; /* Go to next received PDU or PDU Segment */
control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; cursor_p = cursor_p->next;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; if (cursor_p != NULL)
control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; {
control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
control_pdu_info.num_nack += 1; }
nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
} } //end if (cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)
else { else {
/* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ /* Previous PDU segment was the last one and did not have lsf indication : fill the latest gap */
control_pdu_info.ack_sn = sn_cursor;
status_report_completed = true;
}
segment_loop_end = true;
continue; //in order not to go to next cursor
} // end if (!lsf_received)
/* Go to next received PDU or PDU Segment */
cursor_p = cursor_p->next;
} //end if (cursor_p != NULL)
else if (!lsf_received) {
/* Previous PDU segment was the last one and had lsf indication : fill the latest gap */
if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
/* Set E1 of previously received NACK */
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1;
control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so;
control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1;
/* Set E1 for next NACK_SN. The last one will be cleared */
control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1;
control_pdu_info.num_nack += 1; control_pdu_info.num_nack += 1;
nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
#if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING LAST NACK %04d SO START %05d SO END %05d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
__LINE__,
sn_cursor,
waited_so,
RLC_AM_STATUS_PDU_SO_END_ALL_BYTES);
#endif
} }
else { else {
/* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
...@@ -677,16 +662,23 @@ rlc_am_send_status_pdu( ...@@ -677,16 +662,23 @@ rlc_am_send_status_pdu(
control_pdu_info.ack_sn = sn_nack; control_pdu_info.ack_sn = sn_nack;
status_report_completed = true; status_report_completed = true;
} }
} // end while on all PDU segments of sn_cursor
else {
/* Go to next received PDU or PDU segment if sn_cursor is fully received */
cursor_p = cursor_p->next;
} }
/* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */
if ((sn_nack != rlc_pP->vr_ms) && (all_segments_received)) { if (sn_nack != rlc_pP->vr_ms) {
sn_nack = RLC_AM_NEXT_SN(sn_nack); sn_nack = RLC_AM_NEXT_SN(sn_cursor);
cursor_p = cursor_p->next;
} }
} } // End main while NACK_SN
/* Clear E1 of last nack_sn entry */
AssertFatal (control_pdu_info.num_nack, "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id);
control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0;
/* Set ACK_SN unless it was set before */ /* Set ACK_SN unless it was set before */
if (!status_report_completed){ if (!status_report_completed){
...@@ -694,12 +686,8 @@ rlc_am_send_status_pdu( ...@@ -694,12 +686,8 @@ rlc_am_send_status_pdu(
control_pdu_info.ack_sn = sn_nack; control_pdu_info.ack_sn = sn_nack;
} }
if (control_pdu_info.num_nack) {
control_pdu_info.e1 = 1;
}
} else { } else {
/* reception buffer empty or not enough TBS for filling at least 1 NACK_SN + E1 + E2 */
control_pdu_info.ack_sn = rlc_pP->vr_r; control_pdu_info.ack_sn = rlc_pP->vr_r;
#if TRACE_RLC_AM_STATUS_CREATION #if TRACE_RLC_AM_STATUS_CREATION
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d = VR(R)\n", LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d = VR(R)\n",
......
...@@ -88,9 +88,12 @@ typedef struct rlc_am_tx_sdu_management { ...@@ -88,9 +88,12 @@ typedef struct rlc_am_tx_sdu_management {
* \brief Structure containing PDU variables related to its retransmission. * \brief Structure containing PDU variables related to its retransmission.
*/ */
typedef struct pdu_management_flags { typedef struct pdu_management_flags {
uint8_t transmitted:1; /*!< \brief Boolean telling that this PDU is not empty and has been at least transmitted once. */
uint8_t ack:1; /*!< \brief Boolean telling that this PDU has been acknowledged. */ uint8_t ack:1; /*!< \brief Boolean telling that this PDU has been acknowledged. */
uint8_t nack:1; /*!< \brief Boolean telling that this PDU has been acknowledged negatively. */
uint8_t retransmit:1; /*!< \brief Boolean telling a retransmission is scheduled for this PDU. */ uint8_t retransmit:1; /*!< \brief Boolean telling a retransmission is scheduled for this PDU. */
uint8_t dummy:6; /*!< \brief Free bits. */ uint8_t max_retransmit:1; /*!< \brief Boolean telling max retransmission has been hit for this PDU. */
uint8_t dummy:3; /*!< \brief Free bits. */
} pdu_management_flags_t; } pdu_management_flags_t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment