Commit 621ba724 authored by Cedric Roux's avatar Cedric Roux

channel_simulator: gains for channels (for X2 handover with a COTS UE)

The main goal of this commit is to be able to perform X2 handover
using a COTS UE and two 'simulated' eNB, each running on a separate
computer, but both using the same USRP device to send and receive IQ
data over the air. By changin the gains at runtime using a small script,
it is possible to trigger X2 handover based on the A3 measurement report
as sent by the UE.

The documentation on how to perform X2 handover with only one
USRP device is in channel_simulator/README.x2_handover.
parent 939aee9a
How to perform X2 handover with the channel simulator and only one USRP device
==============================================================================
This document describes the configuration and the steps used to perform
X2 handover with the channel simulator and one USRP device (B210).
The setup we used is as follows.
Three computers are on the same LAN.
The LAN we have is not very fast, so computer 1 and computer 2 are also
directly connected using an ethernet cable. The connection is 1Gb/s. It
cannot be less because it has to support the stream of IQ data (around
500 Mb/s for 25 RBs).
Computer 1 has LAN IP address 192.168.12.196 and 10.0.0.1 for the direct
connection with computer 2.
Computer 2 has LAN IP address 192.168.12.108 and 10.0.0.2 for the direct
connection with computer 1.
Computer 3 has LAN IP address 192.168.12.148.
Computer 1 runs:
- channel_simulator
- usrp
- one eNB
- gain.sh to set gains (source below)
Computer 2 runs only one eNB.
Computer 3 runs a proprietary EPC (this is not openair-cn).
The USRP device is connected to computer 1.
Configuration
=============
The configuration files for computer 1 (computer1.conf) and computer 2
(computer2.conf) are identical, except for the following.
/homes/roux> diff computer1.conf computer2.conf
11c11
< eNB_ID = 0xe00;
---
> eNB_ID = 0xe01;
42c42
< Nid_cell = 0;
---
> Nid_cell = 1;
188c188,193
<
---
> target_enb_x2_ip_address = (
> { ipv4 = "192.168.12.196";
> ipv6 = "192:168:30::17";
> preference = "ipv4";
> }
> );
192c197
< ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.196/24";
---
> ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.108/24";
195c200
< ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.196/24";
---
> ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.108/24";
198c203
< ENB_IPV4_ADDRESS_FOR_X2C = "192.168.12.196/24";
---
> ENB_IPV4_ADDRESS_FOR_X2C = "192.168.12.108/24";
/homes/roux>
The eNB_ID and Nid_cell need to be different. The IP address settings
also.
For the X2 configuration, for computer 1, we have:
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
And for computer 2, we have:
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
target_enb_x2_ip_address = (
{ ipv4 = "192.168.12.196";
ipv6 = "192:168:30::17";
preference = "ipv4";
}
);
The full content of computer1.conf and computer2.conf are below, for
reference. It is better to start from a sample configuration file found in
the source tree and change the neeeded values rather than using those files.
They are put here for reference only and may fail to work with future
versions of the software.
Steps
=====
- on computer 3:
- launch the EPC
- on computer 1:
- run: ./channel_simulator
- as root, run: CHANNEL_SIMULATOR_RX_FREQUENCY=2 CHANNEL_SIMULATOR_TX_FREQUENCY=1 CHANNEL_SIMULATOR_TX_SAMPLE_ADVANCE=15360 ./lte-softmodem -O computer1.conf
- on computer 2:
- as root, run: CHANNEL_SIMULATOR_IP=10.0.0.1 CHANNEL_SIMULATOR_RX_FREQUENCY=2 CHANNEL_SIMULATOR_TX_FREQUENCY=1 CHANNEL_SIMULATOR_TX_SAMPLE_ADVANCE=15360 ./lte-softmodem -O computer2.conf
- on computer 1:
- as root, run: ./usrp
- run: ./gain.sh 0 -30
- connect the UE
the UE should connect to the eNB on computer 1 due to the gains.
- on computer 1:
- run gain.sh (source below) repeatedly
at each run, decrease first number, increase second, eg.:
- ./gain.sh -5 -25
- ./gain.sh -10 -20
- ./gain.sh -15 -15
- ./gain.sh -20 -10
- ./gain.sh -25 -5
- ./gain.sh -30 -0
note: actual values may need to be different. The basic idea is to
increase the gain for the target eNB and decrease the gain for
the source eNB to trigger X2 handover based on A3 measurement
report.
Script to set gains (gain.sh)
=============================
Here comes the script used to set gains.
/homes/roux> cat gain.sh
echo set gain $1 to 10.0.0.1
echo $1|telnet 10.0.0.1 4025
echo set gain $2 to 10.0.0.1
echo $2|telnet 10.0.0.2 4025
/homes/roux>
==============================================================================
Content of computer1.conf
==============================================================================
/homes/roux> cat computer1.conf
Active_eNBs = ( "eNB-Eurecom-LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
# real_time choice in {hard, rt-preempt, no}
real_time = "no";
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB-Eurecom-LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = (
{ mcc = 208; mnc = 92; mnc_length = 2; }
);
tr_s_preference = "local_mac"
////////// Physical parameters:
component_carriers = (
{
node_function = "eNodeB_3GPP";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
nb_antenna_ports = 1;
ue_TransmissionMode = 1;
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2680000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 25;
Nid_cell_mbsfn = 0;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
prach_root = 0;
tx_gain = 90;
rx_gain = 115;
pbch_repetition = "FALSE";
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 0;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -29;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -96;
pusch_alpha = "AL1";
pucch_p0_Nominal = -108;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
//Parameters for SIB18
rxPool_sc_CP_Len = "normal";
rxPool_sc_Period = "sf40";
rxPool_data_CP_Len = "normal";
rxPool_ResourceConfig_prb_Num = 20;
rxPool_ResourceConfig_prb_Start = 5;
rxPool_ResourceConfig_prb_End = 44;
rxPool_ResourceConfig_offsetIndicator_present = "prSmall";
rxPool_ResourceConfig_offsetIndicator_choice = 0;
rxPool_ResourceConfig_subframeBitmap_present = "prBs40";
rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000";
rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
/* rxPool_dataHoppingConfig_hoppingParameter = 0;
rxPool_dataHoppingConfig_numSubbands = "ns1";
rxPool_dataHoppingConfig_rbOffset = 0;
rxPool_commTxResourceUC-ReqAllowed = "TRUE";
*/
// Parameters for SIB19
discRxPool_cp_Len = "normal"
discRxPool_discPeriod = "rf32"
discRxPool_numRetx = 1;
discRxPool_numRepetition = 2;
discRxPool_ResourceConfig_prb_Num = 5;
discRxPool_ResourceConfig_prb_Start = 3;
discRxPool_ResourceConfig_prb_End = 21;
discRxPool_ResourceConfig_offsetIndicator_present = "prSmall";
discRxPool_ResourceConfig_offsetIndicator_choice = 0;
discRxPool_ResourceConfig_subframeBitmap_present = "prBs40";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.12.148";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.196/24";
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.196/24";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
ENB_IPV4_ADDRESS_FOR_X2C = "192.168.12.196/24";
ENB_PORT_FOR_X2C = 36422; # Spec 36422
};
log_config :
{
global_log_level ="info";
global_log_verbosity ="high";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="debug";
rlc_log_verbosity ="high";
pdcp_log_level ="info";
pdcp_log_verbosity ="high";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
}
);
THREAD_STRUCT = (
{
parallel_config = "PARALLEL_RU_L1_TRX_SPLITaaaaaa";
worker_config = "ENABLE";
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 118;
eNB_instances = [0];
}
);
log_config :
{
global_log_level ="info";
global_log_verbosity ="high";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="info";
rlc_log_verbosity ="high";
pdcp_log_level ="info";
pdcp_log_verbosity ="high";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
/homes/roux>
==============================================================================
Content of computer2.conf
==============================================================================
/homes/roux> cat computer2.conf
Active_eNBs = ( "eNB-Eurecom-LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
# real_time choice in {hard, rt-preempt, no}
real_time = "no";
////////// Identification parameters:
eNB_ID = 0xe01;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB-Eurecom-LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = (
{ mcc = 208; mnc = 92; mnc_length = 2; }
);
tr_s_preference = "local_mac"
////////// Physical parameters:
component_carriers = (
{
node_function = "eNodeB_3GPP";
node_timing = "synch_to_ext_device";
node_synch_ref = 0;
nb_antenna_ports = 1;
ue_TransmissionMode = 1;
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2680000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 1;
N_RB_DL = 25;
Nid_cell_mbsfn = 0;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
prach_root = 0;
tx_gain = 90;
rx_gain = 115;
pbch_repetition = "FALSE";
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 0;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -29;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -96;
pusch_alpha = "AL1";
pucch_p0_Nominal = -108;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
//Parameters for SIB18
rxPool_sc_CP_Len = "normal";
rxPool_sc_Period = "sf40";
rxPool_data_CP_Len = "normal";
rxPool_ResourceConfig_prb_Num = 20;
rxPool_ResourceConfig_prb_Start = 5;
rxPool_ResourceConfig_prb_End = 44;
rxPool_ResourceConfig_offsetIndicator_present = "prSmall";
rxPool_ResourceConfig_offsetIndicator_choice = 0;
rxPool_ResourceConfig_subframeBitmap_present = "prBs40";
rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000";
rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
/* rxPool_dataHoppingConfig_hoppingParameter = 0;
rxPool_dataHoppingConfig_numSubbands = "ns1";
rxPool_dataHoppingConfig_rbOffset = 0;
rxPool_commTxResourceUC-ReqAllowed = "TRUE";
*/
// Parameters for SIB19
discRxPool_cp_Len = "normal"
discRxPool_discPeriod = "rf32"
discRxPool_numRetx = 1;
discRxPool_numRepetition = 2;
discRxPool_ResourceConfig_prb_Num = 5;
discRxPool_ResourceConfig_prb_Start = 3;
discRxPool_ResourceConfig_prb_End = 21;
discRxPool_ResourceConfig_offsetIndicator_present = "prSmall";
discRxPool_ResourceConfig_offsetIndicator_choice = 0;
discRxPool_ResourceConfig_subframeBitmap_present = "prBs40";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff";
discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5;
discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.12.148";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
///X2
enable_x2 = "yes";
t_reloc_prep = 1000; /* unit: millisecond */
tx2_reloc_overall = 2000; /* unit: millisecond */
target_enb_x2_ip_address = (
{ ipv4 = "192.168.12.196";
ipv6 = "192:168:30::17";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.108/24";
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.108/24";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
ENB_IPV4_ADDRESS_FOR_X2C = "192.168.12.108/24";
ENB_PORT_FOR_X2C = 36422; # Spec 36422
};
log_config :
{
global_log_level ="info";
global_log_verbosity ="high";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="debug";
rlc_log_verbosity ="high";
pdcp_log_level ="info";
pdcp_log_verbosity ="high";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
phy_test_mode = 0;
puSch10xSnr = 200;
puCch10xSnr = 200;
}
);
THREAD_STRUCT = (
{
parallel_config = "PARALLEL_RU_L1_TRX_SPLITaaaaaa";
worker_config = "ENABLE";
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
}
);
RUs = (
{
local_rf = "yes"
nb_tx = 1
nb_rx = 1
att_tx = 0
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 118;
eNB_instances = [0];
}
);
log_config :
{
global_log_level ="info";
global_log_verbosity ="high";
hw_log_level ="info";
hw_log_verbosity ="medium";
phy_log_level ="info";
phy_log_verbosity ="medium";
mac_log_level ="info";
mac_log_verbosity ="high";
rlc_log_level ="info";
rlc_log_verbosity ="high";
pdcp_log_level ="info";
pdcp_log_verbosity ="high";
rrc_log_level ="info";
rrc_log_verbosity ="medium";
};
/homes/roux>
......@@ -8,6 +8,7 @@
#include <inttypes.h>
#include <unistd.h>
#include <sys/socket.h>
#include <immintrin.h>
void init_channel_simulator(channel_simulator *c,
uint32_t samplerate, int n_samples)
......@@ -33,7 +34,7 @@ void cleanup_connections(channel_simulator *c)
con = &c->connections[i];
c->channels[con->rx_channel_index].connection_count--;
c->channels[con->tx_channel_index].connection_count--;
free(con->tx_buffer);
free(con->iq_buffer);
if (c->connections_count == 1) {
free(c->connections);
c->connections = NULL;
......@@ -94,8 +95,8 @@ static int find_or_create_channel(channel_simulator *c, uint64_t freq,
chan = &c->channels[i];
chan->frequency = freq;
chan->sample_advance = sample_advance;
chan->data = calloc(1, c->n_samples * 4);
if (chan->data == NULL) goto oom;
if (posix_memalign((void **)&chan->data, 32, c->n_samples * 4) != 0)
goto oom;
chan->connection_count = 0;
return i;
......@@ -121,8 +122,8 @@ void channel_simulator_add_connection(channel_simulator *c,
con = &c->connections[c->connections_count-1];
con->socket = socket;
con->tx_buffer = calloc(1, c->n_samples * 4);
if (con->tx_buffer == NULL) goto oom;
if (posix_memalign((void **)&con->iq_buffer, 32, c->n_samples * 4) != 0)
goto oom;
con->rx_frequency = rx_frequency;
con->tx_frequency = tx_frequency;
con->rx_channel_index = find_or_create_channel(c, rx_frequency,
......@@ -133,6 +134,14 @@ void channel_simulator_add_connection(channel_simulator *c,
c->channels[con->rx_channel_index].connection_count++;
c->channels[con->tx_channel_index].connection_count++;
if (posix_memalign(&con->gain, 32, 32) != 0) {
printf("posix_memalign failed\n");
exit(1);
}
/* default gain = 1 (actually 1 - 1/2^15) */
*(__m256i *)con->gain = _mm256_set1_epi16(0x7fff);
return;
oom:
......@@ -144,13 +153,30 @@ void connection_send_rx(connection *c, uint64_t timestamp,
uint32_t *data, int n_samples)
{
unsigned char b[8+4];
int k;
int16_t *from;
int16_t *to;
__m256i *gain;
if (c->socket == -1) return;
/* apply gain on data to send */
from = (int16_t *)data;
to = (int16_t *)c->iq_buffer;
gain = (__m256i *)c->gain;
/* does: to[] = from[] * gain[] */
for (k = 0; k < n_samples * 2; k+=16) {
__m256i *a, *b;
a = (__m256i *)&to[k];
b = (__m256i *)&from[k];
*a = _mm256_mulhrs_epi16(*b, *gain);
}
pu64(b, timestamp);
pu32(b+8, n_samples);
if (fullwrite(c->socket, b, 8+4) != 8+4 ||
fullwrite(c->socket, data, n_samples * 4) != n_samples * 4) {
fullwrite(c->socket, c->iq_buffer, n_samples * 4) != n_samples * 4) {
printf("ERROR: connection_send_rx failed, dropping\n");
shutdown(c->socket, SHUT_RDWR);
close(c->socket);
......@@ -198,10 +224,32 @@ err:
con->socket = -1;
}
void command_set_gain(channel_simulator *cs, connection *con, int n)
{
unsigned char b[4];
int v;
if (n != 4) goto err;
if (fullread(con->socket, b, 4) != 4) goto err;
v = gu32(b);
*(__m256i *)con->gain = _mm256_set1_epi16(v);
printf("INFO: setting gain to %d\n", v);
return;
err:
printf("ERROR: command_set_gain failed, dropping\n");
shutdown(con->socket, SHUT_RDWR);
close(con->socket);
con->socket = -1;
}
void do_command(channel_simulator *cs, connection *c, uint64_t command, int n)
{
switch (command) {
case 0: return command_set_frequency(cs, c, n);
case 1: return command_set_gain(cs, c, n);
default:
printf("ERROR: bad command %"PRIu64", dropping\n", command);
shutdown(c->socket, SHUT_RDWR);
......@@ -239,7 +287,7 @@ again:
recv_n_samples, n_samples);
goto err;
}
if (fullread(c->socket, c->tx_buffer, n_samples * 4) != n_samples * 4)
if (fullread(c->socket, c->iq_buffer, n_samples * 4) != n_samples * 4)
goto err;
return;
......@@ -251,8 +299,6 @@ err:
c->socket = -1;
}
#include <immintrin.h>
void channel_simulate(channel_simulator *c)
{
int i;
......@@ -269,38 +315,20 @@ void channel_simulate(channel_simulator *c)
for (i = 0; i < c->channels_count; i++)
memset(c->channels[i].data, 0, c->n_samples * 4);
#if 0
/* basic mixing */
for (i = 0; i < c->connections_count; i++) {
con = &c->connections[i];
from = (int16_t *)con->tx_buffer;
for (k = 0; k < c->n_samples * 2; k++)
mix[con->tx_channel_index][k] += from[k];
}
for (i = 0; i < c->channels_count; i++) {
chan = &c->channels[i];
to = (int16_t *)chan->data;
for (k = 0; k < c->n_samples * 2; k++) {
int v = mix[i][k];
if (v > 32767) v = 32767;
if (v < -32768) v = -32768;
to[k] = v;
}
}
#else
/* basic mixing */
for (i = 0; i < c->connections_count; i++) {
__m256i *gain;
con = &c->connections[i];
from = (int16_t *)con->tx_buffer;
from = (int16_t *)con->iq_buffer;
gain = (__m256i *)con->gain;
/* does: mix[] = mix[] + from[] * gain[] */
for (k = 0; k < c->n_samples * 2; k+=16) {
__m256i *a, *b;
__m256i *a, *b, v;
a = (__m256i *)&mix[con->tx_channel_index][k];
b = (__m256i *)&from[k];
*a = _mm256_adds_epi16(*a, *b);
v = _mm256_mulhrs_epi16(*b, *gain);
*a = _mm256_adds_epi16(*a, v);
}
}
......@@ -309,5 +337,4 @@ void channel_simulate(channel_simulator *c)
to = (int16_t *)chan->data;
memcpy(to, mix[i], c->n_samples * 2 * 2);
}
#endif
}
......@@ -12,11 +12,14 @@ typedef struct {
typedef struct {
int socket;
uint32_t *tx_buffer;
/* iq_buffer is used both in tx and rx */
uint32_t *iq_buffer;
uint64_t rx_frequency;
uint64_t tx_frequency;
int rx_channel_index;
int tx_channel_index;
/* gain to apply to rx and tx data */
void *gain; /* actually __m256i * */
} connection;
typedef struct {
......
CC=gcc
CPP=g++
CFLAGS=-Wall -g -pthread
CFLAGS=-Wall -g -pthread -march=native -O3 -ffast-math
PROG=usrp
OBJS=main.o usrp.o ../utils.o
......
#define _GNU_SOURCE
#include "usrp.h"
#include "../utils.h"
......@@ -10,6 +11,7 @@
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <immintrin.h>
#include <inttypes.h>
......@@ -31,7 +33,7 @@ void receive_from_channel_simulator(int sock, buffer_t *buf)
if (n_samples != buf->n_samples) {
free(buf->data);
buf->n_samples = n_samples;
buf->data = malloc(buf->n_samples * 4); if (buf->data == NULL) goto err;
if (posix_memalign((void **)&buf->data, 32, buf->n_samples * 4) != 0) goto err;
}
if (fullread(sock, buf->data, buf->n_samples * 4) != buf->n_samples * 4)
goto err;
......@@ -139,8 +141,7 @@ int main(void)
receive_from_channel_simulator(sock, &buf);
sim_timestamp = buf.timestamp - 2 * samples_per_subframe + buf.n_samples;
usrp_data = calloc(1, buf.n_samples * 4);
if (usrp_data == NULL) {
if (posix_memalign((void **)&usrp_data, 32, buf.n_samples * 4) != 0) {
printf("ERROR: out of memory\n");
exit(1);
}
......@@ -152,9 +153,18 @@ int main(void)
usrp_timestamp = usrp_read(usrp_data, buf.n_samples);
while (1) {
int i;
for (i = 0; i < buf.n_samples * 2; i += 16) {
__m256i *a = (__m256i *)&((int16_t *)buf.data)[i];
*a = _mm256_slli_epi16(*a, 4);
}
usrp_write(buf.data, buf.n_samples,
usrp_timestamp - buf.n_samples + 2 * samples_per_subframe - tx_sample_advance);
usrp_timestamp = usrp_read(usrp_data, buf.n_samples);
for (i = 0; i < buf.n_samples * 2; i += 16) {
__m256i *a = (__m256i *)&((int16_t *)usrp_data)[i];
*a = _mm256_srai_epi16(*a, 4);
}
send_to_channel_simulator(sock, usrp_data, buf.n_samples, sim_timestamp);
sim_timestamp += buf.n_samples;
receive_from_channel_simulator(sock, &buf);
......
......@@ -32,11 +32,11 @@ void usrp_init_connection(uint64_t rx_freq, uint64_t tx_freq)
usrp->set_rx_rate(7680000, 0);
usrp->set_rx_freq(rx_freq, 0);
usrp->set_rx_gain(40, 0);
usrp->set_rx_gain(62.2, 0);
usrp->set_tx_rate(7680000, 0);
usrp->set_tx_freq(tx_freq, 0);
usrp->set_tx_gain(90, 0);
usrp->set_tx_gain(89.75, 0);
uhd::stream_args_t stream_args_rx("sc16", "sc16");
stream_args_rx.args["spp"] = str(boost::format("%d") % 768 );
......
#define _GNU_SOURCE
#include "common_lib.h"
#include "channel_simulator/utils.h"
......@@ -9,6 +10,7 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <math.h>
typedef struct buffer_s {
uint64_t timestamp;
......@@ -40,6 +42,97 @@ typedef struct {
int samples_per_packet;
} channel_simulator_state_t;
/*************************************************************************/
/* gain setting begin */
/*************************************************************************/
void channel_simulator_set_gain(channel_simulator_state_t *c, int gain_db)
{
unsigned char b[8+4+4];
double gain;
int gain_lin;
gain = exp10(gain_db/20.);
if (gain > 1) gain = 1;
gain_lin = gain * 32767;
if (gain_lin > 0x7fff)
gain_lin = 0x7fff;
printf("channel_simulator: setting gain to %d dB (%d lin)\n", gain_db, gain_lin);
pu64(b, 1);
pu32(b+8, 4);
pu32(b+8+4, gain_lin);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8+4+4) != 8+4+4) {
printf("ERROR: channel_simulator: channel_simulator_set_gain failed\n");
exit(1);
}
unlock(&c->tx_lock);
}
int get_line(int s, char *l, int len)
{
int pos = 0;
while (1) {
if (fullread(s, &l[pos], 1) != 1)
return -1;
if (l[pos] == '\n') {
l[pos] = 0;
break;
}
pos++;
if (pos == len)
return -1;
}
return 0;
}
void channel_simulator_gain_process(channel_simulator_state_t *c, int s)
{
char line[256];
int gain;
if (get_line(s, line, 256) == -1) return;
if (sscanf(line, "%d", &gain) != 1) return;
channel_simulator_set_gain(c, gain);
}
void *channel_simulator_gain_thread(void *_c)
{
channel_simulator_state_t *c = _c;
int port = 4025;
char *env;
struct sockaddr_in addr;
socklen_t addrlen;
int sock;
env = getenv("CHANNEL_SIMULATOR_GAIN_PORT");
if (env != NULL)
port = atoi(env);
else
printf("channel_simulator: environment variable CHANNEL_SIMULATOR_GAIN_PORT"
" not found, using default port %d\n", port);
sock = create_listen_socket("0.0.0.0", port);
while (1) {
int t;
addrlen = sizeof(addr);
t = accept(sock, (struct sockaddr *)&addr, &addrlen);
if (t == -1) { perror("accept"); exit(1); }
channel_simulator_gain_process(c, t);
close(t);
}
return NULL;
}
/*************************************************************************/
/* gain setting end */
/*************************************************************************/
void add_rx_buffer(channel_simulator_state_t *c, buffer_t *b)
{
lock(&c->lock);
......@@ -460,5 +553,7 @@ int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
device->openair0_cfg=&openair0_cfg[0];
new_thread(channel_simulator_gain_thread, channel_simulator);
return 0;
}
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