- Fix: avoid infinite loop on mulitcast read thread if no data to read
Pre-ci test passed git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4000 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
Executable
+103
@@ -0,0 +1,103 @@
|
||||
CC = gcc
|
||||
|
||||
SSE3PROC = $(shell echo `grep ssse3 /proc/cpuinfo`)
|
||||
SSE4PROC = $(shell echo `grep sse4 /proc/cpuinfo`)
|
||||
CPUFLAGS = -mmmx -msse -msse2 -m32 -mssse3 #-msse4
|
||||
CPUFLAGS += $(shell if [ -z $$SSE3PROC]; then echo "" ; else echo "-mssse3"; fi)
|
||||
CPUFLAGS += $(shell if [ -z $$SSE4PROC]; then echo "" ; else echo "-msse4"; fi)
|
||||
cygwin = $(shell if [ $$OSTYPE = "cygwin" ] ; then echo "1" ; else echo "0" ; fi)
|
||||
|
||||
TOP_DIR = $(OPENAIR1_DIR)
|
||||
OPENAIR1_TOP = $(OPENAIR1_DIR)
|
||||
OPENAIR2_TOP = $(OPENAIR2_DIR)
|
||||
OPENAIR3_TOP = $(OPENAIR3_DIR)
|
||||
OPENAIR3 = $(OPENAIR3_DIR)
|
||||
|
||||
EXE_FILE_NAME = test_pdcp
|
||||
|
||||
CFLAGS = -Wall -fno-strict-aliasing -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -g -ggdb $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat
|
||||
|
||||
ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES
|
||||
|
||||
CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE
|
||||
CFLAGS += -I/usr/include/libxml2 -lxml2
|
||||
|
||||
#CFLAGS += -DXFORMS
|
||||
|
||||
ifdef DEBUG_PHY
|
||||
CFLAGS += -DDEBUG_PHY
|
||||
endif
|
||||
|
||||
ifdef NAS_NETLINK
|
||||
CFLAGS += -DNAS_NETLINK -DLINUX -DDEBUG_CONTROL
|
||||
endif
|
||||
|
||||
CFLAGS += -DPHY_ABSTRACTION #-DEMIT_ASN_DEBUG=1
|
||||
CFLAGS += $(shell if [ $$OSTYPE = "cygwin" ] ; then echo "-DCYGWIN" ; fi)
|
||||
|
||||
#include $(OPENAIR1_DIR)/PHY/Makefile.inc
|
||||
#include $(OPENAIR1_DIR)/SCHED/Makefile.inc
|
||||
|
||||
EXTRA_CFLAGS += -DOPENAIR2
|
||||
EXTRA_CFLAGS += -DASSERT
|
||||
EXTRA_CFLAGS += -DNO_RRM
|
||||
|
||||
COMMON_DIR = $(OPENAIR2_TOP)/COMMON
|
||||
L2_INTERFACE_DIR = $(OPENAIR2_TOP)/RRC/L2_INTERFACE
|
||||
RLC_UM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/UM_v9.3.0
|
||||
RLC_AM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/AM_v9.3.0
|
||||
RLC_TM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/TM
|
||||
RLC_DIR = $(OPENAIR2_TOP)/LAYER2/RLC
|
||||
PDCP_DIR = $(OPENAIR2_TOP)/LAYER2/PDCP_v10.1.0
|
||||
MEM_DIR = $(OPENAIR2_TOP)/UTIL/MEM
|
||||
LIST_DIR = $(OPENAIR2_TOP)/UTIL/LISTS
|
||||
MATH_DIR = $(OPENAIR2_TOP)/UTIL/MATH
|
||||
TIMER_DIR = $(OPENAIR2_TOP)/UTIL/TIMER
|
||||
PHY_INTERFACE_DIR = $(OPENAIR2_TOP)/PHY_INTERFACE
|
||||
RRC_DIR = $(OPENAIR2_TOP)/RRC/LITE
|
||||
L2_INTERFACE_DIR = $(OPENAIR2_TOP)/RRC/L2_INTERFACE
|
||||
MAC_DIR = $(OPENAIR2_TOP)/LAYER2/MAC
|
||||
LOG_DIR=$(OPENAIR2_TOP)/UTIL/LOG
|
||||
OCG_DIR=$(OPENAIR2_TOP)/UTIL/OCG
|
||||
OPT_DIR=$(OPENAIR2_TOP)/UTIL/OPT
|
||||
|
||||
SOURCES_L2 = $(LIST_DIR)/list.c
|
||||
SOURCES_L2 += $(LIST_DIR)/list2.c
|
||||
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp.c
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp_primitives.c
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp_sequence_manager.c
|
||||
|
||||
SOURCES_L2 += $(MEM_DIR)/mem_block.c
|
||||
|
||||
LOG_OBJS = $(LOG_DIR)/log.o
|
||||
OPT_OBJS = $(OPT_DIR)/probe.o
|
||||
|
||||
L2_OBJS=$(addsuffix .o,$(basename $(SOURCES_L2))) $(PHY_INTERFACE_OBJS) $(MAC_OBJS) $(L2_INTERFACE_OBJS) $(RRC_OBJS) $(LOG_OBJS) $(OPT_OBJS)
|
||||
|
||||
L2_incl = -I$(OPENAIR2_TOP) -I$(COMMON_DIR) -I$(RLC_DIR) -I$(RLC_AM_DIR) -I$(RLC_UM_DIR) -I$(RLC_TM_DIR) -I$(PDCP_DIR) -I$(MEM_DIR) -I$(LIST_DIR) \
|
||||
-I$(LOG_DIR) -I$(MATH_DIR) -I$(TIMER_DIR) -I$(OPENAIR3)/MESH -I$(OPENAIR2_TOP)/RRC/MESH -I$(OPENAIR2_TOP)/RRC/MESH/MESSAGES -I$(OPENAIR3)/MESH/RRM -I$(OPT_DIR) \
|
||||
-I$(OCG_DIR)
|
||||
|
||||
ASN1_MSG_OBJS2 := $(foreach file, $(ASN1_MSG_OBJS), $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/$(file))
|
||||
|
||||
# Define object file directory for RLM code
|
||||
RLC_OBJ_DIR = $(RLC_DIR)/*.o $(RLC_AM_DIR)/*.o $(RLC_UM_DIR)/*.o $(RLC_TM_DIR)/*.o
|
||||
|
||||
OBJ = $(PHY_OBJS) $(SIMULATION_OBJS) $(SCHED_OBJS) $(STATS_OBJS) $(ASN1_MSG_OBJS2) $(RLC_OBJ_DIR)
|
||||
|
||||
all: build_test_pdcp
|
||||
|
||||
$(OBJ) : %.o : %.c
|
||||
$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -DPHY_CONTEXT=1 -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $@ $<
|
||||
|
||||
$(L2_OBJS) : %.o : %.c
|
||||
$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $@ $<
|
||||
|
||||
build_test_pdcp : $(OBJ) $(L2_OBJS) test_pdcp.c
|
||||
echo CYGWIN variable is $(cygwin)
|
||||
$(CC) test_pdcp.c -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $(EXE_FILE_NAME) $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(L2_OBJS) -lm -lcurses
|
||||
|
||||
clean:
|
||||
rm -f test_pdcp
|
||||
rm -f *.o
|
||||
@@ -0,0 +1,184 @@
|
||||
/*******************************************************************************
|
||||
|
||||
OPENAIRINTERFACE 0/1/2/3
|
||||
Copyright(c) 1999 - 2011 EURECOM
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information:
|
||||
Openair Admin <openair_admin@eurecom.fr>
|
||||
Mailing List <openair_tech@eurecom.fr>
|
||||
Forums http://forums.eurecom.fr/openairinterface
|
||||
Eurecom, 2229, route des cretes, 06560 Valbonne Sophia Antipolis, France
|
||||
|
||||
*******************************************************************************/
|
||||
/*________________________OEPNAIR/OPENAIR0/________________________
|
||||
|
||||
File : readme.txt
|
||||
Authors : Baris Demiray
|
||||
Company : EURECOM
|
||||
Emails : baris.demiray@eurecom.fr
|
||||
________________________________________________________________*/
|
||||
|
||||
|
||||
-----------------
|
||||
Table of contents
|
||||
-----------------
|
||||
|
||||
The content of this readme is the following:
|
||||
|
||||
1) What is this block about in OpenAirInterface
|
||||
2) Folders and files description
|
||||
3) Organization of the folders and their dependancies
|
||||
4) Makefile targets and how to build
|
||||
4.1) NUMBER_OF_TEST_PACKETS
|
||||
4.2) WINDOW_SIZE
|
||||
4.3) TEST_RX_AND_TX_WINDOW
|
||||
4.4) TEST_PDCP_DATA_REQUEST_AND_INDICATION
|
||||
5) Compilation and running
|
||||
6) How to use through a tutorial: run a simple experimentation
|
||||
|
||||
------------------------------------------------
|
||||
1) What is this block about in OpenAirInterface?
|
||||
------------------------------------------------
|
||||
|
||||
Code residing here is the test code for PDCP, particularly the
|
||||
sequence numbering code, pdcp_data_req(), and pdcp_data_ind().
|
||||
|
||||
Sequence numbering code is at pdcp_sequence_number.{c|h}, pdcp_data_req()
|
||||
and pdcp_data_ind() methods are in pdcp.{c|h}, all residing in PDCP_v10.1.0
|
||||
directory at openair2/LAYER2/.
|
||||
|
||||
Normally, PDCP layer is in interaction with following layers,
|
||||
|
||||
|
||||
+-----------+ +-----+
|
||||
| IP Driver | | RRC |
|
||||
+-----------+ +-----+
|
||||
\ /
|
||||
+--------+
|
||||
| PDCP |
|
||||
+--------+
|
||||
|
|
||||
+-----+
|
||||
| RRC |
|
||||
+-----+
|
||||
|
||||
But in this test PDCP is isolated (by the symbolic constant
|
||||
PDCP_UNIT_TEST, defined in LAYER2/PDCP_v10.1.0/pdcp.h) from the rest of the
|
||||
layers and tested on its own.
|
||||
|
||||
There are two different tests. First is for sequence numbers and the other is
|
||||
for PDUs and relevant headers.
|
||||
|
||||
All the sections referred herein should be looked in 3GPP TS 36.323 V10.1.0
|
||||
(2011-03).
|
||||
|
||||
--------------------------------
|
||||
2) Folders and files description
|
||||
--------------------------------
|
||||
|
||||
File/Folder Description
|
||||
----------- -----------
|
||||
|
||||
- Makefile Build targets are `all` and `clean`
|
||||
- test_pdcp.{c|h} Test code
|
||||
- test_util.h Utility methods for debugging
|
||||
- todo.txt Todo list
|
||||
- with_rlc/ Test code to validate interface between PDCP and RLC
|
||||
(written by Lionel)
|
||||
|
||||
-----------------------------------------------------
|
||||
3) Organization of the folders and their dependancies
|
||||
-----------------------------------------------------
|
||||
|
||||
There is only one subfolder named `with_rlc/` and it has no dependency with
|
||||
other test code and has its own Makefile.
|
||||
|
||||
-------------------------------------
|
||||
4) Makefile targets and how to build
|
||||
-------------------------------------
|
||||
|
||||
There is only one build target named `build_test_pdcp` and it can be run
|
||||
also through the target `all`.
|
||||
|
||||
To configure, there is a number of symbolic constants in test_pdcp.c.
|
||||
|
||||
---------------------------
|
||||
4.1) NUMBER_OF_TEST_PACKETS
|
||||
---------------------------
|
||||
|
||||
NUMBER_OF_TEST_PACKETS configures the number of packets that are to be
|
||||
generated during the tests. For TX/RX window tests this is directly the
|
||||
number of sequence numbers generated. For SDU test this constant determines
|
||||
the number of packets passed to pdcp_data_req() (by test_pdcp_data_req()).
|
||||
Then PDUs generated by PDCP are collected in a linked list and passed to
|
||||
pdcp_data_ind() (by test_pdcp_data_ind()) for validation.
|
||||
|
||||
This value is currently set to 10000.
|
||||
|
||||
----------------
|
||||
4.2) WINDOW_SIZE
|
||||
----------------
|
||||
|
||||
This symbolic constant configures TX and RX window size.
|
||||
|
||||
Currently this value is set to 4096 in accordance with the size of sequence
|
||||
number field (12 bits, see 6.2.3).
|
||||
|
||||
--------------------------
|
||||
4.3) TEST_RX_AND_TX_WINDOW
|
||||
--------------------------
|
||||
|
||||
Currently PDCP tests are performed either for TX/RX window or for PDUs
|
||||
because PDCP states are not reset inbetween two tests. If this constant is
|
||||
defined then only TX/RX tests are performed generating NUMBER_OF_TEST_PACKETS
|
||||
packets.
|
||||
|
||||
Warning: If this and TEST_PDCP_DATA_REQUEST_AND_INDICATION are both defined
|
||||
then secondly run test will fail.
|
||||
|
||||
------------------------------------------
|
||||
4.4) TEST_PDCP_DATA_REQUEST_AND_INDICATION
|
||||
------------------------------------------
|
||||
|
||||
Currently PDCP tests are performed either for TX/RX window or for PDUs
|
||||
because PDCP states are not reset inbetween two tests. If this constant is
|
||||
defined then only PDU test is performed generating NUMBER_OF_TEST_PACKETS
|
||||
packets.
|
||||
|
||||
Warning: If this and TEST_RX_AND_TX_WINDOW are both defined then secondly run
|
||||
test will fail.
|
||||
|
||||
--------------------------
|
||||
5) Compilation and running
|
||||
--------------------------
|
||||
|
||||
Since default target is `all` following command suffices,
|
||||
|
||||
$ make
|
||||
|
||||
To run,
|
||||
|
||||
$ ./test_pdcp
|
||||
|
||||
---------------------------------------------------------------
|
||||
6) How to use through a tutorial: run a simple experimentation
|
||||
---------------------------------------------------------------
|
||||
|
||||
Not applicable, see section 5.
|
||||
|
||||
Executable
+394
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* PDCP test code
|
||||
*
|
||||
* Author: Baris Demiray <baris.demiray@eurecom.fr>
|
||||
*/
|
||||
|
||||
#include "MAC_INTERFACE/vars.h"
|
||||
#include "LAYER2/MAC/vars.h"
|
||||
#include "UTIL/LOG/log_if.h"
|
||||
#include "OCG_vars.h"
|
||||
#include "test_util.h"
|
||||
#include "test_pdcp.h"
|
||||
|
||||
/*
|
||||
* These are the PDCP entities that will be utilised
|
||||
* throughout the test
|
||||
*
|
||||
* For pdcp_data_req() and pdcp_data_ind() these
|
||||
* are passed and used
|
||||
*/
|
||||
pdcp_t pdcp_array[2];
|
||||
|
||||
/*
|
||||
* TX list is the one we use to receive PDUs created by pdcp_data_req() and
|
||||
* RX list is the one we use to pass these PDUs to pdcp_data_ind(). In test_pdcp_data_req()
|
||||
* method every PDU created by pdcp_data_req() are first validated and then added to RX
|
||||
* list after it's removed from TX list
|
||||
*/
|
||||
list_t test_pdu_tx_list;
|
||||
list_t test_pdu_rx_list;
|
||||
|
||||
/*
|
||||
* This is used by a number of methods to determine how
|
||||
* many times a packet should be generated/a test run
|
||||
*/
|
||||
#define NUMBER_OF_TEST_PACKETS 10000
|
||||
/*
|
||||
* This is determined by the size of Sequence Number
|
||||
* field and used to check sequence number synchronisation
|
||||
*/
|
||||
#define WINDOW_SIZE 4096 // 12-bit SN
|
||||
|
||||
/*
|
||||
* Test configuration is STATEFUL. If you want to run DATA_REQUEST after TX_WINDOW
|
||||
* then you have to reset/reinitialize PDCP entity state!
|
||||
*
|
||||
* TEST_RX_AND_TX_WINDOW Tests TX window code by repetitively asking for new TX
|
||||
* sequence numbers without generating any packets
|
||||
* And tests RX window code by supplying sequenced RX sequence
|
||||
* numbers and asking RX window code to validate, without
|
||||
* generating any packets
|
||||
*/
|
||||
#define TEST_RX_AND_TX_WINDOW 0
|
||||
/*
|
||||
* TEST_PDCP_DATA_REQUEST_AND_INDICATION Tests pdcp_data_req() method by repetitively asking it
|
||||
* to create a PDCP PDU out of supplied SDU and parsing
|
||||
* particular fields of relevant PDU lateron
|
||||
* Afterwards, those PDUs created by pdcp_data_req() are
|
||||
* passed to pdcp_data_ind()
|
||||
*/
|
||||
#define TEST_PDCP_DATA_REQUEST_AND_INDICATION 1
|
||||
|
||||
/*
|
||||
* Buffer content used for testing purposes
|
||||
*/
|
||||
#define DUMMY_BUFFER ((unsigned char*)"123456789")
|
||||
#define DUMMY_BUFFER_SIZE 10
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned char index = 0;
|
||||
unsigned char test_result = 0;
|
||||
|
||||
/*
|
||||
* Initialize memory allocator, list_t for test PDUs, and log generator
|
||||
*/
|
||||
pool_buffer_init();
|
||||
list_init(&test_pdu_tx_list, NULL);
|
||||
list_init(&test_pdu_rx_list, NULL);
|
||||
logInit();
|
||||
|
||||
if (init_pdcp_entity(&pdcp_array[0]) == TRUE && init_pdcp_entity(&pdcp_array[1]) == TRUE)
|
||||
msg("[TEST] PDCP entity initialization OK\n");
|
||||
else {
|
||||
msg("[TEST] Cannot initialize PDCP entities!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize PDCP state variables */
|
||||
for (index = 0; index < 2; ++index) {
|
||||
if (pdcp_init_seq_numbers(&pdcp_array[index]) == FALSE) {
|
||||
msg("[TEST] Cannot initialize sequence numbers of PDCP entity %d!\n", index);
|
||||
exit(1);
|
||||
} else {
|
||||
msg("[TEST] Sequence number state of PDCP entity %d is initialized\n", index);
|
||||
}
|
||||
}
|
||||
|
||||
#if TEST_RX_AND_TX_WINDOW
|
||||
/* Test TX window */
|
||||
if (test_tx_window() == FALSE)
|
||||
test_result = 1;
|
||||
|
||||
/* Test RX window */
|
||||
if (test_rx_window() == FALSE)
|
||||
test_result = 1;
|
||||
#endif
|
||||
|
||||
#if TEST_PDCP_DATA_REQUEST_AND_INDICATION
|
||||
/* Test pdcp_data_req() method in pdcp.c */
|
||||
if (test_pdcp_data_req() == FALSE)
|
||||
test_result = 1;
|
||||
|
||||
/* Test pdcp_data_ind() method in pdcp.c */
|
||||
if (test_pdcp_data_ind() == FALSE)
|
||||
test_result = 1;
|
||||
#endif
|
||||
|
||||
if (test_result) {
|
||||
msg("\n\nOne or more tests failed!\n");
|
||||
} else {
|
||||
msg("\n\nAll tests are successfull!\n");
|
||||
}
|
||||
|
||||
return test_result;
|
||||
}
|
||||
|
||||
BOOL init_pdcp_entity(pdcp_t *pdcp_entity)
|
||||
{
|
||||
if (pdcp_entity == NULL)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Initialize sequence number state variables of relevant PDCP entity
|
||||
*/
|
||||
pdcp_entity->next_pdcp_tx_sn = 0;
|
||||
pdcp_entity->next_pdcp_rx_sn = 0;
|
||||
pdcp_entity->tx_hfn = 0;
|
||||
pdcp_entity->rx_hfn = 0;
|
||||
/* SN of the last PDCP SDU delivered to upper layers */
|
||||
pdcp_entity->last_submitted_pdcp_rx_sn = 4095;
|
||||
pdcp_entity->seq_num_size = 12;
|
||||
|
||||
msg("PDCP entity is initialized: Next TX: %d, Next Rx: %d, TX HFN: %d, RX HFN: %d, " \
|
||||
"Last Submitted RX: %d, Sequence Number Size: %d\n", pdcp_entity->next_pdcp_tx_sn, \
|
||||
pdcp_entity->next_pdcp_rx_sn, pdcp_entity->tx_hfn, pdcp_entity->rx_hfn, \
|
||||
pdcp_entity->last_submitted_pdcp_rx_sn, pdcp_entity->seq_num_size);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL test_tx_window()
|
||||
{
|
||||
unsigned long index = 0;
|
||||
|
||||
for (index = 0; index < NUMBER_OF_TEST_PACKETS; ++index) {
|
||||
u16 pseudo_tx_sn = pdcp_get_next_tx_seq_number(&pdcp_array[0]);
|
||||
if (pseudo_tx_sn == index % WINDOW_SIZE)
|
||||
msg("TX packet # %07lu seq # %04d hfn # %04d\n", index, pseudo_tx_sn, pdcp_array[0].tx_hfn);
|
||||
else {
|
||||
msg("TX packet is out-of-window!\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL test_rx_window()
|
||||
{
|
||||
unsigned long index = 0;
|
||||
|
||||
for (index = 0; index < NUMBER_OF_TEST_PACKETS; ++index) {
|
||||
u16 pseudo_rx_sn = (index == 0) ? 0 : index % WINDOW_SIZE;
|
||||
if (pdcp_is_rx_seq_number_valid(pseudo_rx_sn, &pdcp_array[1]) == TRUE) {
|
||||
msg("RX packet # %07lu seq # %04d last-submitted # %04d hfn # %04d\n", \
|
||||
index, pdcp_array[1].next_pdcp_rx_sn, pdcp_array[1].last_submitted_pdcp_rx_sn, pdcp_array[1].rx_hfn);
|
||||
} else {
|
||||
msg("RX packet seq # %04lu is not valid!\n", index);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL test_pdcp_data_req()
|
||||
{
|
||||
unsigned char* pdcp_test_pdu_buffer = NULL;
|
||||
unsigned char pdcp_test_pdu_buffer_size = DUMMY_BUFFER_SIZE + PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE;
|
||||
unsigned int index = 0;
|
||||
|
||||
/*
|
||||
* Create an unsigned char buffer out of mem_block_t
|
||||
*/
|
||||
pdcp_test_pdu_buffer = (unsigned char*) calloc(1, pdcp_test_pdu_buffer_size);
|
||||
if (pdcp_test_pdu_buffer == NULL) {
|
||||
msg("Cannot allocate a buffer for test!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask PDCP to handle a number of data requests
|
||||
*/
|
||||
for (index = 0; index < NUMBER_OF_TEST_PACKETS; ++index) {
|
||||
msg("\n\nAsking PDCP to send %d/%d SDU...\n", index+1, NUMBER_OF_TEST_PACKETS);
|
||||
|
||||
/*
|
||||
* Reset test pdu buffer for every run
|
||||
*/
|
||||
memset(pdcp_test_pdu_buffer, 0x00, pdcp_test_pdu_buffer_size);
|
||||
|
||||
/*
|
||||
* Ask PDCP to create a PDU with given buffer and enqueue it to `test_pdu_tx_list`
|
||||
*/
|
||||
if (pdcp_data_req(0, 0, 10, DUMMY_BUFFER, &pdcp_array[0], &test_pdu_tx_list) == TRUE) {
|
||||
msg("[TEST] Starting to dissect PDU created by PDCP...\n");
|
||||
|
||||
/*
|
||||
* XXX mem_block_t doesn't hold buffer size, how do we keep the size
|
||||
* information if we pass mem_block_ts via a linked list?
|
||||
*/
|
||||
#if 0
|
||||
if (pdcp_test_pdu_buffer_size == 0 || pdcp_test_pdu_buffer == NULL) {
|
||||
msg("[TEST] PDU created by pdcp_data_req() is invalid!\n");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Serialize incoming mem_block_t into an unsigned character array
|
||||
* and add removed PDU to RX list in order to use it in the next test
|
||||
* (test_pdcp_data_ind())
|
||||
*/
|
||||
mem_block_t* pdcp_test_pdu = list_remove_head(&test_pdu_tx_list);
|
||||
memcpy(pdcp_test_pdu_buffer, pdcp_test_pdu->data, pdcp_test_pdu_buffer_size);
|
||||
list_add_tail_eurecom(pdcp_test_pdu, &test_pdu_rx_list);
|
||||
|
||||
/*
|
||||
* Verify that this is a data packet by checking
|
||||
* if the first bit is 0x00 (PDCP_DATA_PDU)
|
||||
*/
|
||||
if (pdcp_test_pdu_buffer[0] & 0x80) {
|
||||
msg("[TEST] First bit is not 0, which means this is not a Data PDU!\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
msg("[TEST] First bit is 0 so this is a Data PDU, OK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that all three reserved bits are 0
|
||||
*/
|
||||
if ((pdcp_test_pdu_buffer[0] & 0x70) != 0) {
|
||||
msg("[TEST] Reserved bits are not 0!\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
msg("[TEST] Reserved bits are all 0, OK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and verify sequence number
|
||||
*/
|
||||
u16 sequence_number = pdcp_get_sequence_number_of_pdu_with_long_sn(pdcp_test_pdu_buffer);
|
||||
msg("[TEST] Parsed sequence number is %04d\n", sequence_number);
|
||||
|
||||
if (sequence_number != index % WINDOW_SIZE) {
|
||||
msg("[TEST] Sequence numbers are out-of-order!\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
msg("[TEST] Sequence number is correct\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
msg("[TEST] pdcp_data_req() returned FALSE!\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL test_pdcp_data_ind()
|
||||
{
|
||||
/*
|
||||
* This is the list that pdcp_data_ind() takes to put pdcp_data_ind_header_t
|
||||
* packets after it receives/validates PDUs and preprends them with pdcp_data_ind_header_t
|
||||
* structure. Here, after this list is filled by pdcp_data_ind() we parse/validate
|
||||
* every single element in the list
|
||||
*/
|
||||
list_t test_pdu_indication_list;
|
||||
mem_block_t* test_sdu = NULL;
|
||||
/*
|
||||
* pdcp_data_req() method prepended PDU header in front of DUMMY_BUFFER so
|
||||
* the size should be 12 bytes
|
||||
*/
|
||||
unsigned char test_sdu_size = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE + DUMMY_BUFFER_SIZE;
|
||||
unsigned int index = 0;
|
||||
|
||||
/*
|
||||
* Initialize linked list
|
||||
*/
|
||||
list_init(&test_pdu_indication_list, NULL);
|
||||
|
||||
/*
|
||||
* Ask PDCP to handle a number of data indications
|
||||
*/
|
||||
msg("There are %d PDUs in the list\n", test_pdu_rx_list.nb_elements);
|
||||
|
||||
/*
|
||||
* Traverse PDU list and pass each one of them to pdcp_data_ind()
|
||||
*/
|
||||
while (list_get_head(&test_pdu_rx_list) != NULL) {
|
||||
msg("\n\nAsking PDCP to receive %d. SDU...\n", 1 + index++);
|
||||
|
||||
test_sdu = list_remove_head(&test_pdu_rx_list);
|
||||
|
||||
if (pdcp_data_ind(0, 0, test_sdu_size, test_sdu, &pdcp_array[0], &test_pdu_indication_list) == FALSE) {
|
||||
msg("[TEST] pdcp_data_ind() failed to handle data indication!\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
msg("[TEST] pdcp_data_ind() succcessfuly handled data indication\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse/validate fields of SDU
|
||||
*/
|
||||
msg("[TEST] Starting to dissect SDU created by PDCP...\n");
|
||||
/*
|
||||
* Get pdcp_data_ind_header_t added by pdcp_data_ind()
|
||||
*/
|
||||
mem_block_t* test_data_ind_header = list_remove_head(&test_pdu_indication_list);
|
||||
|
||||
if (test_data_ind_header == NULL) {
|
||||
msg("[TEST] Data indication header is not valid!\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
pdcp_data_ind_header_t* indication_header = (pdcp_data_ind_header_t*)test_data_ind_header->data;
|
||||
|
||||
/*
|
||||
* Verify that radio bearer ID is correct (0)
|
||||
*/
|
||||
if (indication_header->rb_id == 0) {
|
||||
msg("[TEST] Radio bearer ID is correct\n");
|
||||
} else {
|
||||
msg("[TEST] Radio bearer ID is not correct! (expected: 0, parsed: %d)\n", indication_header->rb_id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that SDU size is correct (DUMMY_BUFFER_SIZE)
|
||||
*/
|
||||
if (indication_header->data_size == DUMMY_BUFFER_SIZE + PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE) {
|
||||
msg("[TEST] SDU size is correct\n");
|
||||
} else {
|
||||
msg("[TEST] SDU size is not correct! (expected: %d, parsed: %d)\n", DUMMY_BUFFER_SIZE, indication_header->data_size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Verify `indication_header->inst` when you know what it is
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX PDCP PDU header should also be checked here
|
||||
*/
|
||||
|
||||
/*
|
||||
* Verify that serialised data is the stream we've supplied
|
||||
*
|
||||
* Data comes after `pdcp_data_ind_header_t` and `pdcp_user_plane_data_pdu_header_with_long_sn`
|
||||
*/
|
||||
unsigned char data_index = sizeof(pdcp_data_ind_header_t) + PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE;
|
||||
|
||||
if (memcmp(DUMMY_BUFFER, (unsigned char*)&(test_data_ind_header->data[data_index]), DUMMY_BUFFER_SIZE) == 0) {
|
||||
msg("[TEST] Data payload of pdcp_data_ind_header_t matches with the stream we sent\n");
|
||||
|
||||
} else {
|
||||
msg("[TEST] Data payload of pdcp_data_ind_header_t does not match with the stream we sent!\n");
|
||||
|
||||
/*
|
||||
* Print octets of both streams
|
||||
* XXX This could be a method in test_util.h
|
||||
*/
|
||||
print_byte_stream("[TEST] TXed data: ", DUMMY_BUFFER, DUMMY_BUFFER_SIZE);
|
||||
print_byte_stream("[TEST] RXed data: ", (unsigned char*)&(test_data_ind_header->data[data_index]), DUMMY_BUFFER_SIZE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* PDCP test code
|
||||
*
|
||||
* Author: Baris Demiray <baris.demiray@eurecom.fr>
|
||||
*/
|
||||
|
||||
#ifndef TEST_PDCP_H
|
||||
#define TEST_PDCP_H
|
||||
|
||||
#include "LAYER2/PDCP_v10.1.0/pdcp.h"
|
||||
#include "LAYER2/PDCP_v10.1.0/pdcp_primitives.h"
|
||||
|
||||
/*
|
||||
* To suppress following errors
|
||||
*
|
||||
* /homes/demiray/workspace/openair4G/trunk/openair2/LAYER2/PDCP_v10.1.0/pdcp.o: In function `pdcp_run':
|
||||
* /homes/demiray/workspace/openair4G/trunk/openair2/LAYER2/PDCP_v10.1.0/pdcp.c:270: undefined reference to `pdcp_fifo_read_input_sdus'
|
||||
* /homes/demiray/workspace/openair4G/trunk/openair2/LAYER2/PDCP_v10.1.0/pdcp.c:273: undefined reference to `pdcp_fifo_flush_sdus'
|
||||
*/
|
||||
int pdcp_fifo_flush_sdus () { return 0; }
|
||||
int pdcp_fifo_read_input_sdus_remaining_bytes () { return 0; }
|
||||
int pdcp_fifo_read_input_sdus () { return 0; }
|
||||
|
||||
BOOL init_pdcp_entity(pdcp_t *pdcp_entity);
|
||||
BOOL test_tx_window();
|
||||
BOOL test_rx_window();
|
||||
BOOL test_pdcp_data_req();
|
||||
BOOL test_pdcp_data_ind();
|
||||
|
||||
/*
|
||||
* PDCP methods that are going to be utilised throughout the test
|
||||
*/
|
||||
extern BOOL pdcp_init_seq_numbers(pdcp_t* pdcp_entity);
|
||||
extern u16 pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity);
|
||||
extern BOOL pdcp_is_rx_seq_number_valid(u16 seq_num, pdcp_t* pdcp_entity);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
/*
|
||||
* Helper methods for PDCP test code
|
||||
*
|
||||
* Author: Baris Demiray <baris.demiray@eurecom.fr>
|
||||
*/
|
||||
|
||||
#ifndef TEST_UTIL_H
|
||||
#define TEST_UTIL_H
|
||||
|
||||
#include "LAYER2/PDCP_v10.1.0/pdcp.h"
|
||||
|
||||
/*
|
||||
* Prints binary representation of given octet prepending
|
||||
* passed log message
|
||||
*
|
||||
* @param Octet as an unsigned character
|
||||
* @return None
|
||||
*/
|
||||
void print_binary_representation(unsigned char* message, unsigned char byte)
|
||||
{
|
||||
unsigned char index = 0;
|
||||
unsigned char mask = 0x80;
|
||||
|
||||
if (message != NULL)
|
||||
printf("%s", message);
|
||||
|
||||
for (index = 0; index < 8; ++index) {
|
||||
if (byte & mask) printf("1");
|
||||
else printf("0");
|
||||
|
||||
mask /= 2;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints octets of a byte array in hexadecimal representation
|
||||
*/
|
||||
void print_byte_stream(char* message, unsigned char* buffer, unsigned long size)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
|
||||
unsigned long index = 0lu;
|
||||
|
||||
printf("%s", message);
|
||||
for (index = 0; index < size; ++index) {
|
||||
msg("%x ", buffer[index]);
|
||||
}
|
||||
msg("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints PDCP properties
|
||||
*
|
||||
* @param pdcp_t pointer for relevant PDCP entity
|
||||
* @return none
|
||||
*/
|
||||
void print_pdcp_properties(pdcp_t* pdcp_entity)
|
||||
{
|
||||
printf("PDCP properties:\n");
|
||||
|
||||
if (pdcp_entity == NULL) {
|
||||
printf("PDCP pointer is invalid!\n");
|
||||
} else {
|
||||
printf("-> Is header compression active? %s\n", ((pdcp_entity->header_compression_active == TRUE) ? "Yes" : "No"));
|
||||
printf("-> Sequence number size: %d bits\n", pdcp_entity->seq_num_size);
|
||||
printf("-> Next TX sequence number: %d\n", pdcp_entity->next_pdcp_tx_sn);
|
||||
printf("-> Next RX sequence number: %d\n", pdcp_entity->next_pdcp_rx_sn);
|
||||
printf("-> TX HFN: %d\n", pdcp_entity->tx_hfn);
|
||||
printf("-> RX HFN: %d\n", pdcp_entity->rx_hfn);
|
||||
printf("-> Last submitted RX sequence number: %d\n", pdcp_entity->last_submitted_pdcp_rx_sn);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
* Test configuration should be configurable on run-time (command-line?)
|
||||
* Inbetween every test PDCP entity should be reinitialized or different
|
||||
PDCP entities should be utilised
|
||||
|
||||
|
||||
baris.demiray@eurecom.fr
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
CC = gcc
|
||||
|
||||
SSE3PROC = $(shell echo `grep ssse3 /proc/cpuinfo`)
|
||||
SSE4PROC = $(shell echo `grep sse4 /proc/cpuinfo`)
|
||||
CPUFLAGS = -mmmx -msse -msse2 -m32 -mssse3 #-msse4
|
||||
CPUFLAGS += $(shell if [ -z $$SSE3PROC]; then echo "" ; else echo "-mssse3"; fi)
|
||||
CPUFLAGS += $(shell if [ -z $$SSE4PROC]; then echo "" ; else echo "-msse4"; fi)
|
||||
cygwin = $(shell if [ $$OSTYPE = "cygwin" ] ; then echo "1" ; else echo "0" ; fi)
|
||||
|
||||
TOP_DIR = $(OPENAIR1_DIR)
|
||||
OPENAIR1_TOP = $(OPENAIR1_DIR)
|
||||
OPENAIR2_TOP = $(OPENAIR2_DIR)
|
||||
OPENAIR3_TOP = $(OPENAIR3_DIR)
|
||||
OPENAIR3 = $(OPENAIR3_DIR)
|
||||
|
||||
EXE_FILE_NAME = test_pdcp_rlc
|
||||
|
||||
CFLAGS = -Wall -fno-strict-aliasing -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -g -ggdb $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat
|
||||
|
||||
ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES
|
||||
|
||||
CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE
|
||||
CFLAGS += -I/usr/include/libxml2 -lxml2
|
||||
|
||||
#CFLAGS += -DXFORMS
|
||||
|
||||
ifdef DEBUG_PHY
|
||||
CFLAGS += -DDEBUG_PHY
|
||||
endif
|
||||
|
||||
ifdef NAS_NETLINK
|
||||
CFLAGS += -DNAS_NETLINK -DLINUX -DDEBUG_CONTROL
|
||||
endif
|
||||
|
||||
CFLAGS += -DPHY_ABSTRACTION #-DEMIT_ASN_DEBUG=1
|
||||
CFLAGS += $(shell if [ $$OSTYPE = "cygwin" ] ; then echo "-DCYGWIN" ; fi)
|
||||
|
||||
#include $(OPENAIR1_DIR)/PHY/Makefile.inc
|
||||
#include $(OPENAIR1_DIR)/SCHED/Makefile.inc
|
||||
|
||||
EXTRA_CFLAGS += -DOPENAIR2
|
||||
EXTRA_CFLAGS += -DASSERT
|
||||
EXTRA_CFLAGS += -DNO_RRM
|
||||
|
||||
COMMON_DIR = $(OPENAIR2_TOP)/COMMON
|
||||
L2_INTERFACE_DIR = $(OPENAIR2_TOP)/RRC/L2_INTERFACE
|
||||
RLC_UM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/UM_v9.3.0
|
||||
RLC_AM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/AM_v9.3.0
|
||||
RLC_TM_DIR = $(OPENAIR2_TOP)/LAYER2/RLC/TM
|
||||
RLC_DIR = $(OPENAIR2_TOP)/LAYER2/RLC
|
||||
PDCP_DIR = $(OPENAIR2_TOP)/LAYER2/PDCP_v10.1.0
|
||||
MEM_DIR = $(OPENAIR2_TOP)/UTIL/MEM
|
||||
LIST_DIR = $(OPENAIR2_TOP)/UTIL/LISTS
|
||||
MATH_DIR = $(OPENAIR2_TOP)/UTIL/MATH
|
||||
TIMER_DIR = $(OPENAIR2_TOP)/UTIL/TIMER
|
||||
PHY_INTERFACE_DIR = $(OPENAIR2_TOP)/PHY_INTERFACE
|
||||
RRC_DIR = $(OPENAIR2_TOP)/RRC/LITE
|
||||
L2_INTERFACE_DIR = $(OPENAIR2_TOP)/RRC/L2_INTERFACE
|
||||
MAC_DIR = $(OPENAIR2_TOP)/LAYER2/MAC
|
||||
LOG_DIR=$(OPENAIR2_TOP)/UTIL/LOG
|
||||
OCG_DIR=$(OPENAIR2_TOP)/UTIL/OCG
|
||||
OPT_DIR=$(OPENAIR2_TOP)/UTIL/OPT
|
||||
|
||||
SOURCES_L2 = $(LIST_DIR)/list.c
|
||||
SOURCES_L2 += $(LIST_DIR)/list2.c
|
||||
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp.c
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp_primitives.c
|
||||
SOURCES_L2 += $(PDCP_DIR)/pdcp_sequence_manager.c
|
||||
|
||||
SOURCES_L2 += $(RLC_DIR)/rlc_mac.c
|
||||
SOURCES_L2 += $(RLC_DIR)/rlc.c
|
||||
SOURCES_L2 += $(RLC_DIR)/rlc_rrc.c
|
||||
SOURCES_L2 += $(RLC_DIR)/rlc_mpls.c
|
||||
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_control_primitives.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_dar.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_fsm.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_reassembly.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_receiver.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_segment.c
|
||||
SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_test.c
|
||||
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_init.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_timer_poll_retransmit.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_timer_reordering.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_timer_status_prohibit.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_segment.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_segments_holes.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_in_sdu.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_receiver.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_retransmit.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_windows.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_rx_list.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_reassembly.c
|
||||
SOURCES_L2 += $(RLC_AM_DIR)/rlc_am_status_report.c
|
||||
|
||||
|
||||
SOURCES_L2 += $(RLC_TM_DIR)/rlc_tm.c
|
||||
SOURCES_L2 += $(RLC_TM_DIR)/rlc_tm_control_primitives.c
|
||||
SOURCES_L2 += $(RLC_TM_DIR)/rlc_tm_fsm.c
|
||||
SOURCES_L2 += $(RLC_TM_DIR)/rlc_tm_segment.c
|
||||
SOURCES_L2 += $(RLC_TM_DIR)/rlc_tm_reassembly.c
|
||||
|
||||
|
||||
|
||||
SOURCES_L2 += $(MEM_DIR)/mem_block.c
|
||||
|
||||
LOG_OBJS = $(LOG_DIR)/log.o
|
||||
OPT_OBJS = $(OPT_DIR)/probe.o
|
||||
|
||||
L2_OBJS=$(addsuffix .o,$(basename $(SOURCES_L2))) $(PHY_INTERFACE_OBJS) $(MAC_OBJS) $(L2_INTERFACE_OBJS) $(RRC_OBJS) $(LOG_OBJS) $(OPT_OBJS)
|
||||
|
||||
L2_incl = -I$(OPENAIR2_TOP) -I$(COMMON_DIR) -I$(RLC_DIR) -I$(RLC_AM_DIR) -I$(RLC_UM_DIR) -I$(RLC_TM_DIR) -I$(PDCP_DIR) -I$(MEM_DIR) -I$(LIST_DIR) \
|
||||
-I$(LOG_DIR) -I$(MATH_DIR) -I$(TIMER_DIR) -I$(OPENAIR3)/MESH -I$(OPENAIR2_TOP)/RRC/MESH -I$(OPENAIR2_TOP)/RRC/MESH/MESSAGES -I$(OPENAIR3)/MESH/RRM -I$(OPT_DIR) \
|
||||
-I$(OCG_DIR)
|
||||
|
||||
ASN1_MSG_OBJS2 := $(foreach file, $(ASN1_MSG_OBJS), $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/$(file))
|
||||
|
||||
# Define object file directory for RLM code
|
||||
#RLC_OBJ_DIR = $(RLC_DIR)/*.o $(RLC_AM_DIR)/*.o $(RLC_UM_DIR)/*.o $(RLC_TM_DIR)/*.o
|
||||
|
||||
OBJ = $(PHY_OBJS) $(SIMULATION_OBJS) $(SCHED_OBJS) $(STATS_OBJS) $(ASN1_MSG_OBJS2) $(RLC_OBJ_DIR)
|
||||
|
||||
all: build_test_pdcp_rlc
|
||||
|
||||
$(OBJ) : %.o : %.c
|
||||
$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -DPHY_CONTEXT=1 -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $@ $<
|
||||
|
||||
$(L2_OBJS) : %.o : %.c
|
||||
$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $@ $<
|
||||
|
||||
build_test_pdcp_rlc : $(OBJ) $(L2_OBJS) test_pdcp_rlc.c
|
||||
echo CYGWIN variable is $(cygwin)
|
||||
$(CC) test_pdcp_rlc.c -I$(TOP_DIR) $(L2_incl) -I$(ASN1_MSG_INC) -o $(EXE_FILE_NAME) $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(L2_OBJS) -lm -lcurses
|
||||
|
||||
clean:
|
||||
rm -f test_pdcp_rlc
|
||||
rm -f *.o
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
The aim of the test code test_pdcp_rlc.c is primarily to test a PDCP protocol entity integrated with RLC layer.
|
||||
This is a first step, in near future, this test may be extended with an other type of RLC (AM), and may be
|
||||
integrated with the upcoming traffic generator.
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
The code implements the following figure:
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
+-+-+-+-+ +-+-+-+-+
|
||||
| PDCP1 | | PDCP2 |
|
||||
+-+-+-+-+ +-+-+-+-+
|
||||
| |
|
||||
+-+-+-+-+ +-+-+-+-+
|
||||
| RLC1 | | RLC2 |
|
||||
| UM | | UM |
|
||||
+-+-+-+-+ +-+-+-+-+
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| MAC LAYER EMULATION |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
Compilation of the code:
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
make -f Makefile.data_bearer
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
Execution of the code:
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
./test_pdcp_rlc
|
||||
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
What Could Be Frequently Asked Questions:
|
||||
#----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#-------------------
|
||||
Q:How to send a SDU?
|
||||
A:
|
||||
pdcp_rlc_test_send_sdu(0, 1, 2); // prototype pdcp_rlc_test_send_sdu(module_id_t module_idP, rb_id_t rab_idP, int sdu_indexP)
|
||||
|
||||
#-------------------
|
||||
Q:How to fix the bitrate of the radio bearer?
|
||||
A:
|
||||
pdcp_rlc_test_exchange_pdus(&rlc[0].m_rlc_um_array[rlc[0].m_rlc_pointer[1].rlc_index],
|
||||
&rlc[1].m_rlc_um_array[rlc[1].m_rlc_pointer[1].rlc_index],
|
||||
1000,
|
||||
1000);
|
||||
|
||||
Prototype:
|
||||
pdcp_rlc_test_exchange_pdus(rlc_um_entity_t *um1P, // RLC UM instance 1
|
||||
rlc_um_entity_t *um2P, // RLC UM instance 2
|
||||
u16_t bytes_tx1P, // tx bytes requested at RLC UM instance 1 and sent to RLC UM instance 2
|
||||
u16_t bytes_tx2P) // tx bytes requested at RLC UM instance 2 and sent to RLC UM instance 1
|
||||
|
||||
|
||||
Executable
+270
@@ -0,0 +1,270 @@
|
||||
#define PDCP_C
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include "SIMULATION/TOOLS/defs.h"
|
||||
#include "SIMULATION/RF/defs.h"
|
||||
#include "PHY/types.h"
|
||||
#include "PHY/defs.h"
|
||||
#include "PHY/vars.h"
|
||||
#include "MAC_INTERFACE/vars.h"
|
||||
|
||||
#include "LAYER2/MAC/defs.h"
|
||||
#include "LAYER2/MAC/vars.h"
|
||||
#include "UTIL/LOG/log_if.h"
|
||||
#include "UTIL/LOG/log_extern.h"
|
||||
#include "RRC/LITE/vars.h"
|
||||
#include "PHY_INTERFACE/vars.h"
|
||||
#include "UTIL/OCG/OCG.h"
|
||||
#include "LAYER2/PDCP_v10.1.0/pdcp.h"
|
||||
#include "OCG_vars.h"
|
||||
#include "rlc.h"
|
||||
#include "pdcp.h"
|
||||
|
||||
|
||||
#define TEST_MAX_SEND_SDU 8192
|
||||
#define TARGET_MAX_RX_ERROR_RATE 10
|
||||
#define TARGET_MAX_TX_ERROR_RATE 10
|
||||
static int g_error_on_phy = 0;
|
||||
static int g_random_sdu;
|
||||
static int g_random_nb_frames;
|
||||
static int g_random_tx_pdu_size;
|
||||
static int g_random_rx_pdu_size;
|
||||
static int g_target_tx_error_rate;
|
||||
static int g_target_rx_error_rate;
|
||||
static int g_tx_packets = 0;
|
||||
static int g_dropped_tx_packets = 0;
|
||||
static int g_rx_packets = 0;
|
||||
static int g_dropped_rx_packets = 0;
|
||||
static int g_drop_rx = 0;
|
||||
static int g_drop_tx = 0;
|
||||
static int g_send_sdu_ids[TEST_MAX_SEND_SDU][2];
|
||||
static int g_send_id_write_index[2];
|
||||
static int g_send_id_read_index[2];
|
||||
static s8_t *g_sdus[] = {"En dépit de son volontarisme affiché, le premier ministre est de plus en plus décrié pour son incompétence. La tension politique et dans l'opinion publique est encore montée d'un cran au Japon, sur fond d'inquiétantes nouvelles, avec du plutonium détecté dans le sol autour de la centrale de Fukushima. Le premier ministre Naoto Kan a solennellement déclaré que son gouvernement était «en état d'alerte maximum». Tout en reconnaissant que la situation restait «imprévisible». Ce volontarisme affiché par le premier ministre - que Nicolas Sarkozy rencontrera demain lors d'une visite au Japon - ne l'a pas empêché d'être la cible de violentes critiques de la part de parlementaires sur sa gestion de la crise. Attaqué sur le manque de transparence, il a assuré qu'il rendait publiques toutes les informations en sa possession. Un député de l'opposition, Yosuke Isozaki, a aussi reproché à Naoto Kan de ne pas avoir ordonné l'évacuation des populations dans la zone comprise entre 20 et 30 km autour de la centrale. «Peut-il y avoir quelque chose de plus irresponsable que cela ?», a-t-il lancé. Pour l'heure, la zone d'évacuation est limitée à un rayon de 20 km, seul le confinement étant recommandé pour les 10 km suivants. Sur ce sujet, les autorités japonaises ont été fragilisées mardi par les déclarations de Greenpeace, affirmant que ses experts avaient détecté une radioactivité dangereuse à 40 km de la centrale. L'organisation écologiste a appelé à une extension de la zone d'évacuation, exhortant Tokyo à «cesser de privilégier la politique aux dépens de la science». L'Agence japonaise de sûreté nucléaire a balayé ces critiques.",
|
||||
|
||||
"La pâquerette (Bellis perennis) est une plante vivace des prés, des pelouses, des bords de chemins et des prairies, haute de dix à vingt centimètres, de la famille des Astéracées, dont les fleurs naissent sur des inflorescences appelées capitules : celles du pourtour, que l'on croit à tort être des pétales, appelées fleurs ligulées, parce qu'elles ont la forme d'une languette, ou demi-fleurons, sont des fleurs femelles, dont la couleur varie du blanc au rose plus ou moins prononcé ; celles du centre, jaunes, appelées fleurs tubuleuses, parce que leur corolle forme un tube, ou fleurons, sont hermaphrodites. Ainsi, contrairement à l'opinion populaire, ce qu'on appelle une « fleur » de pâquerette n'est en réalité pas « une » fleur mais un capitule portant des fleurs très nombreuses.Leurs fruits s'envolent grâce au vent et dégagent des odeurs qui attirent les insectes.Une variété muricole peut pousser sur des murs humides verticaux.Les pâquerettes sont des fleurs rustiques et très communes en Europe, sur les gazons, les prairies, les chemins et les zones d'herbe rase.Elles ont la particularité, comme certaines autres fleurs de plantes herbacées, de se fermer la nuit et de s'ouvrir le matin pour s'épanouir au soleil ; elles peuvent aussi se fermer pendant les averses, voire un peu avant, ce qui permet dans les campagnes de prédire la pluie légèrement à l'avance.",
|
||||
|
||||
"La pâquerette",
|
||||
" (Bellis perennis)",
|
||||
" est une plante vivace des prés,",
|
||||
" des pelouses,",
|
||||
" des bords de chemins et des prairies,",
|
||||
"haute de dix à",
|
||||
" vingt centimètres",
|
||||
", de la",
|
||||
" famille des",
|
||||
" Astéracées",
|
||||
", dont",
|
||||
" les",
|
||||
" fleurs",
|
||||
" naissent",
|
||||
" sur",
|
||||
" des",
|
||||
" inflorescences",
|
||||
" appelées",
|
||||
" capitules",
|
||||
" : celles",
|
||||
" du pourtour",
|
||||
", que l'on",
|
||||
" croit à",
|
||||
" tort",
|
||||
" être",
|
||||
" des pétales",
|
||||
", appelées",
|
||||
" fleurs ligulées",
|
||||
", parce qu'elles",
|
||||
" ont la forme d'une languette, ou demi-fleurons, sont",
|
||||
" des fleurs femelles,",
|
||||
" dont la couleur varie du blanc au rose plus ou moins prononcé ; celles du centre, jaunes,",
|
||||
" appelées ",
|
||||
"fleurs tubuleuses",
|
||||
", parce que leur corolle forme un tube, ou fleurons, sont hermaphrodites."
|
||||
};
|
||||
|
||||
|
||||
|
||||
int pdcp_fifo_flush_sdus () {}
|
||||
int pdcp_fifo_read_input_sdus_remaining_bytes () {}
|
||||
int pdcp_fifo_read_input_sdus () {}
|
||||
|
||||
BOOL init_pdcp_entity(pdcp_t *pdcp_entity);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void pdcp_rlc_test_mac_rlc_loop (struct mac_data_ind *data_indP, struct mac_data_req *data_requestP, int* drop_countP, int *tx_packetsP, int* dropped_tx_packetsP) //-----------------------------------------------------------------------------
|
||||
{
|
||||
mem_block_t* tb_src;
|
||||
mem_block_t* tb_dst;
|
||||
unsigned int tb_size;
|
||||
|
||||
data_indP->no_tb = 0;
|
||||
while (data_requestP->data.nb_elements > 0) {
|
||||
tb_src = list_remove_head (&data_requestP->data);
|
||||
if (tb_src != NULL) {
|
||||
tb_size = ((struct mac_tb_req *) (tb_src->data))->tb_size_in_bits >> 3;
|
||||
printf("[RLC-LOOP] FOUND TB SIZE IN BITS %d IN BYTES %d sizeof (mac_rlc_max_rx_header_size_t) %d\n",
|
||||
((struct mac_tb_req *) (tb_src->data))->tb_size_in_bits,
|
||||
tb_size, sizeof (mac_rlc_max_rx_header_size_t));
|
||||
|
||||
*tx_packetsP = *tx_packetsP + 1;
|
||||
if (*drop_countP == 0) {
|
||||
tb_dst = get_free_mem_block(sizeof (mac_rlc_max_rx_header_size_t) + tb_size);
|
||||
if (tb_dst != NULL) {
|
||||
((struct mac_tb_ind *) (tb_dst->data))->first_bit = 0;
|
||||
((struct mac_tb_ind *) (tb_dst->data))->data_ptr = &tb_dst->data[sizeof (mac_rlc_max_rx_header_size_t)];
|
||||
((struct mac_tb_ind *) (tb_dst->data))->size = tb_size;
|
||||
((struct mac_tb_ind *) (tb_dst->data))->error_indication = 0;
|
||||
|
||||
memcpy(((struct mac_tb_ind *) (tb_dst->data))->data_ptr,
|
||||
&((struct mac_tb_req *) (tb_src->data))->data_ptr[0],
|
||||
tb_size);
|
||||
|
||||
list_add_tail_eurecom(tb_dst, &data_indP->data);
|
||||
data_indP->no_tb += 1;
|
||||
} else {
|
||||
printf("Out of memory error\n");
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
printf("[RLC-LOOP] DROPPING 1 TB\n");
|
||||
*drop_countP = *drop_countP - 1;
|
||||
*dropped_tx_packetsP = *dropped_tx_packetsP + 1;
|
||||
}
|
||||
free_mem_block(tb_src);
|
||||
if (data_indP->no_tb > 0) {
|
||||
printf("[RLC-LOOP] Exchange %d TBs\n",data_indP->no_tb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void pdcp_rlc_test_exchange_pdus(rlc_um_entity_t *um_txP,
|
||||
rlc_um_entity_t *um_rxP,
|
||||
u16_t bytes_txP,
|
||||
u16_t bytes_rxP)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
struct mac_data_req data_request_tx;
|
||||
struct mac_data_req data_request_rx;
|
||||
struct mac_data_ind data_ind_tx;
|
||||
struct mac_data_ind data_ind_rx;
|
||||
struct mac_status_ind tx_status;
|
||||
struct mac_status_resp mac_rlc_status_resp_tx;
|
||||
struct mac_status_resp mac_rlc_status_resp_rx;
|
||||
|
||||
|
||||
memset(&data_request_tx, 0, sizeof(struct mac_data_req));
|
||||
memset(&data_request_rx, 0, sizeof(struct mac_data_req));
|
||||
memset(&data_ind_tx, 0, sizeof(struct mac_data_ind));
|
||||
memset(&data_ind_rx, 0, sizeof(struct mac_data_ind));
|
||||
memset(&tx_status, 0, sizeof(struct mac_status_ind));
|
||||
memset(&mac_rlc_status_resp_tx, 0, sizeof(struct mac_status_resp));
|
||||
memset(&mac_rlc_status_resp_rx, 0, sizeof(struct mac_status_resp));
|
||||
|
||||
mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, bytes_txP, tx_status);
|
||||
data_request_tx = rlc_um_mac_data_request(um_txP);
|
||||
mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, bytes_rxP, tx_status);
|
||||
data_request_rx = rlc_um_mac_data_request(um_rxP);
|
||||
|
||||
|
||||
pdcp_rlc_test_mac_rlc_loop(&data_ind_rx, &data_request_tx, &g_drop_tx, &g_tx_packets, &g_dropped_tx_packets);
|
||||
pdcp_rlc_test_mac_rlc_loop(&data_ind_tx, &data_request_rx, &g_drop_rx, &g_rx_packets, &g_dropped_rx_packets);
|
||||
rlc_um_mac_data_indication(um_rxP, data_ind_rx);
|
||||
rlc_um_mac_data_indication(um_txP, data_ind_tx);
|
||||
mac_xface->frame += 1;
|
||||
|
||||
//rlc_um_tx_buffer_display(um_txP,NULL);
|
||||
//assert(um_txP->t_status_prohibit.time_out != 1);
|
||||
//assert(um_rxP->t_status_prohibit.time_out != 1);
|
||||
//assert(!((um_txP->vt_a == 954) && (um_txP->vt_us == 53)));
|
||||
//assert(mac_xface->frame <= 151);
|
||||
//check_mem_area(NULL);
|
||||
//display_mem_load();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void pdcp_rlc_test_send_sdu(module_id_t module_idP, rb_id_t rab_idP, int sdu_indexP)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
pdcp_data_req(module_idP, rab_idP, strlen(g_sdus[sdu_indexP]) + 1, g_sdus[sdu_indexP]);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
unsigned long index = 0;
|
||||
rlc_op_status_t rlc_op_status;
|
||||
rlc_info_t rlc_info;
|
||||
char * g_log_level = "trace"; // by default global log level is set to trace
|
||||
|
||||
mac_xface = malloc(sizeof(MAC_xface));
|
||||
Mac_rlc_xface = (MAC_RLC_XFACE*)malloc16(sizeof(MAC_RLC_XFACE));
|
||||
|
||||
rlc_module_init ();
|
||||
pdcp_module_init();
|
||||
logInit();
|
||||
|
||||
if (init_pdcp_entity(&pdcp_array[0][1]) == TRUE && init_pdcp_entity(&pdcp_array[1][1]) == TRUE)
|
||||
msg("PDCP entity initialization OK\n");
|
||||
else {
|
||||
msg("Cannot initialize PDCP entities!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize PDCP state variables */
|
||||
for (index = 0; index < 2; ++index) {
|
||||
if (pdcp_init_seq_numbers(&pdcp_array[index][1]) == FALSE) {
|
||||
msg("Cannot initialize %s PDCP entity!\n", ((index == 0) ? "first" : "second"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Configure RLCs */
|
||||
rlc_info.rlc_mode = RLC_UM;
|
||||
rlc_info.rlc.rlc_um_info.timer_reordering = 20;
|
||||
rlc_info.rlc.rlc_um_info.sn_field_length = 10;
|
||||
rlc_info.rlc.rlc_um_info.is_mXch = 0;
|
||||
|
||||
rlc_op_status = rrc_rlc_config_req (0, ACTION_ADD, 1, RADIO_ACCESS_BEARER, rlc_info);
|
||||
assert(rlc_op_status == RLC_OP_STATUS_OK);
|
||||
|
||||
rlc_op_status = rrc_rlc_config_req (1, ACTION_ADD, 1, RADIO_ACCESS_BEARER, rlc_info);
|
||||
assert(rlc_op_status == RLC_OP_STATUS_OK);
|
||||
|
||||
|
||||
/* Simulate data traffic */
|
||||
pdcp_rlc_test_send_sdu(0, 1, 2);
|
||||
pdcp_rlc_test_exchange_pdus(&rlc[0].m_rlc_um_array[rlc[0].m_rlc_pointer[1].rlc_index],
|
||||
&rlc[1].m_rlc_um_array[rlc[1].m_rlc_pointer[1].rlc_index],
|
||||
1000,
|
||||
1000);
|
||||
pdcp_rlc_test_exchange_pdus(&rlc[1].m_rlc_um_array[rlc[1].m_rlc_pointer[1].rlc_index],
|
||||
&rlc[0].m_rlc_um_array[rlc[0].m_rlc_pointer[1].rlc_index],
|
||||
1000,
|
||||
1000);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL init_pdcp_entity(pdcp_t *pdcp_entity)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
if (pdcp_entity == NULL)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Initialize sequence number state variables of relevant PDCP entity
|
||||
*/
|
||||
pdcp_entity->next_pdcp_tx_sn = 0;
|
||||
pdcp_entity->next_pdcp_rx_sn = 0;
|
||||
pdcp_entity->tx_hfn = 0;
|
||||
pdcp_entity->rx_hfn = 0;
|
||||
/* SN of the last PDCP SDU delivered to upper layers */
|
||||
pdcp_entity->last_submitted_pdcp_rx_sn = 4095;
|
||||
pdcp_entity->seq_num_size = 12;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user