continue timestamp
This commit is contained in:
@@ -0,0 +1,264 @@
|
|||||||
|
# OpenAirInterface for SystemX
|
||||||
|
|
||||||
|
#Terminology
|
||||||
|
|
||||||
|
****This document use the 5G terminology****
|
||||||
|
|
||||||
|
**Central Unit (CU): **It is a logical node that includes the gNB
|
||||||
|
functions like Transfer of user data, Mobility control, Radio access
|
||||||
|
network sharing, Positioning, Session Management etc., except those
|
||||||
|
functions allocated exclusively to the DU. CU controls the operation of
|
||||||
|
DUs over front-haul (Fs) interface. A central unit (CU) may also be
|
||||||
|
known as BBU/REC/RCC/C-RAN/V-RAN/VNF
|
||||||
|
|
||||||
|
**Distributed Unit (DU):** This logical node includes a subset of the
|
||||||
|
gNB functions, depending on the functional split option. Its operation
|
||||||
|
is controlled by the CU. Distributed Unit (DU) also known with other
|
||||||
|
names like RRH/RRU/RE/RU/PNF.
|
||||||
|
|
||||||
|
In OpenAir code, the terminology is often RU and BBU.
|
||||||
|
|
||||||
|
#Usage
|
||||||
|
##EPC and general environment
|
||||||
|
### OAI EPC
|
||||||
|
|
||||||
|
Use the stable OAI EPC, that can run in one machine (VM or standalone)
|
||||||
|
|
||||||
|
Draft description:
|
||||||
|
<https://open-cells.com/index.php/2017/08/22/all-in-one-openairinterface-august-22nd/>
|
||||||
|
|
||||||
|
##Standalone 4G
|
||||||
|
|
||||||
|
EPC+eNB on one machine, the UE can be commercial or OAI UE.
|
||||||
|
### USRP B210
|
||||||
|
|
||||||
|
Main current issue: traffic is good only on coaxial link between UE and
|
||||||
|
eNB (probably power management issue).
|
||||||
|
|
||||||
|
### Simulated RF
|
||||||
|
|
||||||
|
Running eNB+UE both OAI can be done over a virtual RF link.
|
||||||
|
|
||||||
|
The UE current status is that threads synchronization is implicit in
|
||||||
|
some cases. As the RF simulator is very quick, a “sleep()” is required
|
||||||
|
in the UE main loop
|
||||||
|
|
||||||
|
(line 1744, targets/RT/USER/lte-ue.c).
|
||||||
|
|
||||||
|
Running also the UE in the same machine is possible with simulated RF.
|
||||||
|
|
||||||
|
Running in same machine is simpler, offers about infinite speed for
|
||||||
|
virtual RF samples transmission.
|
||||||
|
|
||||||
|
A specific configuration is required because the EPC Sgi interface has
|
||||||
|
the same IP tunnel end point as the UE.
|
||||||
|
|
||||||
|
So, we have to create a network namespace for the UE and to route data
|
||||||
|
in/out of the namespace.
|
||||||
|
``` bash
|
||||||
|
ip netns delete aNameSpace 2> /dev/null
|
||||||
|
|
||||||
|
ip link delete v-eth1 2> /dev/null
|
||||||
|
|
||||||
|
ip netns add aNameSpace
|
||||||
|
|
||||||
|
ip link add v-eth1 type veth peer name v-peer1
|
||||||
|
|
||||||
|
ip link set v-peer1 netns aNameSpace
|
||||||
|
|
||||||
|
ip addr add 10.200.1.1/24 dev v-eth1
|
||||||
|
|
||||||
|
ip link set v-eth1 up
|
||||||
|
|
||||||
|
iptables -t nat -A POSTROUTING -s 10.200.1.0/255.255.255.0 -o enp0s31f6
|
||||||
|
-j MASQUERADE
|
||||||
|
|
||||||
|
iptables -A FORWARD -i enp0s31f6 -o v-eth1 -j ACCEPT
|
||||||
|
|
||||||
|
iptables -A FORWARD -o enp0s31f6 -i v-eth1 -j ACCEPT
|
||||||
|
|
||||||
|
ip netns exec aNameSpace ip link set dev lo up
|
||||||
|
|
||||||
|
ip netns exec aNameSpace ip addr add 10.200.1.2/24 dev v-peer1
|
||||||
|
|
||||||
|
ip netns exec aNameSpace ip link set v-peer1 up
|
||||||
|
|
||||||
|
ip netns exec aNameSpace bash
|
||||||
|
```
|
||||||
|
|
||||||
|
After the last command, the Linux shell is in the new namespace, ready
|
||||||
|
to run the UE.
|
||||||
|
|
||||||
|
To make user plan traffic, the traffic generator has to run in the same
|
||||||
|
namespace
|
||||||
|
|
||||||
|
`ip netns exec aNameSpace bash
|
||||||
|
`
|
||||||
|
|
||||||
|
The traffic genenrator has to specify the interface:
|
||||||
|
|
||||||
|
`route add default oaitun_ue1
|
||||||
|
`
|
||||||
|
|
||||||
|
or specify the outgoing route in the traffic generator (like option “-I”
|
||||||
|
in ping command).
|
||||||
|
|
||||||
|
## Split 6 DL 4G
|
||||||
|
|
||||||
|
The contract describes to reuse the uplink existing if4p5 and to develop
|
||||||
|
is this work the downlink “functional split 6”.
|
||||||
|
|
||||||
|
The customer required after signature to develop also the uplink
|
||||||
|
functional split 6. This is accepted, as long as the whole work is
|
||||||
|
research with no delivery completeness warranty.
|
||||||
|
### Simulation
|
||||||
|
|
||||||
|
To be able to verify the new features and to help in all future
|
||||||
|
developments, Open Cells added and improved the Rf board simulator
|
||||||
|
during this contract.
|
||||||
|
|
||||||
|
We added the channel modeling simulation, that offer to simulate various
|
||||||
|
3GPP defined channels.
|
||||||
|
### Main loop
|
||||||
|
|
||||||
|
The main log is in RF simulator is in
|
||||||
|
|
||||||
|
targets/RT/USER/lte-ru.c and targets/RT/USER/lte-enb.c
|
||||||
|
|
||||||
|
As this piece of SW is very complex and doesn’t meet our goals
|
||||||
|
(functional split 6), a cleaned version replaces these 2 files in
|
||||||
|
executables/ocp-main.c (openair1/SCHED/prach\_procedures.c is also
|
||||||
|
replaced by this new file as it only launching the RACH actual work in a
|
||||||
|
way not compatible with our FS6).
|
||||||
|
|
||||||
|
The main loop cadences the I/Q samples reception, signal processing and
|
||||||
|
I/Q samples sending.
|
||||||
|
|
||||||
|
The main loop uses extensively function pointers to call the right
|
||||||
|
processing function depending on the split case.
|
||||||
|
|
||||||
|
This is enough for RF board dialog, but the FS6 is higher in SW layers,
|
||||||
|
we need to cut higher functions inside downlink and uplink procedures.
|
||||||
|
|
||||||
|
### DownLink
|
||||||
|
|
||||||
|
The main procedure is phy\_procedures\_eNB\_TX
|
||||||
|
|
||||||
|
This is building the common channels (beacon, multi-UE signaling).
|
||||||
|
|
||||||
|
The FS6 split breaks this function into pieces:
|
||||||
|
|
||||||
|
- The multi-UE signals, built by common\_signal\_procedures(),
|
||||||
|
subframe2harq\_pid(), generate\_dci\_top(), subframe2harq\_pid()
|
||||||
|
|
||||||
|
- These functions will be executed in the DU, nevertheless all
|
||||||
|
context has to be sent (it is also needed partially for
|
||||||
|
UL spitting)
|
||||||
|
- IT should be in the DU also to meet the requirement of pushing
|
||||||
|
in DU the data encoded with large redundancy (>3 redundancy)
|
||||||
|
- the per UE data: pdsch\_procedures() that needs further splitting:
|
||||||
|
|
||||||
|
- dlsch\_encoding\_all() that makes the encoding: turbo code
|
||||||
|
and lte\_rate\_matching\_turbo() that will be in the DU (some
|
||||||
|
unlikely cases can reach redundancy up to x3, when MCS is very
|
||||||
|
low (negative SINR cases)).
|
||||||
|
|
||||||
|
- dlsch\_encoding() output needs to be transmitted between the
|
||||||
|
DU and the CU for functional split 6.
|
||||||
|
- dlsch\_scrambling() that will go in the DU
|
||||||
|
- dlsch\_modulation() that will go in the DU
|
||||||
|
|
||||||
|
### Uplink
|
||||||
|
|
||||||
|
The uplink require configuration that is part of the DL transmission.
|
||||||
|
|
||||||
|
It interprets the signalling to extract the RACH and the per UE data
|
||||||
|
channels.
|
||||||
|
|
||||||
|
Ocp-main.c:rxtx() calls directly the entry procedure
|
||||||
|
phy\_procedures\_eNB\_uespec\_RX() calls:
|
||||||
|
|
||||||
|
- rx\_ulsch() that demodulate and extract soft bits per UE.
|
||||||
|
|
||||||
|
- This function runs in the DU
|
||||||
|
- the output data will be processes in the DU, so it needs to be
|
||||||
|
transmitted to the DU
|
||||||
|
- ulsch\_decoding() that do lte\_rate\_matching\_turbo\_rx()
|
||||||
|
sub\_block\_deinterleaving\_turbo() then turbo decode
|
||||||
|
|
||||||
|
- it runs
|
||||||
|
- fill\_ulsch\_cqi\_indication()
|
||||||
|
|
||||||
|
- TBD: either runs in DU or output needs to be transmitted to DU
|
||||||
|
- fill\_crc\_indication() , fill\_rx\_indication() results need also
|
||||||
|
to be transmitted or made in the DU
|
||||||
|
|
||||||
|
### UDP transport layer
|
||||||
|
|
||||||
|
A general UDP transport layer is in executables/transport\_split.c
|
||||||
|
|
||||||
|
Linux offers a UDP socket builtin timeout, that we use.
|
||||||
|
|
||||||
|
In and out buffers are memory zones that contains compacted
|
||||||
|
(concatenated) UDP chunks.
|
||||||
|
|
||||||
|
For output, sendSubFrame() sends each UDP chunk
|
||||||
|
|
||||||
|
For input, receiveSubFrame() collects all UDP chunks for a group (a
|
||||||
|
subframe in OAI LTE case). It returns in the following cases:
|
||||||
|
|
||||||
|
- all chunks are received
|
||||||
|
- a timeout expired
|
||||||
|
- a chunk from the next subframe already arrived
|
||||||
|
|
||||||
|
### Functional split 6 usage
|
||||||
|
|
||||||
|
The ocp cleaned main hale to be used: run ocp-softmodem instead of
|
||||||
|
lte-softmodem.
|
||||||
|
|
||||||
|
The functionality and parameters is the same, enhanced with FS6 mode.
|
||||||
|
|
||||||
|
The environment variable “fs6” enables the fs6 mode and decided to be cu
|
||||||
|
or du from the fs6 variable content.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
`fs6=cu ./ocp-softmodem -O … (regular lte-softmodem paramters)
|
||||||
|
`
|
||||||
|
|
||||||
|
Run the CU init of the split 6 eNB.
|
||||||
|
|
||||||
|
CU and DU IP address and port are configurable in the eNB configuration
|
||||||
|
file (as X2, GTP, … interfaces).
|
||||||
|
|
||||||
|
##5G and F1
|
||||||
|
|
||||||
|
Today 5G achievement is limited to physical layer.
|
||||||
|
|
||||||
|
The available modulation is 40MHz, that require one X310 or N300 for the
|
||||||
|
gNB and a X310 or N300 for the nrUE.
|
||||||
|
|
||||||
|
### Usage with X310
|
||||||
|
|
||||||
|
Linux configuration:
|
||||||
|
<https://files.ettus.com/manual/page_usrp_x3x0_config.html>
|
||||||
|
|
||||||
|
We included most of this configuration included in OAI source code.
|
||||||
|
|
||||||
|
Remain to set the NIC (network interface card) MTU to 9000 (jumbo
|
||||||
|
frames).
|
||||||
|
|
||||||
|
### Running 5G
|
||||||
|
|
||||||
|
Usage with RFsimulator:
|
||||||
|
|
||||||
|
gNB
|
||||||
|
|
||||||
|
`sudo RFSIMULATOR=server ./nr-softmodem -O
|
||||||
|
../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
|
||||||
|
--parallel-config PARALLEL\_SINGLE\_THREAD`
|
||||||
|
|
||||||
|
nrUE
|
||||||
|
|
||||||
|
`sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C
|
||||||
|
3510000000 -d`
|
||||||
@@ -183,8 +183,8 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${CMAKE_CU
|
|||||||
#########################
|
#########################
|
||||||
# set a flag for changes in the source code
|
# set a flag for changes in the source code
|
||||||
# these changes are related to hardcoded path to include .h files
|
# these changes are related to hardcoded path to include .h files
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3")
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3 -O2")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g3 -DMALLOC_CHECK_=3 -O0")
|
||||||
|
|
||||||
|
|
||||||
set(GIT_BRANCH "UNKNOWN")
|
set(GIT_BRANCH "UNKNOWN")
|
||||||
|
|||||||
+23
-18
@@ -653,6 +653,8 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx
|
|||||||
hDL(bufferZone)->amp=AMP;
|
hDL(bufferZone)->amp=AMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (num_mdci) abort();
|
||||||
|
|
||||||
if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci);
|
if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci);
|
||||||
|
|
||||||
if (do_meas==1) start_meas(&eNB->dlsch_ue_specific);
|
if (do_meas==1) start_meas(&eNB->dlsch_ue_specific);
|
||||||
@@ -741,21 +743,21 @@ void phy_procedures_eNB_TX_extract(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rx
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DL_du_fs6(RU_t *ru, int frame, int subframe, uint64_t TS) {
|
void DL_du_fs6(RU_t *ru) {
|
||||||
RU_proc_t *ru_proc=&ru->proc;
|
RU_proc_t *ru_proc=&ru->proc;
|
||||||
|
|
||||||
for (int i=0; i<ru->num_eNB; i++) {
|
for (int i=0; i<ru->num_eNB; i++) {
|
||||||
initBufferZone(bufferZone);
|
initBufferZone(bufferZone);
|
||||||
int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) );
|
int nb_blocks=receiveSubFrame(&sockFS6, ru_proc->timestamp_tx, bufferZone, sizeof(bufferZone), CTsentCUv0 );
|
||||||
L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx;
|
|
||||||
L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp;
|
|
||||||
L1_proc->frame_tx=hDL(bufferZone)->frame;
|
|
||||||
L1_proc->subframe_tx=hDL(bufferZone)->subframe;
|
|
||||||
|
|
||||||
if (nb_blocks>0)
|
if (nb_blocks > 0) {
|
||||||
|
L1_rxtx_proc_t *L1_proc = &ru->eNB_list[i]->proc.L1_proc_tx;
|
||||||
|
L1_proc->timestamp_tx=hUDP(bufferZone)->timestamp;
|
||||||
|
L1_proc->frame_tx=hDL(bufferZone)->frame;
|
||||||
|
L1_proc->subframe_tx=hDL(bufferZone)->subframe;
|
||||||
phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1);
|
phy_procedures_eNB_TX_process( bufferZone, nb_blocks, ru->eNB_list[i], &ru->eNB_list[i]->proc.L1_proc, 1);
|
||||||
else
|
} else
|
||||||
LOG_E(PHY,"DL not received for subframe: %d\n", subframe);
|
LOG_E(PHY,"DL not received for subframe\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OAI data model is wrong: hardcode link ru to enb index 0*/
|
/* OAI data model is wrong: hardcode link ru to enb index 0*/
|
||||||
@@ -799,8 +801,14 @@ void UL_du_fs6(RU_t *ru, int frame, int subframe) {
|
|||||||
phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc );
|
phy_procedures_eNB_uespec_RX_extract(bufferZone, FS6_BUF_SIZE, eNB, &proc->L1_proc );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hUDP(bufferZone)->nbBlocks==0) {
|
||||||
|
hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE)
|
||||||
|
hUDP(bufferZone)->blockID=0;
|
||||||
|
hUDP(bufferZone)->contentBytes=sizeof(fs6_ul_t);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<ru->num_eNB; i++) {
|
for (int i=0; i<ru->num_eNB; i++) {
|
||||||
sendSubFrame(&sockFS6,bufferZone, sizeof(fs6_ul_t));
|
sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_ul_t), CTsentDUv0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,12 +835,12 @@ void DL_cu_fs6(RU_t *ru,int frame, int subframe) {
|
|||||||
hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t);
|
hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t) );
|
sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) {
|
void UL_cu_fs6(RU_t *ru,int frame, int subframe, uint64_t TS) {
|
||||||
initBufferZone(bufferZone);
|
initBufferZone(bufferZone);
|
||||||
int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone) );
|
int nb_blocks=receiveSubFrame(&sockFS6, TS, bufferZone, sizeof(bufferZone), CTsentDUv0 );
|
||||||
|
|
||||||
if (nb_blocks ==0) {
|
if (nb_blocks ==0) {
|
||||||
LOG_W(PHY, "CU lost a subframe\n");
|
LOG_W(PHY, "CU lost a subframe\n");
|
||||||
@@ -878,7 +886,6 @@ void *cu_fs6(void *arg) {
|
|||||||
void *du_fs6(void *arg) {
|
void *du_fs6(void *arg) {
|
||||||
RU_t *ru = (RU_t *)arg;
|
RU_t *ru = (RU_t *)arg;
|
||||||
//RU_proc_t *proc = &ru->proc;
|
//RU_proc_t *proc = &ru->proc;
|
||||||
int64_t AbsoluteSubframe=-1;
|
|
||||||
fill_rf_config(ru,ru->rf_config_file);
|
fill_rf_config(ru,ru->rf_config_file);
|
||||||
init_frame_parms(&ru->frame_parms,1);
|
init_frame_parms(&ru->frame_parms,1);
|
||||||
phy_init_RU(ru);
|
phy_init_RU(ru);
|
||||||
@@ -887,11 +894,9 @@ void *du_fs6(void *arg) {
|
|||||||
AssertFatal(createUDPsock(NULL, "7777", "127.0.0.1", "8888", &sockFS6),"");
|
AssertFatal(createUDPsock(NULL, "7777", "127.0.0.1", "8888", &sockFS6),"");
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
AbsoluteSubframe++;
|
L1_rxtx_proc_t *proc = &ru->eNB_list[0]->proc;
|
||||||
int subframe=AbsoluteSubframe%10;
|
UL_du_fs6(ru, proc->frame_rx,proc->subframe_rx);
|
||||||
int frame=(AbsoluteSubframe/10)%1024;
|
DL_du_fs6(ru);
|
||||||
UL_du_fs6(ru, frame,subframe);
|
|
||||||
DL_du_fs6(ru, frame,subframe, AbsoluteSubframe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
+1
-13
@@ -582,13 +582,11 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) {
|
void eNB_top(PHY_VARS_eNB *eNB, int dummy1, int dummy2, char *string,RU_t *ru) {
|
||||||
L1_proc_t *proc = &eNB->proc;
|
L1_proc_t *proc = &eNB->proc;
|
||||||
L1_rxtx_proc_t *L1_proc = &proc->L1_proc;
|
L1_rxtx_proc_t *L1_proc = &proc->L1_proc;
|
||||||
LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
|
LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
|
||||||
RU_proc_t *ru_proc=&ru->proc;
|
RU_proc_t *ru_proc=&ru->proc;
|
||||||
proc->frame_rx = frame_rx;
|
|
||||||
proc->subframe_rx = subframe_rx;
|
|
||||||
|
|
||||||
if (!oai_exit) {
|
if (!oai_exit) {
|
||||||
L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti);
|
L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti);
|
||||||
@@ -650,16 +648,6 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
|
|||||||
proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10;
|
proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10;
|
||||||
proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
|
proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
|
||||||
|
|
||||||
if (proc->first_rx == 0) {
|
|
||||||
AssertFatal( proc->subframe_rx == *subframe && proc->frame_rx == *frame,
|
|
||||||
"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d) (proc->frame_rx %d frame %d)\n",
|
|
||||||
(long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe, proc->frame_rx,*frame);
|
|
||||||
} else {
|
|
||||||
proc->first_rx = 0;
|
|
||||||
*frame = proc->frame_rx;
|
|
||||||
*subframe = proc->subframe_rx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rxs != fp->samples_per_tti) {
|
if (rxs != fp->samples_per_tti) {
|
||||||
#if defined(USRP_REC_PLAY)
|
#if defined(USRP_REC_PLAY)
|
||||||
exit_fun("Exiting IQ record/playback");
|
exit_fun("Exiting IQ record/playback");
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ typedef struct {
|
|||||||
int sockHandler;
|
int sockHandler;
|
||||||
} UDPsock_t;
|
} UDPsock_t;
|
||||||
|
|
||||||
|
#define CTsentCUv0 0xA500
|
||||||
|
#define CTsentDUv0 0x5A00
|
||||||
|
|
||||||
typedef struct commonUDP_s {
|
typedef struct commonUDP_s {
|
||||||
uint64_t timestamp; // id of the group (subframe for LTE)
|
uint64_t timestamp; // id of the group (subframe for LTE)
|
||||||
uint16_t nbBlocks; // total number of blocks for this timestamp
|
uint16_t nbBlocks; // total number of blocks for this timestamp
|
||||||
@@ -67,8 +70,8 @@ typedef struct {
|
|||||||
} fs6_dl_uespec_t;
|
} fs6_dl_uespec_t;
|
||||||
|
|
||||||
bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result);
|
bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result);
|
||||||
int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize);
|
int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType);
|
||||||
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize);
|
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType);
|
||||||
|
|
||||||
#define initBufferZone(xBuf) \
|
#define initBufferZone(xBuf) \
|
||||||
uint8_t xBuf[FS6_BUF_SIZE];\
|
uint8_t xBuf[FS6_BUF_SIZE];\
|
||||||
@@ -77,12 +80,12 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize);
|
|||||||
#define hUDP(xBuf) ((commonUDP_t *)xBuf)
|
#define hUDP(xBuf) ((commonUDP_t *)xBuf)
|
||||||
#define hDL(xBuf) (((fs6_dl_t*)((commonUDP_t *)xBuf)+1))
|
#define hDL(xBuf) (((fs6_dl_t*)((commonUDP_t *)xBuf)+1))
|
||||||
|
|
||||||
inline size_t alignedSize(uint8_t *ptr) {
|
static inline size_t alignedSize(uint8_t *ptr) {
|
||||||
commonUDP_t *header=(commonUDP_t *) ptr;
|
commonUDP_t *header=(commonUDP_t *) ptr;
|
||||||
return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign;
|
return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void *commonUDPdata(uint8_t *ptr) {
|
static inline void *commonUDPdata(uint8_t *ptr) {
|
||||||
return (void *) (((commonUDP_t *)ptr)+1);
|
return (void *) (((commonUDP_t *)ptr)+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo
|
|||||||
|
|
||||||
int enable=1;
|
int enable=1;
|
||||||
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,"");
|
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,"");
|
||||||
struct timeval tv= {0,UDP_TIMEOUT};
|
//struct timeval tv= {0,UDP_TIMEOUT};
|
||||||
|
struct timeval tv= {2,UDP_TIMEOUT}; //debug: wait 2 seconds for human understanding
|
||||||
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,"");
|
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,"");
|
||||||
// Make a send/recv buffer larger than a a couple of subframe
|
// Make a send/recv buffer larger than a a couple of subframe
|
||||||
// so the kernel will store for us in and out paquets
|
// so the kernel will store for us in and out paquets
|
||||||
@@ -69,9 +70,9 @@ bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPo
|
|||||||
// sock: udp socket
|
// sock: udp socket
|
||||||
// expectedTS: the expected timestamp, 0 if unknown
|
// expectedTS: the expected timestamp, 0 if unknown
|
||||||
// bufferZone: a reception area of bufferSize
|
// bufferZone: a reception area of bufferSize
|
||||||
int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize) {
|
int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int bufferSize, uint16_t contentType) {
|
||||||
int rcved=0;
|
int rcved=0;
|
||||||
commonUDP_t *tmp=NULL;
|
commonUDP_t *bufOrigin=(commonUDP_t *)bufferZone;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
//read all subframe data from the control unit
|
//read all subframe data from the control unit
|
||||||
@@ -85,22 +86,37 @@ int receiveSubFrame(UDPsock_t *sock, uint64_t expectedTS, void *bufferZone, int
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tmp=(commonUDP_t *)bufferZone;
|
if (hUDP(bufferZone)->contentType != contentType)
|
||||||
|
abort();
|
||||||
|
|
||||||
if ( expectedTS && tmp->timestamp != expectedTS) {
|
if ( hUDP(bufferZone)->timestamp != expectedTS) {
|
||||||
LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n");
|
if ( hUDP(bufferZone)->timestamp < expectedTS) {
|
||||||
|
LOG_W(HW,"Received a paquet from past subframes, dropping it\n");
|
||||||
|
} else {
|
||||||
|
LOG_W(HW,"Received a paquet in future subframes\n");
|
||||||
|
|
||||||
|
if ( rcved == 0 ) {
|
||||||
|
LOG_W(HW,"First paquet in the sub-frame, keeping it\n");
|
||||||
|
rcved++;
|
||||||
|
bufferZone+=ret;
|
||||||
|
expectedTS=hUDP(bufferZone)->timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rcved++;
|
rcved++;
|
||||||
bufferZone+=ret;
|
bufferZone+=ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ( !rcved || rcved < tmp->nbBlocks );
|
} while ( !rcved || rcved < hUDP(bufferZone)->nbBlocks );
|
||||||
|
|
||||||
|
LOG_D(HW,"Received: nb_blocks: %d, TS: %lu, frame: %d, subframe: %d\n",
|
||||||
|
rcved, bufOrigin->timestamp, *(((int *)bufOrigin)+1), *(((int *)bufOrigin)+2));
|
||||||
return rcved;
|
return rcved;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) {
|
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType) {
|
||||||
commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ;
|
commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ;
|
||||||
|
UDPheader->contentType=contentType;
|
||||||
int nbBlocks=UDPheader->nbBlocks;
|
int nbBlocks=UDPheader->nbBlocks;
|
||||||
int blockId=0;
|
int blockId=0;
|
||||||
|
|
||||||
@@ -131,5 +147,7 @@ int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize) {
|
|||||||
nbBlocks--;
|
nbBlocks--;
|
||||||
} while (nbBlocks);
|
} while (nbBlocks);
|
||||||
|
|
||||||
|
LOG_D(HW,"Sent: TS: %lu, frame: %d, subframe: %d\n",
|
||||||
|
UDPheader->timestamp, *(((int *)UDPheader)+1), *(((int *)UDPheader)+2));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,10 +409,10 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
|
|||||||
ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe);
|
ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe);
|
||||||
|
|
||||||
// clear previous allocation information for all UEs
|
// clear previous allocation information for all UEs
|
||||||
for (i = 0; i < NUMBER_OF_UE_MAX; i++) {
|
//for (i = 0; i < NUMBER_OF_UE_MAX; i++) {
|
||||||
//if (eNB->dlsch[i][0])
|
//if (eNB->dlsch[i][0])
|
||||||
//eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
|
//eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
|
||||||
}
|
//}
|
||||||
|
|
||||||
/* TODO: check the following test - in the meantime it is put back as it was before */
|
/* TODO: check the following test - in the meantime it is put back as it was before */
|
||||||
//if ((ul_subframe < 10)&&
|
//if ((ul_subframe < 10)&&
|
||||||
|
|||||||
Reference in New Issue
Block a user