adding mbms-gw and mch generation tables

master
yagoda 7 years ago
parent 12c9f50ba9
commit e4c3f0bc30

@ -82,7 +82,7 @@ uint32_t multiplex_nof_layers = 1;
int mbsfn_area_id = -1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
float rf_amp = 0.8, rf_gain = 60.0, rf_freq = 2400000000;
float output_file_snr = +INFINITY;
@ -302,7 +302,7 @@ void base_init() {
}
if (net_port > 0) {
if (srslte_netsource_init(&net_source, "0.0.0.0", net_port, SRSLTE_NETSOURCE_TCP)) {
if (srslte_netsource_init(&net_source, "127.0.0.1", net_port, SRSLTE_NETSOURCE_UDP)) {
fprintf(stderr, "Error creating input UDP socket at port %d\n", net_port);
exit(-1);
}
@ -869,13 +869,13 @@ int main(int argc, char **argv) {
}
/* Transmit PDCCH + PDSCH only when there is data to send */
if (net_port > 0) {
if ((net_port > 0) && (sf_idx == 1 || mbsfn_area_id < 0)) {
send_data = net_packet_ready;
if (net_packet_ready) {
INFO("Transmitting packet\n");
}
} else {
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
printf("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (pdsch_cfg.grant.tb_en[tb]) {
for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) {
@ -890,9 +890,8 @@ int main(int argc, char **argv) {
send_data = false;
}
}
if (send_data) {
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
if(sf_idx != 2 || mbsfn_area_id < 0) { // PDCCH + PDSCH
srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
@ -1026,8 +1025,11 @@ int main(int argc, char **argv) {
} else {
#ifndef DISABLE_RF
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
//norm_factor = 0.066667;
//rf_amp = 0.8;
printf("power adj is %f\n",rf_amp * norm_factor);
for (i = 0; i < cell.nof_ports; i++) {
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_vec_sc_prod_cfc(output_buffer[i], 0.01, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
start_of_burst=false;

@ -385,7 +385,7 @@ int main(int argc, char **argv) {
}
if (prog_args.net_port > 0) {
if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_TCP)) {
if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_UDP)) {
fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port);
exit(-1);
}

@ -0,0 +1,52 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef GEN_MCH_TALBES_H
#define GEN_MCH_TALBES_H
/******************************************************************************
* Common mch table generation - used in phch_common of UE and ENB for MBMS
*****************************************************************************/
#include <pthread.h>
#include <string.h>
#include <vector>
#include "srslte/common/common.h"
namespace srslte {
void generate_frame_mch_table(uint8_t *table, uint8_t alloc);
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames);
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc);
} // namespace srsue
#endif // SECURITY_H

@ -147,6 +147,7 @@ public:
}
}
protected:
std::vector<SubH> subheaders;
uint32_t pdu_len;

@ -494,8 +494,6 @@ public:
};
/** PHY interface
*
*/
@ -566,12 +564,12 @@ public:
class phy_interface_mac : public phy_interface_mac_common
{
public:
/* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0;
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0;
virtual int prach_tx_tti() = 0;
/* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0;

@ -0,0 +1,65 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/gen_mch_tables.h"
namespace srslte {
/******************************************************************************
* Key Generation
*****************************************************************************/
void generate_frame_table(uint8_t *table, uint8_t alloc)
{
table[1] = (alloc >> 5) & 0x01;
table[2] = (alloc >> 4) & 0x01;
table[3] = (alloc >> 3) & 0x01;
table[6] = (alloc >> 2) & 0x01;
table[7] = (alloc >> 1) & 0x01;
table[8] = (alloc >> 0) & 0x01;
}
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames)
{
if(num_frames == 1){
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
} else if(num_frames == 4){
for(uint32_t j=0; j<4; j++){
uint8_t alloc = (sf_alloc >> 6*(3-j)) & 0x3F;
generate_frame_table(&table[j*10], alloc);
}
}
}
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc)
{
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
}
} // namespace srsue

@ -113,6 +113,7 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
rem_len = 0;
}
/* Determine the header size and CE payload size */
uint32_t header_sz = 0;
uint32_t ce_payload_sz = 0;
@ -168,7 +169,6 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
subheaders[i].write_payload(&ptr);
}
}
// Set padding to zeros (if any)
if (rem_len > 0) {
bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t));
@ -384,6 +384,7 @@ uint16_t sch_subh::get_c_rnti()
return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1];
}
}
uint64_t sch_subh::get_con_res_id()
{
if (payload) {
@ -395,6 +396,7 @@ uint64_t sch_subh::get_con_res_id()
return 0;
}
}
float sch_subh::get_phr()
{
if (payload) {
@ -786,12 +788,6 @@ uint8_t sch_subh::phr_report_table(float phr_value)
return (uint8_t) floor(phr_value+23);
}
void rar_pdu::fprint(FILE* stream)
{
fprintf(stream, "MAC PDU for RAR. ");
@ -861,38 +857,47 @@ void rar_subh::init()
ta = 0;
temp_rnti = 0;
}
uint32_t rar_subh::get_rapid()
{
return preamble;
}
void rar_subh::get_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{
memcpy(grant_, grant, sizeof(uint8_t)*RAR_GRANT_LEN);
}
uint32_t rar_subh::get_ta_cmd()
{
return ta;
}
uint16_t rar_subh::get_temp_crnti()
{
return temp_rnti;
}
void rar_subh::set_rapid(uint32_t rapid)
{
preamble = rapid;
}
void rar_subh::set_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{
memcpy(grant, grant_, sizeof(uint8_t)*RAR_GRANT_LEN);
}
void rar_subh::set_ta_cmd(uint32_t ta_)
{
ta = ta_;
}
void rar_subh::set_temp_crnti(uint16_t temp_rnti_)
{
temp_rnti = temp_rnti_;
}
// Section 6.2.2
void rar_subh::write_subheader(uint8_t** ptr, bool is_last)
{

@ -154,7 +154,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->rsrp_neighbour = false;
q->average_subframe = false;
q->smooth_filter_auto = false;
q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);

@ -120,6 +120,7 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t
return 1+l*SRSLTE_CP_NSYMB(cp);
}
}
inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l)
{
uint32_t ret = 0;

@ -561,7 +561,6 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, int slot_in_sf) {
void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{
uint32_t i, cp_len;
for(i=0;i<q->nof_symbols_mbsfn;i++) {
cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));

@ -364,7 +364,6 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
data != NULL &&
cfg != NULL)
{
INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n",
cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re,
cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1);
@ -379,6 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
/* extract symbols */
n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart);
return SRSLTE_ERROR;
}
@ -433,7 +433,6 @@ int srslte_pmch_encode(srslte_pmch_t *q,
/* Set pointers for layermapping & precoding */
cf_t *x[SRSLTE_MAX_LAYERS];
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && cfg != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {

@ -658,6 +658,7 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
noise_estimate,
q->current_mbsfn_area_id, data);
if (ret == SRSLTE_ERROR) {
q->pmch_pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {

@ -139,7 +139,7 @@ void srslte_vec_fprint_c(FILE *stream, cf_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%+2.2f%+2.2fi, ", __real__ x[i], __imag__ x[i]);
fprintf(stream, "%+2.5f%+2.5fi, ", __real__ x[i], __imag__ x[i]);
}
fprintf(stream, "];\n");
}

@ -43,6 +43,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32)
bzero(&cfg, sizeof(srslte_rlc_um_config_t));
tx_sdu = NULL;
rx_sdu = NULL;
pool = byte_buffer_pool::get_instance();
@ -480,6 +481,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
@ -509,6 +511,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
@ -717,6 +720,7 @@ void rlc_um::reassemble_rx_sdus()
}
// Handle last segment
if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
log->debug("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n",
vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes);
@ -886,7 +890,6 @@ void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_s
{
uint8_t ext;
uint8_t *ptr = payload;
// Fixed part
if(RLC_UMD_SN_SIZE_5_BITS == sn_size)
{
@ -933,7 +936,6 @@ void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, byte_buffer_t *p
{
uint32_t i;
uint8_t ext = (header->N_li > 0) ? 1 : 0;
// Make room for the header
uint32_t len = rlc_um_packed_length(header);
pdu->msg -= len;

@ -545,3 +545,4 @@ int main(int argc, char **argv) {
reassmble_test2();
byte_buffer_pool::get_instance()->cleanup();
}

@ -49,6 +49,7 @@ typedef struct {
LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg;
} phy_cfg_t;
class phy : public phy_interface_mac,
public phy_interface_rrc
{

@ -78,6 +78,7 @@ typedef struct {
typedef struct {
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB];
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT mac_cnfg;
LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cfg;
LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT antenna_info;
LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM pdsch_cfg;

@ -735,6 +735,7 @@ uint32_t HexToBytes(const std::string& str, uint8_t *char_value, uint32_t buff_l
return i/2;
}
int enb::parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data)
{
parser::section sib9("sib9");

@ -449,7 +449,6 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
// Register new user in RRC
rrc_h->add_user(last_rnti);
// Trigger scheduler RACH
scheduler.dl_rach_info(tti, ra_id, last_rnti, 7);
@ -774,9 +773,6 @@ void mac::tti_clock()
timers_thread.tti_clock();
}
/********************************************************
*
* Interface for upper layer timers
@ -799,7 +795,6 @@ srslte::timers::timer* mac::timer_get(uint32_t timer_id)
}
/********************************************************
*
* Class to run timers with normal priority

@ -57,6 +57,8 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf
mac = mac_;
memcpy(&cell, cell_, sizeof(srslte_cell_t));
is_first_of_burst = true;
is_first_tx = true;
for (uint32_t i=0;i<max_mutex;i++) {

@ -1057,18 +1057,6 @@ void phch_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t
void phch_worker::start_plot() {
#ifdef ENABLE_GUI
if (plot_worker_id == -1) {

@ -131,6 +131,7 @@ void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t *
void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu)
{
rlc->write_sdu(rnti, lcid, sdu);
}

@ -30,6 +30,7 @@
#include "srslte/srslte.h"
#include "srslte/asn1/liblte_mme.h"
using srslte::byte_buffer_t;
using srslte::bit_buffer_t;
@ -273,6 +274,7 @@ void rrc::add_user(uint16_t rnti)
{
pthread_mutex_lock(&user_mutex);
if (users.count(rnti) == 0) {
users[rnti].parent = this;
users[rnti].rnti = rnti;
rlc->add_user(rnti);

@ -0,0 +1,93 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: mbms-gw.h
* Description: Top-level MBMS-GW class. Creates and links all
* interfaces and helpers.
*****************************************************************************/
#ifndef MBMS_GW_H
#define MBMS_GW_H
#include <cstddef>
#include "srslte/common/log.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/threads.h"
#include "srslte/asn1/gtpc.h"
namespace srsepc{
const uint16_t GTPU_RX_PORT = 2152;
typedef struct {
std::string name;
std::string sgi_mb_if_addr;
std::string m1u_multi_addr;
} mbms_gw_args_t;
class mbms_gw:
public thread
{
public:
static mbms_gw* get_instance(void);
static void cleanup(void);
int init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log);
void stop();
void run_thread();
private:
/* Methods */
mbms_gw();
virtual ~mbms_gw();
static mbms_gw *m_instance;
srslte::error_t init_sgi_mb_if(mbms_gw_args_t *args);
srslte::error_t init_m1_u(mbms_gw_args_t *args);
void handle_sgi_md_pdu(srslte::byte_buffer_t *msg);
/* Members */
bool m_running;
srslte::byte_buffer_pool *m_pool;
srslte::log_filter *m_mbms_gw_log;
bool m_sgi_mb_up;
int m_sgi_mb_if;
bool m_m1u_up;
int m_m1u;
struct sockaddr_in m_m1u_multi_addr;
};
} // namespace srsepc
#endif // SGW_H

@ -0,0 +1,39 @@
#####################################################################
# srsEPC configuration file
#####################################################################
#####################################################################
# MBMS-GW configuration
#
# name: MBMS-GW name
# sgi_mb_if_addr: SGi-mb interface IP address
# m1u_addr: Multicast group for eNBs (FIXME this should be setup with M2/M3)
#
#####################################################################
[mbms_gw]
name = srsmbmsgw01
sgi_mb_if_addr = 172.16.0.254
m1u_multi_addr = 239.255.0.1
####################################################################
# Log configuration
#
# Log levels can be set for individual layers. "all_level" sets log
# level for all layers unless otherwise configured.
# Format: e.g. s1ap_level = info
#
# In the same way, packet hex dumps can be limited for each level.
# "all_hex_limit" sets the hex limit for all layers unless otherwise
# configured.
# Format: e.g. s1ap_hex_limit = 32
#
# Logging layers: mbms_gw, all
# Logging levels: debug, info, warning, error, none
#
# filename: File path to use for log output. Can be set to stdout
# to print logs to standard output
#####################################################################
[log]
all_level = debug
all_hex_limit = 32
filename = /tmp/mbms.log

@ -1,7 +1,27 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(mme)
add_subdirectory(hss)
add_subdirectory(spgw)
add_subdirectory(mbms-gw)
# Link libstdc++ and libgcc
if(BUILD_STATIC)
@ -26,11 +46,22 @@ target_link_libraries(srsepc srsepc_mme
${LIBCONFIGPP_LIBRARIES}
${SCTP_LIBRARIES})
add_executable(srsmbms mbms-gw/main.cc )
target_link_libraries(srsmbms srsepc_mbms_gw
srslte_upper
srslte_common
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${SEC_LIBRARIES}
${LIBCONFIGPP_LIBRARIES}
${SCTP_LIBRARIES})
if (RPATH)
set_target_properties(srsepc PROPERTIES INSTALL_RPATH ".")
set_target_properties(srsmbms PROPERTIES INSTALL_RPATH ".")
endif (RPATH)
install(TARGETS srsepc DESTINATION ${RUNTIME_DIR})
install(TARGETS srsmbms DESTINATION ${RUNTIME_DIR})
########################################################################
# Option to run command after build (useful for remote builds)

@ -0,0 +1,23 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
file(GLOB SOURCES "*.cc")
add_library(srsepc_mbms_gw STATIC ${SOURCES})
install(TARGETS srsepc_mbms_gw DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,216 @@
/**
*
* \section COPYRIGHT
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <fstream>
#include <errno.h>
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
using namespace std;
using namespace srsepc;
namespace bpo = boost::program_options;
bool running = true;
void
sig_int_handler(int signo){
running = false;
}
typedef struct {
std::string mbms_gw_level;
int mbms_gw_hex_limit;
std::string all_level;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct {
mbms_gw_args_t mbms_gw_args;
log_args_t log_args;
}all_args_t;
srslte::LOG_LEVEL_ENUM
level(std::string l)
{
boost::to_upper(l);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
/**********************************************************************
* Program arguments processing
***********************************************************************/
string config_file;
void
parse_args(all_args_t *args, int argc, char* argv[]) {
string mbms_gw_name;
string mbms_gw_sgi_mb_if_addr;
string mbms_gw_m1u_multi_addr;
string log_filename;
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit")
;
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("mbms_gw.name", bpo::value<string>(&mbms_gw_name)->default_value("srsmbmsgw01"), "MBMS-GW Name")
("mbms_gw.sgi_mb_if_addr", bpo::value<string>(&mbms_gw_sgi_mb_if_addr)->default_value("172.16.1.1"), "SGi-mb TUN interface Address")
("mbms_gw.m1u_multi_addr", bpo::value<string>(&mbms_gw_m1u_multi_addr)->default_value("239.255.0.1"), "M1-u GTPu destination multicast address")
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/mbms.log"),"Log filename")
;
// Positional options - config file location
bpo::options_description position("Positional options");
position.add_options()
("config_file", bpo::value< string >(&config_file), "MBMS-GW configuration file")
;
bpo::positional_options_description p;
p.add("config_file", -1);
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(position).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
//Parsing Config File
if (!vm.count("config_file")) {
cout << "Error: Configuration file not provided" << endl;
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
exit(0);
} else {
cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
}
args->mbms_gw_args.name = mbms_gw_name;
args->mbms_gw_args.sgi_mb_if_addr = mbms_gw_sgi_mb_if_addr;
args->mbms_gw_args.m1u_multi_addr = mbms_gw_m1u_multi_addr;
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if(!vm.count("log.mbms_gw_level")) {
args->log_args.mbms_gw_level = args->log_args.all_level;
}
}
// Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) {
if(!vm.count("log.mbms_gw_hex_limit")) {
args->log_args.mbms_gw_hex_limit = args->log_args.all_hex_limit;
}
}
return;
}
int
main (int argc,char * argv[] )
{
cout << endl <<"--- Software Radio Systems MBMS ---" << endl << endl;
signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler);
signal(SIGKILL, sig_int_handler);
all_args_t args;
parse_args(&args, argc, argv);
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
srslte::logger *logger;
/*Init logger*/
if (!args.log_args.filename.compare("stdout")) {
logger = &logger_stdout;
} else {
logger_file.init(args.log_args.filename);
logger_file.log("\n--- Software Radio Systems MBMS log ---\n\n");
logger = &logger_file;
}
srslte::log_filter mbms_gw_log;
mbms_gw_log.init("MBMS",logger);
mbms_gw_log.set_level(level(args.log_args.mbms_gw_level));
mbms_gw_log.set_hex_limit(args.log_args.mbms_gw_hex_limit);
mbms_gw *mbms_gw = mbms_gw::get_instance();
if(mbms_gw->init(&args.mbms_gw_args,&mbms_gw_log)) {
cout << "Error initializing MBMS-GW" << endl;
exit(1);
}
mbms_gw->start();
while(running) {
sleep(1);
}
mbms_gw->stop();
mbms_gw->cleanup();
cout << std::endl <<"--- exiting ---" << endl;
return 0;
}

@ -0,0 +1,326 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <algorithm>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
#include "srslte/upper/gtpu.h"
namespace srsepc{
mbms_gw* mbms_gw::m_instance = NULL;
pthread_mutex_t mbms_gw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t MBMS_GW_BUFFER_SIZE = 2500;
mbms_gw::mbms_gw():
m_running(false),
m_sgi_mb_up(false)
{
return;
}
mbms_gw::~mbms_gw()
{
return;
}
mbms_gw*
mbms_gw::get_instance(void)
{
pthread_mutex_lock(&mbms_gw_instance_mutex);
if(NULL == m_instance) {
m_instance = new mbms_gw();
}
pthread_mutex_unlock(&mbms_gw_instance_mutex);
return(m_instance);
}
void
mbms_gw::cleanup(void)
{
pthread_mutex_lock(&mbms_gw_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&mbms_gw_instance_mutex);
}
int
mbms_gw::init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log)
{
srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance();
//Init log
m_mbms_gw_log = mbms_gw_log;
err = init_sgi_mb_if(args);
if (err != srslte::ERROR_NONE)
{
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
return -1;
}
err = init_m1_u(args);
if (err != srslte::ERROR_NONE)
{
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
return -1;
}
m_mbms_gw_log->info("MBMS GW Initiated\n");
m_mbms_gw_log->console("MBMS GW Initiated\n");
return 0;
}
void
mbms_gw::stop()
{
if(m_running)
{
if(m_sgi_mb_up)
{
close(m_sgi_mb_if);
m_mbms_gw_log->info("Closed SGi-MB interface\n");
}
m_running = false;
thread_cancel();
wait_thread_finish();
}
return;
}
srslte::error_t
mbms_gw::init_sgi_mb_if(mbms_gw_args_t *args)
{
char dev[IFNAMSIZ] = "sgi_mb";
struct ifreq ifr;
if(m_sgi_mb_up)
{
return(srslte::ERROR_ALREADY_STARTED);
}
// Construct the TUN device
m_sgi_mb_if = open("/dev/net/tun", O_RDWR);
m_mbms_gw_log->info("TUN file descriptor = %d\n", m_sgi_mb_if);
if(m_sgi_mb_if < 0)
{
m_mbms_gw_log->error("Failed to open TUN device: %s\n", strerror(errno));
return(srslte::ERROR_CANT_START);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
if(ioctl(m_sgi_mb_if, TUNSETIFF, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
// Bring up the interface
int sgi_mb_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sgi_mb_sock<0)
{
m_mbms_gw_log->error("Failed to bring up socket: %s\n", strerror(errno));
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
if(ioctl(sgi_mb_sock, SIOCGIFFLAGS, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to bring up interface: %s\n", strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return(srslte::ERROR_CANT_START);
}
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(sgi_mb_sock, SIOCSIFFLAGS, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to set socket flags: %s\n", strerror(errno));
close(sgi_mb_sock);
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
//Set IP of the interface
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_mb_if_addr.c_str());
addr->sin_port = 0;
if (ioctl(sgi_mb_sock, SIOCSIFADDR, &ifr) < 0) {
m_mbms_gw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_mb_if_addr.c_str(), strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return srslte::ERROR_CANT_START;
}
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.255");
if (ioctl(sgi_mb_sock, SIOCSIFNETMASK, &ifr) < 0) {
m_mbms_gw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return srslte::ERROR_CANT_START;
}
m_sgi_mb_up = true;
close(sgi_mb_sock);
return(srslte::ERROR_NONE);
}
srslte::error_t
mbms_gw::init_m1_u(mbms_gw_args_t *args)
{
int addrlen;
struct sockaddr_in addr;
m_m1u = socket(AF_INET, SOCK_DGRAM, 0);
if(m_m1u<0)
{
m_mbms_gw_log->error("Failed to open socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_m1u_up = true;
/* set no loopback */
char loopch = 0;
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loopch, sizeof(char))<0){
m_mbms_gw_log->error("Failed to disable loopback: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
} else {
m_mbms_gw_log->debug("Loopback disabled\n");
}
/* Set local interface for outbound multicast packets*/
/* The IP must be associated with a local multicast capable interface */
struct in_addr local_if;
local_if.s_addr = inet_addr("127.0.1.200");
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_if, sizeof(struct in_addr))<0){
perror("Error setting multicast interface.\n");
} else {
printf("Multicast interface specified.\n");
}
bzero(&m_m1u_multi_addr,sizeof(m_m1u_multi_addr));
m_m1u_multi_addr.sin_family = AF_INET;
m_m1u_multi_addr.sin_port = htons(GTPU_RX_PORT+1);
m_m1u_multi_addr.sin_addr.s_addr = inet_addr(args->m1u_multi_addr.c_str());
m_mbms_gw_log->info("Initialized M1-U\n");
return srslte::ERROR_NONE;
}
void
mbms_gw::run_thread()
{
//Mark the thread as running
m_running=true;
srslte::byte_buffer_t *msg;
msg = m_pool->allocate();
uint8_t seq = 0;
while(m_running)
{
msg->reset();
int n;
do{
n = read(m_sgi_mb_if, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
}while(n == -1 && errno == EAGAIN);
if(n<0){
m_mbms_gw_log->error("Error reading from TUN interface. Error: %s\n", strerror(errno));
}
else{
msg->N_bytes = n;
handle_sgi_md_pdu(msg);
}
}
m_pool->deallocate(msg);
return;
}
void
mbms_gw::handle_sgi_md_pdu(srslte::byte_buffer_t *msg)
{
uint8_t version;
srslte::gtpu_header_t header;
in_addr_t baddr = inet_addr("172.16.0.255");
//Setup GTP-U header
header.flags = 0x30;
header.message_type = 0xFF;
header.length = msg->N_bytes;
header.teid = 0xAAAA; //FIXME Harcoded TEID for now
//Sanity Check IP packet
if(msg->N_bytes < 20)
{
m_mbms_gw_log->error("IPv4 min len: %d, drop msg len %d\n", 20, msg->N_bytes);
return;
}
version = msg->msg[0]>>4;
if(version !=4)
{
m_mbms_gw_log->warning("IPv6 not supported yet.\n");
return;
}
//Replace Destination IP with broadcast address
memcpy(&msg->msg[16],&baddr,4);
//Write GTP-U header into packet
if(!srslte::gtpu_write_header(&header, msg))
{
m_mbms_gw_log->console("Error writing GTP-U header on PDU\n");
}
int n = sendto(m_m1u, msg->msg, msg->N_bytes, 0,
(sockaddr *) &m_m1u_multi_addr, sizeof(struct sockaddr));
if(n<0){
m_mbms_gw_log->console("Error writting to M1-U socket.\n");
}
else{
m_mbms_gw_log->console("Sent %d Bytes\n", msg->N_bytes);
}
}
} //namespace srsepc

@ -74,9 +74,10 @@ private:
nas_interface_gw *nas;
srslte::byte_buffer_pool *pool;
srslte::log *gw_log;
srslte::srslte_gw_config_t cfg;
bool running;
bool run_enable;
int32 tun_fd;

@ -271,6 +271,7 @@ void ra_proc::step_preamble_transmission() {
}
void ra_proc::step_pdcch_setup() {
int ra_tti = phy_h->prach_tx_tti();
if (ra_tti > 0) {
ra_rnti = 1+ra_tti%10;
@ -387,7 +388,7 @@ void ra_proc::step_response_reception() {
if (ra_tti >= 0 && !rar_received) {
uint32_t interval = srslte_tti_interval(phy_h->get_current_tti(), ra_tti+3+responseWindowSize);
if (interval > 1 && interval < 100) {
rDebug("RA response not received within the response window\n");
Error("RA response not received within the response window\n");
state = RESPONSE_ERROR;
}
}

@ -72,7 +72,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
{
if (file.is_open() && ue != NULL) {
if(n_reports == 0) {
file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_ta;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;is_attached\n";
file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_ta,ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;is_attached\n";
}
file << (metrics_report_period*n_reports) << ";";
file << float_to_string(metrics.phy.dl.rsrp, 2);

@ -51,6 +51,7 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
rx_gain_offset = 0;
last_ri = 0;
last_pmi = 0;
//have_mtch_stop = false;
bzero(&dl_metrics, sizeof(dl_metrics_t));
dl_metrics_read = true;

@ -392,6 +392,7 @@ void phch_recv::run_thread()
phy_state.state_exit();
break;
case sync_state::SFN_SYNC:
/* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe
* and returns
*/
@ -473,6 +474,7 @@ void phch_recv::run_thread()
is_end_of_burst = true;
// Start worker
workers_pool->start_worker(worker);
@ -500,6 +502,7 @@ void phch_recv::run_thread()
}
break;
case sync_state::IDLE:
if (radio_h->is_init()) {
uint32_t nsamples = 1920;
if (current_srate > 0) {

@ -133,6 +133,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_ph
return false;
}
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled);
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask);

@ -354,6 +354,7 @@ uint32_t phy::get_current_tti()
return sf_recv.get_current_tti();
}
void phy::sr_send()
{
workers_common.sr_enabled = true;

Loading…
Cancel
Save