Moved srsapps to srsue repository

master
ismagom 9 years ago
parent a5c43d9959
commit 510e4c892e

@ -151,4 +151,3 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/mex/include)
######################################################################## ########################################################################
ADD_SUBDIRECTORY(srslte) ADD_SUBDIRECTORY(srslte)
ADD_SUBDIRECTORY(mex) ADD_SUBDIRECTORY(mex)
ADD_SUBDIRECTORY(srsapps)

@ -1,34 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
########################################################################
# Install headers
########################################################################
remove_definitions(-fvisibility=hidden)
INCLUDE_DIRECTORIES(radio/include/)
INCLUDE_DIRECTORIES(common/include/)
add_subdirectory(radio)
add_subdirectory(common)
add_subdirectory(ue)

@ -1,34 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
INSTALL(DIRECTORY include/
DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
FILE(GLOB SOURCES "src/*.cc")
ADD_LIBRARY(srsapps_common SHARED ${SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/src/threads.c)
INSTALL(TARGETS srsapps_common DESTINATION ${LIBRARY_DIR})
SRSLTE_SET_PIC(srsapps_common)
FILE(GLOB HEADERS_ALL "include/srsapps/common/*.h")
ADD_CUSTOM_TARGET (add_srsapps_common_headers SOURCES ${HEADERS_ALL})

@ -1,64 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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/.
*
*/
#ifndef CONFIG_H
#define CONFIG_H
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
#define SRSAPPS_IMPORT __declspec(dllimport)
#define SRSAPPS_EXPORT __declspec(dllexport)
#define SRSAPPS_LOCAL
#else
#if __GNUC__ >= 4
#define SRSAPPS_IMPORT __attribute__ ((visibility ("default")))
#define SRSAPPS_EXPORT __attribute__ ((visibility ("default")))
#else
#define SRSAPPS_IMPORT
#define SRSAPPS_EXPORT
#define SRSAPPS_LOCAL
#endif
#endif
// Define SRSAPPS_API
// is used for the public API symbols.
#ifdef SRSAPPS_DLL_EXPORTS // defined if we are building the SRSAPPS DLL (instead of using it)
#define SRSAPPS_EXPORT
#else
#define SRSAPPS_IMPORT
#endif
// Common error codes
#define SRSAPPS_SUCCESS 0
#define SRSAPPS_ERROR -1
#define SRSAPPS_ERROR_INVALID_INPUTS -2
// cf_t definition
typedef _Complex float cf_t;
#endif // CONFIG_H

@ -1,101 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
/******************************************************************************
* File: log.h
*
* Description: Abstract logging service
*
* Reference:
*****************************************************************************/
#ifndef LOG_H
#define LOG_H
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
namespace srslte {
class log
{
public:
log(std::string service_name_) { service_name = service_name_; tti = 0; level = LOG_LEVEL_NONE; }
// This function shall be called at the start of every tti for printing tti
void step(uint32_t tti_) {
tti = tti_;
}
typedef enum {
LOG_LEVEL_NONE = 0,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG
} log_level_t;
void set_level_info() {
level = LOG_LEVEL_INFO;
}
void set_level_debug() {
level = LOG_LEVEL_DEBUG;
}
uint32_t get_tti() {
return tti;
}
// Pure virtual methods for logging
virtual void error(std::string message, ...) = 0;
virtual void warning(std::string message, ...) = 0;
virtual void info(std::string message, ...) = 0;
virtual void debug(std::string message, ...) = 0;
// Same with line and file info
virtual void error_line(std::string file, int line, std::string message, ...) = 0;
virtual void warning_line(std::string file, int line, std::string message, ...) = 0;
virtual void info_line(std::string file, int line, std::string message, ...) = 0;
virtual void debug_line(std::string file, int line, std::string message, ...) = 0;
protected:
std::string get_service_name() { return service_name; }
uint32_t tti;
log_level_t level;
private:
std::string service_name;
};
}
#endif

@ -1,78 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
#include <stdarg.h>
#include "srsapps/common/log.h"
/******************************************************************************
* File: log_stout.h
*
* Description: Logging service through standard output. Inherits log interface
*
* Reference:
*****************************************************************************/
#ifndef LOGSTDOUT_H
#define LOGSTDOUT_H
using namespace std;
namespace srslte {
class log_stdout : public log
{
public:
log_stdout(string service_name_) : log(service_name_) { }
void error(string message, ...);
void warning(string message, ...);
void info(string message, ...);
void debug(string message, ...);
// Same with line and file info
void error_line(string file, int line, string message, ...);
void warning_line(string file, int line, string message, ...);
void info_line(string file, int line, string message, ...);
void debug_line(string file, int line, string message, ...);
private:
typedef enum {
ERROR=0, WARNING, INFO, DEBUG, NOF_LEVELS
} level_t;
void printlog(level_t level, uint32_t tti, string file, int line, string message, va_list args);
void printlog(level_t level, uint32_t tti, string message, va_list args);
};
}
#endif

@ -1,215 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
#include "srslte/srslte.h"
/******************************************************************************
* File: mac_interface.h
*
* Description: LTE MAC layer interface
*
* Reference:
*****************************************************************************/
#ifndef MAC_INTERFACE_H
#define MAC_INTERFACE_H
namespace srslte {
namespace ue {
/* Interface PHY -> MAC */
class mac_interface_phy
{
public:
typedef struct {
uint32_t pid;
uint32_t tti;
bool ndi;
uint32_t n_bytes;
uint32_t rv;
uint16_t rnti;
bool is_from_rar;
bool is_sps_release;
srslte_rnti_type_t rnti_type;
srslte_phy_grant_t phy_grant;
} mac_grant_t;
typedef struct {
bool decode_enabled;
uint32_t rv;
uint16_t rnti;
bool generate_ack;
bool default_ack;
// If non-null, called after tb_decoded_ok to determine if ack needs to be sent
bool (*generate_ack_callback)(void*);
void *generate_ack_callback_arg;
uint8_t *payload_ptr;
srslte_softbuffer_rx_t *softbuffer;
srslte_phy_grant_t phy_grant;
} tb_action_dl_t;
typedef struct {
bool tx_enabled;
bool expect_ack;
uint32_t rv;
uint16_t rnti;
uint32_t current_tx_nb;
srslte_softbuffer_tx_t *softbuffer;
srslte_phy_grant_t phy_grant;
uint8_t *payload_ptr;
} tb_action_ul_t;
/* Indicate reception of UL grant.
* payload_ptr points to memory where MAC PDU must be written by MAC layer */
virtual void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) = 0;
/* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */
virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of HARQ information only through PHICH. */
virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of DL grant. */
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
/* Indicate successfull decoding of PDSCH TB. */
virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
/* Indicate successfull decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0;
/* Function called every start of a subframe (TTI). Warning, this function is called
* from a high priority thread and should terminate asap
*/
virtual void tti_clock(uint32_t tti) = 0;
};
/* Interface RLC -> MAC */
class mac_interface_rlc
{
public:
/* RLC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
virtual uint32_t get_current_tti() = 0;
virtual void reconfiguration() = 0;
virtual void reset() = 0;
};
/* Interface MAC -> RLC */
class rlc_interface_mac
{
public:
/* MAC calls RLC to get buffer state for a logical channel. This function should return quickly */
virtual uint32_t get_buffer_state(uint32_t lcid) = 0;
const static int MAX_PDU_SEGMENTS = 20;
/* MAC calls RLC to get RLC segment of nof_bytes length. Segmentation happens in this function. RLC PDU is stored in
* payload. */
virtual int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
/* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. PDU gets placed into the
* PDCP buffer and higher layer thread gets notified
* when the last segment is received
*/
virtual void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0;
};
class mac_interface_params
{
public:
typedef enum {
SPS_DL_SCHED_INTERVAL,
SPS_DL_NOF_PROC,
RNTI_TEMP,
RNTI_C,
BCCH_SI_WINDOW_ST,
BCCH_SI_WINDOW_LEN,
PCCH_RECEIVE,
CONTENTION_ID, // Transmitted UE Contention ID
TIMER_TIMEALIGN,
// Random Access parameters. See 5.1.1
RA_CONFIGINDEX,
RA_PREAMBLEINDEX,
RA_MASKINDEX,
RA_NOFPREAMBLES,
RA_NOFGROUPAPREAMBLES,
RA_MESSAGEPOWEROFFSETB,
RA_MESSAGESIZEA,
RA_PCMAX,
RA_DELTAPREAMBLEMSG3,
RA_RESPONSEWINDOW,
RA_POWERRAMPINGSTEP,
RA_PREAMBLETRANSMAX,
RA_INITRECEIVEDPOWER,
RA_CONTENTIONTIMER,
SR_PUCCH_CONFIGURED,
SR_TRANS_MAX,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
HARQ_MAXTX,
HARQ_MAXMSG3TX,
PDSCH_RSPOWER,
PDSCH_PB,
NOF_PARAMS,
} mac_param_t;
/* Sets/gets a parameter */
virtual void set_param(mac_param_t param, int64_t value) = 0;
virtual int64_t get_param(mac_param_t param) = 0;
};
}
}
#endif

@ -1,71 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdlib.h>
#ifndef PARAMS_H
#define PARAMS_H
namespace srslte {
namespace ue {
class params_db
{
public:
params_db(uint32_t nof_params_) {
nof_params = nof_params_;
db = (int64_t*) calloc(sizeof(int64_t), nof_params);
for (int i=0;i<nof_params;i++) {
db[i] = 0;
}
}
~params_db() {
free(db);
}
void set_param(uint32_t param_idx, int64_t value) {
if (param_idx < nof_params) {
db[param_idx] = value;
}
}
int64_t get_param(uint32_t param_idx) {
if (param_idx < nof_params) {
return db[param_idx];
} else {
return -1;
}
}
private:
uint32_t nof_params;
int64_t *db;
};
}
}
#endif

@ -1,166 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
#include "srslte/srslte.h"
/******************************************************************************
* File: phy_interface.h
*
* Description: LTE PHY layer interface
*
* Reference:
*****************************************************************************/
#ifndef PHY_INTERFACE_H
#define PHY_INTERFACE_H
namespace srslte {
namespace ue {
class phy_interface_params
{
public:
/* PHY parameters */
typedef enum {
DL_FREQ = 0,
UL_FREQ,
CELLSEARCH_TIMEOUT_PSS_NFRAMES,
CELLSEARCH_TIMEOUT_MIB_NFRAMES,
CELLSEARCH_TIMEOUT_PSS_CORRELATION_THRESHOLD, // integer that will be divided by 10
PUSCH_EN_64QAM,
PUSCH_RS_CYCLIC_SHIFT,
PUSCH_RS_GROUP_ASSIGNMENT,
DMRS_GROUP_HOPPING_EN,
DMRS_SEQUENCE_HOPPING_EN,
PUSCH_HOPPING_N_SB,
PUSCH_HOPPING_INTRA_SF,
PUSCH_HOPPING_OFFSET,
PUCCH_DELTA_SHIFT,
PUCCH_CYCLIC_SHIFT,
PUCCH_N_RB_2,
PUCCH_N_PUCCH_1_0,
PUCCH_N_PUCCH_1_1,
PUCCH_N_PUCCH_1_2,
PUCCH_N_PUCCH_1_3,
PUCCH_N_PUCCH_1,
PUCCH_N_PUCCH_2,
PUCCH_N_PUCCH_SR,
SR_CONFIG_INDEX,
SRS_UE_TXCOMB,
SRS_UE_NRRC,
SRS_UE_DURATION,
SRS_UE_CONFIGINDEX,
SRS_UE_BW,
SRS_UE_HOP,
SRS_UE_CS,
SRS_UE_CYCLICSHIFT,
SRS_CS_BWCFG,
SRS_CS_SFCFG,
SRS_CS_ACKNACKSIMUL,
SRS_IS_CONFIGURED,
CQI_PERIODIC_PMI_IDX,
CQI_PERIODIC_SIMULT_ACK,
CQI_PERIODIC_FORMAT_SUBBAND,
CQI_PERIODIC_FORMAT_SUBBAND_K,
CQI_PERIODIC_CONFIGURED,
UCI_I_OFFSET_ACK,
UCI_I_OFFSET_RI,
UCI_I_OFFSET_CQI,
PRACH_CONFIG_INDEX,
PRACH_ROOT_SEQ_IDX,
PRACH_HIGH_SPEED_FLAG,
PRACH_ZC_CONFIG,
PRACH_FREQ_OFFSET,
NOF_PARAMS,
} phy_param_t;
/* Get/Set PHY parameters */
virtual void set_param(phy_param_t param, int64_t value) = 0;
virtual int64_t get_param(phy_param_t param) = 0;
};
/* Interface MAC -> PHY */
class phy_interface
{
public:
/* Instructs the PHY to configure using the parameters written with set_param()
* These two functions may take a while to return.
*/
virtual void configure_prach_params() = 0;
virtual void configure_ul_params() = 0;
/* Start synchronization with strongest cell in the current carrier frequency */
virtual void sync_start() = 0;
virtual void sync_stop() = 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;
/* Time advance commands */
virtual void set_timeadv_rar(uint32_t ta_cmd) = 0;
virtual void set_timeadv(uint32_t ta_cmd) = 0;
/* Sets RAR grant payload */
virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 0;
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_ul_search_reset() = 0;
virtual void pdcch_dl_search_reset() = 0;
virtual uint32_t get_current_tti() = 0;
virtual void reset() = 0;
};
}
}
#endif

@ -1,93 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#ifndef QBUFF_H
#define QBUFF_H
/** Implementation of a lock-free single-producer single-consumer queue buffer
* Communication can be pointer-based or stream based.
* Only 1 thread can read and only 1 thread can write.
*
* Writer:
* - Call request, returns a pointer.
* - Writes to memory, up to max_msg_size bytes
* - Call to push() passing message size
* or
* - use send()
*
* Reader:
* - Call to pop, receive pointer and message size
* - Read memory contents
* - Call to release() to release the message buffer
* or
* - use recv()
*/
namespace srslte {
class qbuff
{
public:
qbuff();
~qbuff();
bool init(uint32_t nof_messages, uint32_t max_msg_size);
void* request();
bool push(uint32_t len);
void* pop(uint32_t *len, uint32_t idx);
void* pop(uint32_t *len);
void* pop();
void release();
bool isempty();
bool isfull();
void flush();
bool send(void *buffer, uint32_t msg_size);
int recv(void* buffer, uint32_t buffer_size);
void move_to(qbuff *dst);
uint32_t pending_data();
private:
typedef struct {
bool valid;
uint32_t len;
void *ptr;
} pkt_t;
uint32_t nof_messages;
uint32_t max_msg_size;
uint32_t rp, wp;
pkt_t *packets;
uint8_t *buffer;
};
}
#endif

@ -1,65 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <pthread.h>
#include <stdint.h>
#include <string>
#include <queue>
#include "srsapps/common/threads.h"
/******************************************************************************
* File: task_dispatcher.h
*
* Description: Implements a pool of threads. Pending tasks to execute are
* identified by a pointer.
*
* Reference:
*****************************************************************************/
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
namespace srslte {
class task_dispatcher : public thread
{
public:
task_dispatcher(uint32_t max_pending_tasks);
~task_dispatcher();
void push_task(uint32_t task_code);
virtual void run_task(uint32_t task_code) = 0;
private:
std::queue<uint32_t> pending_tasks;
void run_thread();
pthread_mutex_t mutex;
pthread_cond_t cvar;
bool running;
};
}
#endif

@ -1,107 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
#include <vector>
#include <stack>
#include "srsapps/common/threads.h"
/******************************************************************************
* File: thread_pool.h
*
* Description: Implements a pool of threads. Pending tasks to execute are
* identified by a pointer.
*
* Reference:
*****************************************************************************/
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
namespace srslte {
class thread_pool
{
public:
class worker : public thread
{
public:
void setup(uint32_t id, thread_pool *parent, uint32_t prio=0);
void stop();
uint32_t get_id();
void release();
protected:
virtual void work_imp() = 0;
private:
uint32_t my_id;
thread_pool *my_parent;
bool running;
void run_thread();
void wait_to_start();
void finished();
};
thread_pool(uint32_t nof_workers);
void init_worker(uint32_t id, worker*, uint32_t prio = 0);
void stop();
worker* wait_worker();
worker* wait_worker(uint32_t tti);
void start_worker(worker*);
void start_worker(uint32_t id);
worker* get_worker(uint32_t id);
uint32_t get_nof_workers();
private:
bool find_finished_worker(uint32_t tti, uint32_t *id);
typedef enum {
IDLE,
START_WORK,
WORKER_READY,
WORKING
}worker_status;
std::vector<worker*> workers;
uint32_t nof_workers;
bool running;
pthread_cond_t cvar_queue;
pthread_mutex_t mutex_queue;
std::vector<worker_status> status;
std::vector<pthread_cond_t> cvar;
std::vector<pthread_mutex_t> mutex;
std::stack<worker*> available_workers;
};
}
#endif

@ -1,68 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <pthread.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg);
bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, uint32_t prio_offset);
bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, uint32_t prio_offset);
void threads_print_self();
#ifdef __cplusplus
}
#ifndef THREADS_
#define THREADS_
class thread
{
public:
bool start(uint32_t prio = 0) {
return threads_new_rt_prio(&_thread, thread_function_entry, this, prio);
}
void print_priority() {
threads_print_self();
}
void wait_thread_finish() {
pthread_join(_thread, NULL);
}
protected:
virtual void run_thread() = 0;
private:
static void *thread_function_entry(void *_this) { ((thread*) _this)->run_thread();}
pthread_t _thread;
};
#endif
#endif

@ -1,127 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <vector>
#ifndef TIMERS_H
#define TIMERS_H
namespace srslte {
class timer_callback
{
public:
virtual void timer_expired(uint32_t timer_id) = 0;
};
class timers
{
public:
class timer
{
public:
timer() { counter = 0; timeout = 0; running = false; };
void set(timer_callback *callback_, uint32_t timeout_) {
callback = callback_;
timeout = timeout_;
}
bool is_running() {
return counter < timeout;
}
bool is_expired() {
return counter == timeout;
}
void reset() {
counter = 0;
}
void step() {
if (running) {
counter++;
if (is_expired()) {
callback->timer_expired(id);
}
}
}
void stop() {
running = false;
}
void run() {
running = true;
}
uint32_t id;
private:
timer_callback *callback;
uint32_t timeout;
uint32_t counter;
bool running;
};
timers(uint32_t nof_timers_) : timer_list(nof_timers_) {
nof_timers = nof_timers_;
for (uint32_t i=0;i<nof_timers;i++) {
timer_list[i].id = i;
}
}
void step_all() {
for (int i=0;i<nof_timers;i++) {
get(i)->step();
}
}
void stop_all() {
for (int i=0;i<nof_timers;i++) {
get(i)->stop();
}
}
void run_all() {
for (int i=0;i<nof_timers;i++) {
get(i)->run();
}
}
void reset_all() {
for (int i=0;i<nof_timers;i++) {
get(i)->reset();
}
}
timer *get(uint32_t i) {
if (i < nof_timers) {
return &timer_list[i];
} else {
printf("Error accessing invalid timer %d (Only %d timers available)\n", i, nof_timers);
return NULL;
}
}
private:
uint32_t nof_timers;
std::vector<timer> timer_list;
};
}
#endif

@ -1,98 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdio.h>
#include <string>
#include <vector>
#ifndef TRACE_H
#define TRACE_H
namespace srslte {
template<class elemType>
class trace
{
public:
trace(uint32_t nof_elems_) : tti(nof_elems_), data(nof_elems_) {
rpm=0;
nof_elems=nof_elems_;
wrapped = false;
};
void push_cur_time_us(uint32_t cur_tti) {
struct timeval t;
gettimeofday(&t, NULL);
elemType us = t.tv_sec*1e6+t.tv_usec;
push(cur_tti, us);
}
void push(uint32_t value_tti, elemType value) {
tti[rpm] = value_tti;
data[rpm] = value;
rpm++;
if (rpm >= nof_elems) {
rpm = 0;
wrapped = true;
}
}
bool writeToBinary(std::string filename) {
FILE *f = fopen(filename.c_str(), "w");
if (f != NULL) {
uint32_t st=wrapped?(rpm+1):0;
do {
writeToBinaryValue(f, st++);
if (st >= nof_elems) {
st=0;
}
} while(st!=rpm);
fclose(f);
return true;
} else {
perror("fopen");
return false;
}
}
private:
std::vector<uint32_t> tti;
std::vector<elemType> data;
uint32_t rpm;
uint32_t nof_elems;
bool wrapped;
void writeToBinaryValue(FILE *f, uint32_t idx) {
fwrite(&tti[idx], 1, sizeof(uint32_t), f);
fwrite(&data[idx], 1, sizeof(elemType), f);
}
};
}
#endif

@ -1,80 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#ifndef TTISYNC_H
#define TTISYNC_H
namespace srslte {
namespace ue {
/* Interface used for PHY-MAC synchronization (producer-consumer model).
* The consumer waits while its counter is lower than the producer counter.
* The PHY is the consumer. The MAC is the producer.
*/
class tti_sync
{
public:
tti_sync(uint32_t modulus_)
{
modulus = modulus_;
increment = 1;
init_counters(0);
}
virtual void increase() = 0;
virtual void resync() = 0;
virtual uint32_t wait() = 0;
virtual void set_producer_cntr(uint32_t) = 0;
uint32_t get_producer_cntr() { return producer_cntr; }
uint32_t get_consumer_cntr() { return consumer_cntr; }
void set_increment(uint32_t increment_) {
increment = increment_;
}
protected:
void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; }
void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; }
bool wait_condition() { return producer_cntr == consumer_cntr; }
void init_counters(uint32_t val)
{
consumer_cntr = val;
producer_cntr = val;
}
uint32_t increment;
uint32_t modulus;
uint32_t producer_cntr;
uint32_t consumer_cntr;
};
}
}
#endif

@ -1,61 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <pthread.h>
#include "srsapps/common/tti_sync.h"
#ifndef TTISYNC_CV_H
#define TTISYNC_CV_H
namespace srslte {
namespace ue {
/* Implements tti_sync interface with condition variables.
*/
class tti_sync_cv : public tti_sync
{
public:
tti_sync_cv(uint32_t modulus = 10240);
~tti_sync_cv();
void increase();
uint32_t wait();
void resync();
void set_producer_cntr(uint32_t producer_cntr);
private:
pthread_cond_t cond;
pthread_mutex_t mutex;
};
}
}
#endif

@ -1,137 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include <string>
#include <stdarg.h>
#include <stdio.h>
#include "srsapps/common/log_stdout.h"
using namespace std;
namespace srslte {
const char* level_str[4] = {"[ERROR ",
"[WARN ",
"[INFO ",
"[DEBUG "};
void log_stdout::printlog(level_t type, uint32_t tti, string msg, va_list args) {
printlog(type, tti, string(), -1, msg, args);
}
void log_stdout::printlog(level_t type, uint32_t tti, string file, int line, string msg, va_list args) {
printf("%s %s",level_str[type], get_service_name().c_str());
if (file.length() > 0) {
printf("/%-14s", file.substr(file.find_last_of("/")+1,file.find_last_of(".")-1-file.find_last_of("/")).c_str());
}
if (line >= 0) {
printf(" %5d]: ", tti);
}
vprintf(msg.c_str(), args);
}
void log_stdout::error(string msg, ...)
{
va_list args;
va_start(args, msg);
printlog(ERROR, tti, msg, args);
va_end(args);
}
void log_stdout::info(string msg, ...)
{
if (level >= LOG_LEVEL_INFO) {
va_list args;
va_start(args, msg);
printlog(INFO, tti, msg, args);
va_end(args);
}
}
void log_stdout::debug(string msg, ...)
{
if (level >= LOG_LEVEL_DEBUG) {
va_list args;
va_start(args, msg);
printlog(DEBUG, tti, msg, args);
va_end(args);
}
}
void log_stdout::warning(string msg, ...)
{
va_list args;
va_start(args, msg);
printlog(WARNING, tti, msg, args);
va_end(args);
}
void log_stdout::error_line(string file, int line, string msg, ...)
{
va_list args;
va_start(args, msg);
printlog(ERROR, tti, file, line, msg, args);
va_end(args);
}
void log_stdout::info_line(string file, int line, string msg, ...)
{
if (level >= LOG_LEVEL_INFO) {
va_list args;
va_start(args, msg);
printlog(INFO, tti, file, line, msg, args);
va_end(args);
}
}
void log_stdout::debug_line(string file, int line, string msg, ...)
{
if (level >= LOG_LEVEL_DEBUG) {
va_list args;
va_start(args, msg);
printlog(DEBUG, tti, file, line, msg, args);
va_end(args);
}
}
void log_stdout::warning_line(string file, int line, string msg, ...)
{
va_list args;
va_start(args, msg);
printlog(WARNING, tti, file, line, msg, args);
va_end(args);
}
}

@ -1,215 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "srsapps/common/qbuff.h"
namespace srslte {
qbuff::qbuff()
{
nof_messages=0;
max_msg_size=0;
wp = 0;
rp = 0;
buffer = NULL;
packets = NULL;
}
qbuff::~qbuff()
{
free(buffer);
free(packets);
}
bool qbuff::init(uint32_t nof_messages_, uint32_t max_msg_size_)
{
nof_messages = nof_messages_;
max_msg_size = max_msg_size_;
buffer = (uint8_t*) calloc(nof_messages,max_msg_size);
packets = (pkt_t*) calloc(nof_messages,sizeof(pkt_t));
if (buffer && packets) {
flush();
return true;
} else {
return false;
}
}
void qbuff::flush()
{
wp = 0;
rp = 0;
for (int i=0;i<nof_messages;i++) {
packets[i].valid = false;
packets[i].ptr = &buffer[i*max_msg_size];
packets[i].len = 0;
}
}
bool qbuff::isempty()
{
return !packets[rp].valid;
}
bool qbuff::isfull()
{
return packets[wp].valid;
}
void* qbuff::request()
{
if (!isfull()) {
return packets[wp].ptr;
} else {
return NULL;
}
}
bool qbuff::push(uint32_t len)
{
packets[wp].len = len;
packets[wp].valid = true;
wp += (wp+1 >= nof_messages)?(1-nof_messages):1;
return true;
}
void* qbuff::pop()
{
return pop(NULL);
}
void* qbuff::pop(uint32_t* len)
{
if (!isempty()) {
if (len) {
*len = packets[rp].len;
}
return packets[rp].ptr;
} else {
return NULL;
}
}
void* qbuff::pop(uint32_t* len, uint32_t idx)
{
if (idx == 0) {
return pop(len);
} else {
uint32_t rpp = rp;
uint32_t i = 0;
while(i<idx && packets[rpp].valid) {
rpp += (rpp+1 >= nof_messages)?(1-nof_messages):1;
i++;
}
if (packets[rpp].valid) {
if (len) {
*len = packets[rpp].len;
}
return packets[rpp].ptr;
} else {
return NULL;
}
}
}
void qbuff::release()
{
packets[rp].valid = false;
packets[rp].len = 0;
rp += (rp+1 >= nof_messages)?(1-nof_messages):1;
}
bool qbuff::send(void* buffer, uint32_t msg_size)
{
if (msg_size <= max_msg_size) {
void *ptr = request();
if (ptr) {
memcpy(ptr, buffer, msg_size);
return push(msg_size);
} else {
printf("No ptr\n");
return false;
}
} else {
return false;
}
}
uint32_t qbuff::pending_data()
{
uint32_t total_len = 0;
for (int i=0;i<nof_messages;i++) {
total_len += packets[i].len;
}
return total_len;
}
// Move packets between queues with only 1 memcpy
void qbuff::move_to(qbuff *dst) {
uint32_t len;
void *ptr_src = pop(&len);
if (ptr_src) {
void *ptr_dst = dst->request();
if (ptr_dst) {
memcpy(ptr_dst, ptr_src, len);
dst->push(len);
release();
}
}
}
int qbuff::recv(void* buffer, uint32_t buffer_size)
{
uint32_t len;
void *ptr = pop(&len);
if (ptr) {
if (len <= buffer_size) {
memcpy(buffer, ptr, len);
release();
return len;
} else {
return -1;
}
} else {
return 0;
}
}
}

@ -1,75 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 "srsapps/common/task_dispatcher.h"
#include <queue>
namespace srslte {
task_dispatcher::task_dispatcher(uint32_t max_pending_tasks)
{
pthread_cond_init(&cvar, NULL);
pthread_mutex_init(&mutex, NULL);
}
task_dispatcher::~task_dispatcher()
{
running = false;
pthread_cond_signal(&cvar);
wait_thread_finish();
pthread_cond_destroy(&cvar);
pthread_mutex_destroy(&mutex);
}
void task_dispatcher::push_task(uint32_t task_code)
{
pthread_mutex_lock(&mutex);
pending_tasks.push(task_code);
pthread_cond_signal(&cvar);
pthread_mutex_unlock(&mutex);
}
void task_dispatcher::run_thread()
{
running = true;
while(running) {
uint32_t task = 0;
pthread_mutex_lock(&mutex);
while(pending_tasks.empty()) {
pthread_cond_wait(&cvar, &mutex);
}
task = (uint32_t) pending_tasks.front();
pending_tasks.pop();
pthread_mutex_unlock(&mutex);
if (running) {
run_task(task);
}
}
}
}

@ -1,252 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <stdio.h>
#include "srsapps/common/thread_pool.h"
#define DEBUG 0
#define debug_thread(fmt, ...) do { if(DEBUG) printf(fmt, __VA_ARGS__); } while(0)
#define USE_QUEUE
namespace srslte {
void thread_pool::worker::setup(uint32_t id, thread_pool *parent, uint32_t prio)
{
my_id = id;
my_parent = parent;
start(prio);
}
void thread_pool::worker::run_thread()
{
running = true;
while(running) {
wait_to_start();
if (running) {
work_imp();
finished();
}
}
}
uint32_t thread_pool::worker::get_id()
{
return my_id;
}
void thread_pool::worker::stop()
{
running = false;
pthread_cond_signal(&my_parent->cvar[my_id]);
wait_thread_finish();
}
thread_pool::thread_pool(uint32_t nof_workers_) :
workers(nof_workers_),
status(nof_workers_),
cvar(nof_workers_),
mutex(nof_workers_)
{
nof_workers = nof_workers_;
for (int i=0;i<nof_workers;i++) {
workers[i] = NULL;
status[i] = IDLE;
pthread_mutex_init(&mutex[i], NULL);
pthread_cond_init(&cvar[i], NULL);
}
pthread_mutex_init(&mutex_queue, NULL);
pthread_cond_init(&cvar_queue, NULL);
running = true;
}
void thread_pool::init_worker(uint32_t id, worker *obj, uint32_t prio)
{
if (id < nof_workers) {
pthread_mutex_lock(&mutex_queue);
workers[id] = obj;
available_workers.push(obj);
obj->setup(id, this, prio);
pthread_cond_signal(&cvar_queue);
pthread_mutex_unlock(&mutex_queue);
}
}
void thread_pool::stop()
{
/* Stop any thread waiting for available worker */
running = false;
/* Now stop all workers */
for (uint32_t i=0;i<nof_workers;i++) {
if (workers[i]) {
workers[i]->stop();
// Need to call start to wake it up
start_worker(i);
workers[i]->wait_thread_finish();
}
pthread_cond_destroy(&cvar[i]);
pthread_mutex_destroy(&mutex[i]);
}
pthread_cond_destroy(&cvar_queue);
pthread_mutex_destroy(&mutex_queue);
}
void thread_pool::worker::release()
{
finished();
}
void thread_pool::worker::wait_to_start()
{
debug_thread("wait_to_start() id=%d, status=%d, enter\n", my_id, my_parent->status[my_id]);
pthread_mutex_lock(&my_parent->mutex[my_id]);
while(my_parent->status[my_id] != START_WORK && running) {
pthread_cond_wait(&my_parent->cvar[my_id], &my_parent->mutex[my_id]);
}
my_parent->status[my_id] = WORKING;
pthread_mutex_unlock(&my_parent->mutex[my_id]);
debug_thread("wait_to_start() id=%d, status=%d, exit\n", my_id, my_parent->status[my_id]);
}
void thread_pool::worker::finished()
{
#ifdef USE_QUEUE
//my_parent->available_workers.push(this);
pthread_mutex_lock(&my_parent->mutex[my_id]);
my_parent->status[my_id] = IDLE;
pthread_mutex_unlock(&my_parent->mutex[my_id]);
pthread_mutex_lock(&my_parent->mutex_queue);
pthread_cond_signal(&my_parent->cvar_queue);
pthread_mutex_unlock(&my_parent->mutex_queue);
#else
pthread_mutex_lock(&my_parent->mutex[my_id]);
my_parent->status[my_id] = IDLE;
pthread_cond_signal(&my_parent->cvar[my_id]);
pthread_mutex_unlock(&my_parent->mutex[my_id]);
#endif
}
thread_pool::worker* thread_pool::wait_worker()
{
wait_worker(0);
}
bool thread_pool::find_finished_worker(uint32_t tti, uint32_t *id) {
for(int i=0;i<nof_workers;i++) {
if (status[i] == IDLE) {
*id = i;
return true;
}
}
return false;
}
thread_pool::worker* thread_pool::wait_worker(uint32_t tti)
{
thread_pool::worker *x;
#ifdef USE_QUEUE
debug_thread("wait_worker() - enter - tti=%d, state0=%d, state1=%d\n", tti, status[0], status[1]);
pthread_mutex_lock(&mutex_queue);
uint32_t id = 0;
while(!find_finished_worker(tti, &id) && running) {
pthread_cond_wait(&cvar_queue, &mutex_queue);
}
pthread_mutex_unlock(&mutex_queue);
if (running) {
x = workers[id];
pthread_mutex_lock(&mutex[id]);
status[id] = WORKER_READY;
pthread_mutex_unlock(&mutex[id]);
} else {
x = NULL;
}
debug_thread("wait_worker() - exit - id=%d, x=0x%x\n", id, x);
#else
uint32_t id = tti%nof_workers;
pthread_mutex_lock(&mutex[id]);
while(status[id] != IDLE && running) {
pthread_cond_wait(&cvar[id], &mutex[id]);
}
if (running) {
x = (worker*) workers[id];
status[id] = WORKER_READY;
} else {
x = NULL;
}
pthread_mutex_unlock(&mutex[id]);
#endif
return x;
}
void thread_pool::start_worker(uint32_t id) {
if (id < nof_workers) {
pthread_mutex_lock(&mutex[id]);
status[id] = START_WORK;
pthread_cond_signal(&cvar[id]);
pthread_mutex_unlock(&mutex[id]);
debug_thread("start_worker() id=%d, status=%d\n", id, status[id]);
}
}
void thread_pool::start_worker(worker* x)
{
for (uint32_t i=0;i<nof_workers;i++) {
if (x == workers[i]) {
start_worker(i);
return;
}
}
}
thread_pool::worker* thread_pool::get_worker(uint32_t id)
{
if (id < nof_workers) {
return workers[id];
}
}
uint32_t thread_pool::get_nof_workers()
{
return nof_workers;
}
}

@ -1,125 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include "srsapps/common/threads.h"
bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg) {
return threads_new_rt_prio(thread, start_routine, arg, 0);
}
bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, uint32_t prio_offset) {
return threads_new_rt_cpu(thread, start_routine, arg, -1, prio_offset);
}
bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, uint32_t prio_offset) {
bool ret = false;
pthread_attr_t attr;
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset;
pthread_attr_init(&attr);
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
perror("pthread_attr_setinheritsched");
}
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
perror("pthread_attr_setschedpolicy");
}
if (pthread_attr_setschedparam(&attr, &param)) {
perror("pthread_attr_setschedparam");
fprintf(stderr, "Error not enough privileges to set Scheduling priority\n");
}
if (cpu != -1) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET((size_t) cpu, &cpuset);
if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) {
perror("pthread_attr_setaffinity_np");
}
}
int err = pthread_create(thread, &attr, start_routine, arg);
if (err) {
if (EPERM == err) {
perror("Failed to create thread - permission error. Running with root permissions?");
}
perror("pthread_create");
} else {
ret = true;
}
pthread_attr_destroy(&attr);
return ret;
}
void threads_print_self() {
pthread_t thread;
cpu_set_t cpuset;
struct sched_param param;
int policy;
const char *p;
int s,j;
thread = pthread_self();
s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
if (s != 0) {
printf("error pthread_getaffinity_np: %s\n",strerror(s));
}
printf("Set returned by pthread_getaffinity_np() contained:\n");
for (j = 0; j < CPU_SETSIZE; j++) {
if (CPU_ISSET(j, &cpuset)) {
printf(" CPU %d\n", j);
}
}
s = pthread_getschedparam(thread, &policy, &param);
if (s != 0) {
printf("error pthread_getaffinity_np: %s\n", strerror(s));
}
switch(policy) {
case SCHED_FIFO:
p = "SCHED_FIFO";
break;
case SCHED_RR:
p = "SCHED_RR";
break;
default:
p = "Other";
break;
}
printf("Sched policy is %s. Priority is %d\n",p,param.sched_priority);
}

@ -1,80 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <pthread.h>
#include "srsapps/common/tti_sync_cv.h"
namespace srslte {
namespace ue {
tti_sync_cv::tti_sync_cv(uint32_t modulus): tti_sync(modulus)
{
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
}
tti_sync_cv::~tti_sync_cv()
{
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
}
uint32_t tti_sync_cv::wait()
{
pthread_mutex_lock(&mutex);
while(wait_condition()) {
pthread_cond_wait(&cond, &mutex);
}
uint32_t x = consumer_cntr;
increase_consumer();
pthread_mutex_unlock(&mutex);
return x;
}
void tti_sync_cv::resync()
{
consumer_cntr = producer_cntr;
}
void tti_sync_cv::set_producer_cntr(uint32_t producer_cntr)
{
pthread_mutex_lock(&mutex);
init_counters(producer_cntr);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
void tti_sync_cv::increase()
{
pthread_mutex_lock(&mutex);
increase_producer();
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
}

@ -1,38 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
FIND_PACKAGE(UHD)
INSTALL(DIRECTORY include/
DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
IF(UHD_FOUND)
FILE(GLOB SOURCES "src/*.cc")
ADD_LIBRARY(srsapps_radio SHARED ${SOURCES})
INSTALL(TARGETS srsapps_radio DESTINATION ${LIBRARY_DIR})
SRSLTE_SET_PIC(srsapps_radio)
ENDIF(UHD_FOUND)
FILE(GLOB HEADERS_ALL "include/srsapps/radio/*.h")
ADD_CUSTOM_TARGET (add_srsapps_radio_headers SOURCES ${HEADERS_ALL})

@ -1,70 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srslte/srslte.h"
#include "srslte/common/timestamp.h"
#ifndef RADIO_H
#define RADIO_H
namespace srslte {
/* Interface to the RF frontend.
*/
class SRSLTE_API radio
{
public:
virtual void get_time(srslte_timestamp_t *now) = 0;
virtual bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) = 0;
virtual bool tx_end() = 0;
virtual bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time) = 0;
virtual bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) = 0;
virtual void set_tx_gain(float gain) = 0;
virtual void set_rx_gain(float gain) = 0;
virtual double set_rx_gain_th(float gain) = 0;
virtual void set_tx_freq(float freq) = 0;
virtual void set_rx_freq(float freq) = 0;
virtual void set_tx_srate(float srate) = 0;
virtual void set_rx_srate(float srate) = 0;
virtual void start_rx() = 0;
virtual void stop_rx() = 0;
virtual float get_tx_gain() = 0;
virtual float get_rx_gain() = 0;
// This is used for debugging/trace purposes
virtual void set_tti(uint32_t tti) = 0;
};
}
#endif

@ -1,105 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/radio/radio.h"
#include "srslte/srslte.h"
#include "srslte/cuhd/cuhd.h"
#include "srsapps/common/trace.h"
#ifndef RADIO_UHD_H
#define RADIO_UHD_H
namespace srslte {
/* Interface to the RF frontend.
*/
class radio_uhd : public radio
{
public:
radio_uhd() : tr_local_time(1024*10), tr_usrp_time(1024*10), tr_tx_time(1024*10), tr_is_eob(1024*10) {};
bool init();
bool init(char *args);
bool init_agc();
bool init_agc(char *args);
void get_time(srslte_timestamp_t *now);
bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx_end();
bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
void set_tx_gain(float gain);
void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain);
void set_tx_freq(float freq);
void set_rx_freq(float freq);
void set_tx_srate(float srate);
void set_rx_srate(float srate);
float get_tx_gain();
float get_rx_gain();
void start_trace();
void write_trace(std::string filename);
void start_rx();
void stop_rx();
void set_tti(uint32_t tti);
private:
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
void *uhd;
static const double lo_offset = 8e6; // LO offset (in Hz)
static const double burst_settle_time = 0.4e-3; // Start of burst settle time (off->on RF transition time)
const static uint32_t burst_settle_max_samples = 30720000; // 30.72 MHz is maximum frequency
srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst;
uint32_t burst_settle_samples;
double burst_settle_time_rounded; // settle time rounded to sample time
cf_t zeros[burst_settle_max_samples];
double cur_tx_srate;
trace<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time;
trace<uint32_t> tr_tx_time;
trace<uint32_t> tr_is_eob;
bool trace_enabled;
uint32_t tti;
};
}
#endif

@ -1,216 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/radio/radio_uhd.h"
namespace srslte {
bool radio_uhd::init()
{
return init((char*) "");
}
bool radio_uhd::init(char *args)
{
printf("Opening UHD device...\n");
if (cuhd_open(args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
return false;
}
bzero(zeros, burst_settle_max_samples*sizeof(cf_t));
return true;
}
bool radio_uhd::init_agc()
{
return init_agc((char*) "");
}
void radio_uhd::set_tx_rx_gain_offset(float offset) {
cuhd_set_tx_rx_gain_offset(uhd, offset);
}
bool radio_uhd::init_agc(char *args)
{
printf("Opening UHD device with threaded RX Gain control ...\n");
if (cuhd_open_th(args, &uhd, true)) {
fprintf(stderr, "Error opening uhd\n");
return false;
}
cuhd_set_rx_gain(uhd, 40);
cuhd_set_tx_gain(uhd, 40);
burst_settle_samples = 0;
burst_settle_time_rounded = 0;
is_start_of_burst = true;
return true;
}
bool radio_uhd::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time)
{
fprintf(stderr, "Not implemented\n");
return false;
}
bool radio_uhd::rx_now(void* buffer, uint32_t nof_samples, srslte_timestamp_t* rxd_time)
{
if (cuhd_recv_with_time(uhd, buffer, nof_samples, true, &rxd_time->full_secs, &rxd_time->frac_secs) > 0) {
return true;
} else {
return false;
}
}
void radio_uhd::get_time(srslte_timestamp_t *now) {
cuhd_get_time(uhd, &now->full_secs, &now->frac_secs);
}
bool radio_uhd::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
{
if (is_start_of_burst) {
if (burst_settle_samples != 0) {
srslte_timestamp_t tx_time_pad;
srslte_timestamp_copy(&tx_time_pad, &tx_time);
srslte_timestamp_sub(&tx_time_pad, 0, burst_settle_time_rounded);
save_trace(1, &tx_time_pad);
cuhd_send_timed2(uhd, zeros, burst_settle_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false);
}
is_start_of_burst = false;
}
// Save possible end of burst time
srslte_timestamp_copy(&end_of_burst_time, &tx_time);
srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate);
save_trace(0, &tx_time);
if (cuhd_send_timed2(uhd, buffer, nof_samples, tx_time.full_secs, tx_time.frac_secs, false, false) > 0) {
return true;
} else {
return false;
}
}
bool radio_uhd::tx_end()
{
save_trace(2, &end_of_burst_time);
cuhd_send_timed2(uhd, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true);
is_start_of_burst = true;
}
void radio_uhd::start_trace() {
trace_enabled = true;
}
void radio_uhd::set_tti(uint32_t tti_) {
tti = tti_;
}
void radio_uhd::write_trace(std::string filename)
{
tr_local_time.writeToBinary(filename + ".local");
tr_is_eob.writeToBinary(filename + ".eob");
tr_usrp_time.writeToBinary(filename + ".usrp");
tr_tx_time.writeToBinary(filename + ".tx");
}
void radio_uhd::save_trace(uint32_t is_eob, srslte_timestamp_t *tx_time) {
if (trace_enabled) {
tr_local_time.push_cur_time_us(tti);
srslte_timestamp_t usrp_time;
cuhd_get_time(uhd, &usrp_time.full_secs, &usrp_time.frac_secs);
tr_usrp_time.push(tti, srslte_timestamp_uint32(&usrp_time));
tr_tx_time.push(tti, srslte_timestamp_uint32(tx_time));
tr_is_eob.push(tti, is_eob);
}
}
void radio_uhd::set_rx_freq(float freq)
{
cuhd_set_rx_freq(uhd, freq);
}
void radio_uhd::set_rx_gain(float gain)
{
cuhd_set_rx_gain(uhd, gain);
}
double radio_uhd::set_rx_gain_th(float gain)
{
return cuhd_set_rx_gain_th(uhd, gain);
}
void radio_uhd::set_rx_srate(float srate)
{
cuhd_set_rx_srate(uhd, srate);
}
void radio_uhd::set_tx_freq(float freq)
{
cuhd_set_tx_freq_offset(uhd, freq, lo_offset);
}
void radio_uhd::set_tx_gain(float gain)
{
cuhd_set_tx_gain(uhd, gain);
}
float radio_uhd::get_tx_gain()
{
return cuhd_get_tx_gain(uhd);
}
float radio_uhd::get_rx_gain()
{
return cuhd_get_rx_gain(uhd);
}
void radio_uhd::set_tx_srate(float srate)
{
cur_tx_srate = cuhd_set_tx_srate(uhd, srate);
burst_settle_samples = (uint32_t) (cur_tx_srate * burst_settle_time);
if (burst_settle_samples > burst_settle_max_samples) {
burst_settle_samples = burst_settle_max_samples;
fprintf(stderr, "Error setting TX srate %.1f MHz. Maximum frequency for zero prepadding is 30.72 MHz\n", srate*1e-6);
}
burst_settle_time_rounded = (double) burst_settle_samples/cur_tx_srate;
}
void radio_uhd::start_rx()
{
cuhd_start_rx_stream(uhd);
}
void radio_uhd::stop_rx()
{
cuhd_stop_rx_stream(uhd);
}
}

@ -1,27 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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_DIRECTORIES(phy/include/)
INCLUDE_DIRECTORIES(mac/include/)
add_subdirectory(phy)
add_subdirectory(mac)

@ -1,36 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
INSTALL(DIRECTORY include/
DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
FILE(GLOB SOURCES "src/*.cc")
ADD_LIBRARY(srsapps_ue_mac SHARED ${SOURCES})
INSTALL(TARGETS srsapps_ue_mac DESTINATION ${LIBRARY_DIR})
SRSLTE_SET_PIC(srsapps_ue_mac)
FILE(GLOB HEADERS_ALL "include/srsapps/ue/mac/*.h")
ADD_CUSTOM_TARGET (add_ue_mac_headers SOURCES ${HEADERS_ALL})
ADD_SUBDIRECTORY(test)

@ -1,103 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/phy/phy.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/common/log.h"
#include "srsapps/common/qbuff.h"
#include "srsapps/common/timers.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/pdu.h"
#ifndef DEMUX_H
#define DEMUX_H
/* Logical Channel Demultiplexing and MAC CE dissassemble */
namespace srslte {
namespace ue {
class demux
{
public:
demux();
void init(phy_interface* phy_h_, rlc_interface_mac *rlc, log* log_h_, timers* timers_db_);
void process_pdus();
uint8_t* request_buffer(uint32_t len);
void push_pdu(uint8_t *buff, uint32_t nof_bytes);
void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes);
void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes);
void release_buffer(uint8_t *ptr);
void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg);
bool get_uecrid_successful();
private:
const static int NOF_PDU_Q = 3; // prevents threads from being locked
const static int MAX_PDU_LEN = 128*1024;
bool (*uecrid_callback) (void*, uint64_t);
void *uecrid_callback_arg;
sch_pdu mac_msg;
sch_pdu pending_mac_msg;
void process_pdu(uint8_t *pdu, uint32_t nof_bytes);
void process_sch_pdu(sch_pdu *pdu);
bool process_ce(sch_subh *subheader);
bool find_unused_queue(uint8_t *idx);
bool find_nonempty_queue(uint8_t *idx);
void push_buffer(uint8_t *buff, uint32_t nof_bytes);
bool is_uecrid_successful;
typedef struct {
uint8_t idx;
uint8_t dummy[15]; // FIXME: This it to keep 128-bit alignment
} buff_header_t;
// Mutex for exclusive access
qbuff pdu_q[NOF_PDU_Q];
bool used_q[NOF_PDU_Q];
phy_interface *phy_h;
log *log_h;
timers *timers_db;
rlc_interface_mac *rlc;
};
}
}
#endif

@ -1,110 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/log.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/common/timers.h"
#include "srsapps/ue/mac/demux.h"
#include "srsapps/ue/mac/dl_sps.h"
#include "srsapps/ue/mac/mac_pcap.h"
#ifndef DLHARQ_H
#define DLHARQ_H
/* Downlink HARQ entity as defined in 5.3.2 of 36.321 */
namespace srslte {
namespace ue {
class dl_harq_entity
{
public:
const static uint32_t NOF_HARQ_PROC = 8;
const static uint32_t HARQ_BCCH_PID = NOF_HARQ_PROC;
dl_harq_entity();
bool init(log *log_h_, mac_params *params_db, timers *timers_, demux *demux_unit);
/***************** PHY->MAC interface for DL processes **************************/
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void reset();
void start_pcap(mac_pcap* pcap);
private:
class dl_harq_process {
public:
dl_harq_process();
bool init(uint32_t pid, dl_harq_entity *parent);
void reset();
bool is_sps();
bool is_new_transmission(mac_interface_phy::mac_grant_t grant);
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack);
private:
bool is_initiated;
dl_harq_entity *harq_entity;
log *log_h;
uint32_t pid;
uint8_t *payload_buffer_ptr;
bool ack;
mac_interface_phy::mac_grant_t cur_grant;
srslte_softbuffer_rx_t softbuffer;
};
static bool generate_ack_callback(void *arg);
uint32_t get_harq_sps_pid(uint32_t tti);
dl_sps dl_sps_assig;
dl_harq_process proc[NOF_HARQ_PROC+1];
timers *timers_db;
mac_params *params_db;
demux *demux_unit;
log *log_h;
mac_pcap *pcap;
uint16_t last_temporal_crnti;
};
}
}
#endif

@ -1,59 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/log.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/common/timers.h"
#ifndef DLSPS_H
#define DLSPS_H
/* Downlink Semi-Persistent schedulign (Section 5.10.1) */
namespace srslte {
namespace ue {
class dl_sps
{
public:
void clear() {}
void reset() {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) {
return false;
}
private:
};
}
}
#endif

@ -1,145 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/log.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/dl_harq.h"
#include "srsapps/ue/mac/ul_harq.h"
#include "srsapps/common/timers.h"
#include "srsapps/ue/mac/proc_ra.h"
#include "srsapps/ue/mac/proc_sr.h"
#include "srsapps/ue/mac/proc_bsr.h"
#include "srsapps/ue/mac/proc_phr.h"
#include "srsapps/ue/mac/mux.h"
#include "srsapps/ue/mac/demux.h"
#include "srsapps/ue/mac/mac_pcap.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/common/tti_sync_cv.h"
#include "srsapps/common/threads.h"
#ifndef UEMAC_H
#define UEMAC_H
namespace srslte {
namespace ue {
class mac : public mac_interface_phy, mac_interface_rlc, thread, timer_callback, mac_interface_params
{
public:
mac();
bool init(phy_interface *phy, rlc_interface_mac *rlc, log *log_h);
void stop();
/******** Interface from PHY (PHY -> MAC) ****************/
/* see mac_interface.h for comments */
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action);
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len);
void tti_clock(uint32_t tti);
/******** Interface from RLC (RLC -> MAC) ****************/
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void reconfiguration();
void reset();
/******** MAC parameters ****************/
void set_param(mac_interface_params::mac_param_t param, int64_t value);
int64_t get_param(mac_interface_params::mac_param_t param);
void timer_expired(uint32_t timer_id);
void start_pcap(mac_pcap* pcap);
uint32_t get_current_tti();
enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
NOF_MAC_TIMERS
} mac_timers_t;
private:
void run_thread();
void search_si_rnti();
static const int MAC_THREAD_PRIO = 5;
// Interaction with PHY
tti_sync_cv ttisync;
phy_interface *phy_h;
rlc_interface_mac *rlc_h;
log *log_h;
mac_params params_db;
uint32_t tti;
bool started;
bool is_synchronized;
uint16_t last_temporal_crnti;
uint16_t phy_rnti;
/* Multiplexing/Demultiplexing Units */
mux mux_unit;
demux demux_unit;
/* DL/UL HARQ */
dl_harq_entity dl_harq;
ul_harq_entity ul_harq;
/* MAC Uplink-related Procedures */
ra_proc ra_procedure;
sr_proc sr_procedure;
bsr_proc bsr_procedure;
phr_proc phr_procedure;
/* Functions for MAC Timers */
timers timers_db;
void setup_timers();
void timeAlignmentTimerExpire();
// pointer to MAC PCAP object
mac_pcap* pcap;
bool si_search_in_progress;
int si_window_length;
int si_window_start;
bool signals_pregenerated;
};
}
}
#endif

@ -1,53 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/common/params_db.h"
#include "srsapps/common/mac_interface.h"
#ifndef MACPARAMS_H
#define MACPARAMS_H
namespace srslte {
namespace ue {
class mac_params : public params_db
{
public:
mac_params() : params_db(mac_interface_params::NOF_PARAMS) {}
~mac_params() {}
};
}
}
#endif

@ -1,64 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/ue/mac/pcap.h"
#ifndef MACPCAP_H
#define MACPCAP_H
namespace srslte {
namespace ue {
class mac_pcap
{
public:
mac_pcap() {enable_write=false; ue_id=0;};
void enable(bool en);
bool open(const char *filename, uint32_t ue_id = 0);
void close();
void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti);
void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti);
void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti);
// SI and BCH only for DL
void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
private:
bool enable_write;
FILE *pcap_file;
uint32_t ue_id;
void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti,
uint16_t crnti_, uint8_t direction, uint8_t rnti_type);
};
}
}
#endif

@ -1,106 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <pthread.h>
#include "srsapps/common/qbuff.h"
#include "srsapps/common/log.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/pdu.h"
#include "srsapps/ue/mac/proc_bsr.h"
#ifndef MUX_H
#define MUX_H
/* Logical Channel Multiplexing and Prioritization + Msg3 Buffer */
namespace srslte {
namespace ue {
class mux
{
public:
mux();
void reset();
void init(rlc_interface_mac *rlc, log *log_h, bsr_proc *bsr_procedure);
bool is_pending_ccch_sdu();
bool is_pending_any_sdu();
bool is_pending_sdu(uint32_t lcid);
uint8_t* pdu_get(uint8_t *payload, uint32_t pdu_sz);
uint8_t* msg3_get(uint8_t* payload, uint32_t pdu_sz);
void msg3_flush();
bool msg3_is_transmitted();
void append_crnti_ce_next_tx(uint16_t crnti);
void set_priority(uint32_t lcid, uint32_t priority, int PBR_x_tti, uint32_t BSD);
private:
bool pdu_move_to_msg3(uint32_t pdu_sz);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu, bool *is_first);
bool allocate_sdu(uint32_t lcid, sch_pdu *pdu, int max_sdu_sz, uint32_t *sdu_sz, bool *is_first);
const static int NOF_UL_LCH = 10;
const static int MIN_RLC_SDU_LEN = 0;
const static int MAX_NOF_SUBHEADERS = 20;
int64_t Bj[NOF_UL_LCH];
int PBR[NOF_UL_LCH]; // -1 sets to infinity
uint32_t BSD[NOF_UL_LCH];
uint32_t priority[NOF_UL_LCH];
uint32_t priority_sorted[NOF_UL_LCH];
uint32_t lchid_sorted[NOF_UL_LCH];
// Mutex for exclusive access
pthread_mutex_t mutex;
log *log_h;
rlc_interface_mac *rlc;
bsr_proc *bsr_procedure;
uint16_t pending_crnti_ce;
/* Msg3 Buffer */
static const uint32_t MSG3_BUFF_SZ = 128;
qbuff msg3_buff;
/* PDU Buffer */
sch_pdu pdu_msg;
bool msg3_has_been_transmitted;
bool phr_included;
};
}
}
#endif

@ -1,218 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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/.
*
*/
#ifndef UEPCAP_H
#define UEPCAP_H
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define MAC_LTE_DLT 147
/* This structure gets written to the start of the file */
typedef struct pcap_hdr_s {
unsigned int magic_number; /* magic number */
unsigned short version_major; /* major version number */
unsigned short version_minor; /* minor version number */
unsigned int thiszone; /* GMT to local correction */
unsigned int sigfigs; /* accuracy of timestamps */
unsigned int snaplen; /* max length of captured packets, in octets */
unsigned int network; /* data link type */
} pcap_hdr_t;
/* This structure precedes each packet */
typedef struct pcaprec_hdr_s {
unsigned int ts_sec; /* timestamp seconds */
unsigned int ts_usec; /* timestamp microseconds */
unsigned int incl_len; /* number of octets of packet saved in file */
unsigned int orig_len; /* actual length of packet */
} pcaprec_hdr_t;
/* radioType */
#define FDD_RADIO 1
#define TDD_RADIO 2
/* Direction */
#define DIRECTION_UPLINK 0
#define DIRECTION_DOWNLINK 1
/* rntiType */
#define NO_RNTI 0 /* Used for BCH-BCH */
#define P_RNTI 1
#define RA_RNTI 2
#define C_RNTI 3
#define SI_RNTI 4
#define SPS_RNTI 5
#define M_RNTI 6
#define MAC_LTE_START_STRING "mac-lte"
#define MAC_LTE_RNTI_TAG 0x02
/* 2 bytes, network order */
#define MAC_LTE_UEID_TAG 0x03
/* 2 bytes, network order */
#define MAC_LTE_SUBFRAME_TAG 0x04
/* 2 bytes, network order */
#define MAC_LTE_PREDFINED_DATA_TAG 0x05
/* 1 byte */
#define MAC_LTE_RETX_TAG 0x06
/* 1 byte */
#define MAC_LTE_CRC_STATUS_TAG 0x07
/* 1 byte */
/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU
continues until the end of the frame) */
#define MAC_LTE_PAYLOAD_TAG 0x01
/* Context information for every MAC PDU that will be logged */
typedef struct MAC_Context_Info_t {
unsigned short radioType;
unsigned char direction;
unsigned char rntiType;
unsigned short rnti;
unsigned short ueid;
unsigned char isRetx;
unsigned char crcStatusOK;
unsigned short sysFrameNumber;
unsigned short subFrameNumber;
} MAC_Context_Info_t;
/**************************************************************************/
/* API functions for opening/writing/closing MAC-LTE PCAP files */
/* Open the file and write file header */
inline FILE *MAC_LTE_PCAP_Open(const char *fileName)
{
pcap_hdr_t file_header =
{
0xa1b2c3d4, /* magic number */
2, 4, /* version number is 2.4 */
0, /* timezone */
0, /* sigfigs - apparently all tools do this */
65535, /* snaplen - this should be long enough */
MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */
};
FILE *fd = fopen(fileName, "w");
if (fd == NULL) {
printf("Failed to open file \"%s\" for writing\n", fileName);
return NULL;
}
/* Write the file header */
fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd);
return fd;
}
/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */
inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
char context_header[256];
int offset = 0;
unsigned short tmp16;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* Subframe number */
context_header[offset++] = MAC_LTE_SUBFRAME_TAG;
tmp16 = htons(context->subFrameNumber);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
/* CRC Status */
context_header[offset++] = MAC_LTE_CRC_STATUS_TAG;
context_header[offset++] = context->crcStatusOK;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = offset + length;
packet_header.orig_len = offset + length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(context_header, 1, offset, fd);
fwrite(PDU, 1, length, fd);
return 1;
}
/* Close the PCAP file */
inline void MAC_LTE_PCAP_Close(FILE *fd)
{
fclose(fd);
}
#endif /* UEPCAP_H */

@ -1,331 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/common/log.h"
#include "srsapps/common/mac_interface.h"
#include <vector>
#include <stdio.h>
#ifndef MACPDU_H
#define MACPDU_H
/* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */
namespace srslte {
namespace ue {
template<class SubH>
class pdu
{
public:
pdu(uint32_t max_subheaders_) : subheaders(max_subheaders_) {
max_subheaders = max_subheaders_;
nof_subheaders = 0;
cur_idx = -1;
pdu_len = 0;
rem_len = 0;
for (int i=0;i<max_subheaders;i++) {
subheaders[i].parent = this;
}
}
void fprint(FILE *stream) {
fprintf(stream, "Number of Subheaders: %d\n", nof_subheaders);
for (int i=0;i<nof_subheaders;i++) {
fprintf(stream, " -- Subheader %d: ", i);
subheaders[i].fprint(stream);
}
}
/* Resets the Read/Write position and remaining PDU length */
void reset() {
cur_idx = -1;
rem_len = pdu_len;
}
void init_rx(uint32_t pdu_len_bytes, bool is_ulsch = false) {
init_(NULL, pdu_len_bytes, is_ulsch);
}
void init_tx(uint8_t *payload, uint32_t pdu_len_bytes, bool is_ulsch = false) {
init_(payload, pdu_len_bytes, is_ulsch);
}
uint32_t nof_subh() {
return nof_subheaders;
}
bool new_subh() {
if (nof_subheaders < max_subheaders - 1) {
nof_subheaders++;
return true;
} else {
return false;
}
}
bool next() {
if (cur_idx < nof_subheaders - 1) {
cur_idx++;
return true;
} else {
return false;
}
}
void del_subh() {
if (nof_subheaders > 0) {
nof_subheaders--;
}
if (cur_idx > 0) {
cur_idx--;
}
}
SubH* get() {
if (cur_idx >= 0) {
return &subheaders[cur_idx];
}
}
bool is_ul() {
return pdu_is_ul;
}
uint8_t* get_current_sdu_ptr() {
return &buffer_tx[total_sdu_len+sdu_offset_start];
}
void add_sdu(uint32_t sdu_sz) {
total_sdu_len += sdu_sz;
}
// Section 6.1.2
void parse_packet(uint8_t *ptr) {
uint8_t *init_ptr = ptr;
nof_subheaders = 0;
while(subheaders[nof_subheaders].read_subheader(&ptr)) {
nof_subheaders++;
}
nof_subheaders++;
for (int i=0;i<nof_subheaders;i++) {
subheaders[i].read_payload(&ptr);
}
}
protected:
std::vector<SubH> subheaders;
uint32_t pdu_len;
uint32_t rem_len;
int cur_idx;
int nof_subheaders;
uint32_t max_subheaders;
bool pdu_is_ul;
uint8_t* buffer_tx;
uint32_t total_sdu_len;
uint32_t sdu_offset_start;
private:
/* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */
void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
nof_subheaders = 0;
pdu_len = pdu_len_bytes;
rem_len = pdu_len;
pdu_is_ul = is_ulsch;
buffer_tx = buffer_tx_ptr;
sdu_offset_start = max_subheaders*2 + 13; // Assuming worst-case 2 bytes per sdu subheader + all possible CE
total_sdu_len = 0;
reset();
for (int i=0;i<max_subheaders;i++) {
subheaders[i].init();
}
}
};
template<class SubH>
class subh
{
public:
virtual bool read_subheader(uint8_t** ptr) = 0;
virtual void read_payload(uint8_t **ptr) = 0;
virtual void write_subheader(uint8_t** ptr, bool is_last) = 0;
virtual void write_payload(uint8_t **ptr) = 0;
virtual void fprint(FILE *stream) = 0;
pdu<SubH>* parent;
private:
virtual void init() = 0;
};
class sch_subh : public subh<sch_subh>
{
public:
typedef enum {
PHR_REPORT = 26,
C_RNTI = 27,
CON_RES_ID = 28,
TRUNC_BSR = 28,
TA_CMD = 29,
SHORT_BSR = 29,
DRX_CMD = 30,
LONG_BSR = 30,
PADDING = 31,
SDU = 0
} cetype;
// Reading functions
bool is_sdu();
cetype ce_type();
uint32_t size_plus_header();
void set_payload_size(uint32_t size);
bool read_subheader(uint8_t** ptr);
void read_payload(uint8_t **ptr);
uint32_t get_sdu_lcid();
uint32_t get_sdu_nbytes();
uint8_t* get_sdu_ptr();
uint16_t get_c_rnti();
uint64_t get_con_res_id();
uint8_t get_ta_cmd();
uint8_t get_phr();
// Writing functions
void write_subheader(uint8_t** ptr, bool is_last);
void write_payload(uint8_t **ptr);
int set_sdu(uint32_t lcid, uint32_t requested_bytes, rlc_interface_mac *rlc);
int set_sdu(uint32_t lcid, uint32_t requested_bytes, rlc_interface_mac *rlc, bool is_first);
bool set_c_rnti(uint16_t crnti);
bool set_bsr(uint32_t buff_size[4], sch_subh::cetype format, bool update_size);
bool set_con_res_id(uint64_t con_res_id);
bool set_ta_cmd(uint8_t ta_cmd);
bool set_phr(uint8_t phr);
void set_padding();
void set_padding(uint32_t padding_len);
void init();
void fprint(FILE *stream);
private:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid;
uint32_t nof_bytes;
uint8_t* payload;
uint8_t w_payload_ce[8];
bool F_bit;
uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
uint8_t buff_size_table(uint32_t buffer_size);
};
class sch_pdu : public pdu<sch_subh>
{
public:
sch_pdu(uint32_t max_rars) : pdu(max_rars) {}
void parse_packet(uint8_t *ptr);
uint8_t* write_packet();
bool has_space_ce(uint32_t nbytes);
bool has_space_sdu(uint32_t nbytes);
bool has_space_sdu(uint32_t nbytes, bool is_first);
uint32_t size();
uint32_t rem_size();
static uint32_t size_plus_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes);
bool update_space_sdu(uint32_t nbytes);
bool update_space_sdu(uint32_t nbytes, bool is_first);
void fprint(FILE *stream);
};
class rar_subh : public subh<rar_subh>
{
public:
static const uint32_t RAR_GRANT_LEN = 20;
// Reading functions
bool read_subheader(uint8_t** ptr);
void read_payload(uint8_t** ptr);
uint32_t get_rapid();
uint32_t get_ta_cmd();
uint16_t get_temp_crnti();
void get_sched_grant(uint8_t grant[RAR_GRANT_LEN]);
// Writing functoins
void write_subheader(uint8_t** ptr, bool is_last);
void write_payload(uint8_t** ptr);
void set_rapid(uint32_t rapid);
void set_ta_cmd(uint32_t ta);
void set_temp_crnti(uint16_t temp_rnti);
void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]);
void init();
void fprint(FILE *stream);
private:
uint8_t grant[RAR_GRANT_LEN];
uint32_t ta;
uint16_t temp_rnti;
uint32_t preamble;
};
class rar_pdu : public pdu<rar_subh>
{
public:
rar_pdu(uint32_t max_rars);
void set_backoff(uint8_t bi);
bool has_backoff();
uint8_t get_backoff();
bool write_packet(uint8_t* ptr);
void fprint(FILE *stream);
private:
bool has_backoff_indicator;
uint8_t backoff_indicator;
};
}
}
#endif

@ -1,62 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#ifndef PROC_H
#define PROC_H
/* Interface for a MAC procedure */
namespace srslte {
namespace ue {
class proc
{
public:
proc() {
running = false;
}
void run() {
running = true;
}
void stop() {
running = false;
}
bool is_running() {
return running;
}
virtual void step(uint32_t tti) = 0;
private:
bool running;
};
}
}
#endif

@ -1,105 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/common/log.h"
#include "srsapps/ue/mac/proc.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/common/timers.h"
#ifndef PROCBSR_H
#define PROCBSR_H
/* Buffer status report procedure */
namespace srslte {
namespace ue {
class bsr_proc : public proc, timer_callback
{
public:
bsr_proc();
void init(rlc_interface_mac *rlc, log *log_h, mac_params *params_db, timers *timers_db);
void step(uint32_t tti);
void reset();
void setup_lcg(uint32_t lcid, uint32_t new_lcg);
void set_priority(uint32_t lcid, uint32_t priority);
void timer_expired(uint32_t timer_id);
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
uint32_t need_to_send_bsr_on_ul_grant(uint32_t grant_size);
bool generate_bsr_on_ul_grant(uint32_t nof_padding_bytes, bsr_t *bsr);
bool need_to_send_sr();
bool need_to_reset_sr();
private:
const static int QUEUE_STATUS_PERIOD_MS = 500;
bool reset_sr;
mac_params *params_db;
timers *timers_db;
log *log_h;
rlc_interface_mac *rlc;
bool initiated;
const static int MAX_LCID = 6;
int lcg[MAX_LCID];
uint32_t last_pending_data[MAX_LCID];
int priorities[MAX_LCID];
uint32_t find_max_priority_lcid();
typedef enum {NONE, REGULAR, PADDING, PERIODIC} triggered_bsr_type_t;
triggered_bsr_type_t triggered_bsr_type;
bool timer_periodic;
bool timer_retx;
bool sr_is_sent;
uint32_t last_print;
void update_pending_data();
bool check_highest_channel();
bool check_single_channel();
bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes);
char* bsr_type_tostring(triggered_bsr_type_t type);
char* bsr_format_tostring(bsr_format_t format);
};
}
}
#endif

@ -1,57 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/ue/mac/proc.h"
#ifndef PROCPHR_H
#define PROCPHR_H
/* Power headroom report procedure */
namespace srslte {
namespace ue {
class phr_proc : public proc
{
public:
void step(uint32_t tti) {
if (is_running()) {
fprintf(stderr, "PHR procedure not implemented\n");
}
}
void reset() {
}
};
}
}
#endif

@ -1,174 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/ue/phy/phy.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/common/qbuff.h"
#include "srsapps/ue/mac/proc.h"
#include "srsapps/common/timers.h"
#include "srsapps/ue/mac/mux.h"
#include "srsapps/ue/mac/demux.h"
#include "srsapps/ue/mac/pdu.h"
#include "srsapps/ue/mac/mac_pcap.h"
#ifndef PROCRA_H
#define PROCRA_H
/* Random access procedure as specified in Section 5.1 of 36.321 */
namespace srslte {
namespace ue {
class ra_proc : public proc,timer_callback
{
public:
ra_proc() : rar_pdu_msg(20) {pcap = NULL;};
bool init(phy_interface *phy_h, log *log_h, mac_params *params_db, timers *timers_db, mux *mux_unit, demux *demux_unit);
void reset();
void start_pdcch_order();
void start_rlc_order();
void start_mac_order();
void step(uint32_t tti);
bool is_successful();
bool is_response_error();
bool is_contention_resolution();
bool is_error();
bool in_progress();
void pdcch_to_crnti(bool is_ul_grant);
void timer_expired(uint32_t timer_id);
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action);
void tb_decoded_ok();
void start_pcap(mac_pcap* pcap);
private:
static bool uecrid_callback(void *arg, uint64_t uecri);
bool contention_resolution_id_received(uint64_t uecri);
void process_timeadv_cmd(uint32_t ta_cmd);
void step_initialization();
void step_resource_selection();
void step_preamble_transmission();
void step_pdcch_setup();
void step_response_reception();
void step_response_error();
void step_backoff_wait();
void step_contention_resolution();
void step_completition();
// Buffer to receive RAR PDU
static const uint32_t MAX_RAR_PDU_LEN = 2048;
uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN];
rar_pdu rar_pdu_msg;
// Random Access parameters provided by higher layers defined in 5.1.1
// They are read from params_db during initialization init()
uint32_t configIndex;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
uint32_t nof_groupB_preambles;
uint32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t Pcmax;
uint32_t deltaPreambleMsg3;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
uint32_t iniReceivedTargetPower;
int delta_preamble_db;
uint32_t contentionResolutionTimer;
uint32_t maskIndex;
int preambleIndex;
// Internal variables
uint32_t preambleTransmissionCounter;
uint32_t backoff_param_ms;
uint32_t sel_maskIndex;
uint32_t sel_preamble;
uint32_t backoff_interval_start;
uint32_t backoff_inteval;
int received_target_power_dbm;
uint32_t ra_rnti;
srslte_softbuffer_rx_t softbuffer_rar;
enum {
IDLE = 0,
INITIALIZATION, // Section 5.1.1
RESOURCE_SELECTION, // Section 5.1.2
PREAMBLE_TRANSMISSION, // Section 5.1.3
PDCCH_SETUP,
RESPONSE_RECEPTION, // Section 5.1.4
RESPONSE_ERROR,
BACKOFF_WAIT,
CONTENTION_RESOLUTION, // Section 5.1.5
COMPLETION, // Section 5.1.6
RA_PROBLEM // Section 5.1.5 last part
} state;
typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t;
ra_group_t last_msg3_group;
bool msg3_transmitted;
bool first_rar_received;
void read_params();
phy_interface *phy_h;
log *log_h;
mac_params *params_db;
timers *timers_db;
mux *mux_unit;
demux *demux_unit;
mac_pcap *pcap;
uint64_t transmitted_contention_id;
uint16_t transmitted_crnti;
enum {
PDCCH_CRNTI_NOT_RECEIVED = 0,
PDCCH_CRNTI_UL_GRANT,
PDCCH_CRNTI_DL_GRANT
} pdcch_to_crnti_received;
enum {
PDCCH_ORDER = 0,
RLC_ORDER,
MAC_ORDER
} start_mode;
uint32_t rar_grant_nbytes;
uint32_t rar_grant_tti;
bool msg3_flushed;
};
}
}
#endif

@ -1,68 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srsapps/ue/mac/proc.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac_params.h"
#ifndef PROCSR_H
#define PROCSR_H
/* Scheduling Request procedure as defined in 5.4.4 of 36.321 */
namespace srslte {
namespace ue {
class sr_proc : public proc
{
public:
sr_proc();
void init(phy_interface *phy_h, log *log_h, mac_params *params_db);
void step(uint32_t tti);
void reset();
void start();
bool need_random_access();
private:
uint32_t sr_counter;
uint32_t dsr_transmax;
bool is_pending_sr;
mac_params *params_db;
phy_interface *phy_h;
log *log_h;
bool initiated;
bool do_ra;
};
}
}
#endif

@ -1,129 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/mac_interface.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/ue/mac/mux.h"
#include "srsapps/ue/mac/ul_sps.h"
#include "srsapps/ue/mac/mac_pcap.h"
#include "srsapps/common/timers.h"
#ifndef ULHARQ_H
#define ULHARQ_H
/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */
namespace srslte {
namespace ue {
class ul_harq_entity
{
public:
const static uint32_t NOF_HARQ_PROC = 8;
static uint32_t pidof(uint32_t tti);
ul_harq_entity() { pcap = NULL; }
bool init(log *log_h, mac_params *params_db, timers* timers_, mux *mux_unit);
void reset();
void reset_ndi();
void start_pcap(mac_pcap* pcap);
/***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action);
void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action);
private:
class ul_harq_process {
public:
ul_harq_process();
bool init(uint32_t pid, ul_harq_entity *parent);
void reset();
void reset_ndi();
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
uint32_t get_rv();
bool has_grant();
void set_harq_feedback(bool ack);
bool get_ndi();
bool is_sps();
uint32_t last_tx_tti();
uint32_t get_nof_retx();
private:
mac_interface_phy::mac_grant_t cur_grant;
uint32_t pid;
uint32_t current_tx_nb;
uint32_t current_irv;
bool harq_feedback;
bool ndi;
log *log_h;
ul_harq_entity *harq_entity;
bool is_grant_configured;
srslte_softbuffer_tx_t softbuffer;
bool is_msg3;
bool is_initiated;
uint32_t tti_last_tx;
const static int payload_buffer_len = 128*1024;
uint8_t *payload_buffer;
uint8_t *pdu_ptr;
void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
void generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_new_tx(uint32_t tti_tx, bool is_msg3, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
};
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
void set_ack(uint32_t tti, bool ack);
ul_sps ul_sps_assig;
timers *timers_db;
mux *mux_unit;
ul_harq_process proc[NOF_HARQ_PROC];
log *log_h;
mac_params *params_db;
mac_pcap *pcap;
};
}
}
#endif

@ -1,59 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/log.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac_params.h"
#include "srsapps/common/timers.h"
#ifndef ULSPS_H
#define ULSPS_H
/* Uplink Semi-Persistent schedulign (Section 5.10.2) */
namespace srslte {
namespace ue {
typedef _Complex float cf_t;
class ul_sps
{
public:
void clear() {}
void reset(uint32_t tti) {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { return false; }
private:
};
}
}
#endif

@ -1,249 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/demux.h"
namespace srslte {
namespace ue {
demux::demux() : mac_msg(20), pending_mac_msg(20)
{
for (int i=0;i<NOF_PDU_Q;i++) {
pdu_q[i].init(8, MAX_PDU_LEN);
used_q[i] = false;
}
}
void demux::init(phy_interface* phy_h_, rlc_interface_mac *rlc_, log* log_h_, timers* timers_db_)
{
phy_h = phy_h_;
log_h = log_h_;
rlc = rlc_;
timers_db = timers_db_;
}
void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) {
uecrid_callback = callback;
uecrid_callback_arg = arg;
}
bool demux::get_uecrid_successful() {
return is_uecrid_successful;
}
bool demux::find_unused_queue(uint8_t *idx) {
for (uint8_t i=0;i<NOF_PDU_Q;i++) {
if (!used_q[i]) {
if (idx) {
*idx = i;
}
return true;
}
}
return false;
}
// Read packets from queues in round robin
bool demux::find_nonempty_queue(uint8_t *idx) {
uint32_t start=0;
if (idx) {
start = *idx;
}
for (uint8_t i=0;i<NOF_PDU_Q;i++) {
if (!pdu_q[(i+start+1)%NOF_PDU_Q].isempty()) {
if (idx) {
*idx = (i+start+1)%NOF_PDU_Q;
}
return true;
}
}
return false;
}
uint8_t* demux::request_buffer(uint32_t len)
{
if (len >= MAX_PDU_LEN - sizeof(buff_header_t)) {
return NULL;
}
uint8_t idx=0;
if(find_unused_queue(&idx)) {
if (idx > 0) {
//printf("Using queue %d for MAC PDU\n", idx);
}
used_q[idx] = true;
uint8_t *buff = (uint8_t*) pdu_q[idx].request();
buff_header_t *head = (buff_header_t*) buff;
head->idx = idx;
return &buff[sizeof(buff_header_t)];
} else {
Error("All DL buffers are full. Packet will be lost\n");
return NULL;
}
}
void demux::push_buffer(uint8_t *buff, uint32_t nof_bytes) {
buff_header_t *head = (buff_header_t*) (buff-sizeof(buff_header_t));
if (head->idx < NOF_PDU_Q) {
if (nof_bytes > 0) {
if (!pdu_q[head->idx].push(nof_bytes)) {
Warning("Full queue %d when pushing MAC PDU %d bytes\n", head->idx, nof_bytes);
}
}
used_q[head->idx] = false;
}
}
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
* the MAC in transparent mode.
* Warning: this function sends the message to RLC now, since SI blocks do not
* require ACK feedback to be transmitted quickly.
*/
void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes)
{
Debug("Pushed BCCH MAC PDU in transparent mode\n");
rlc->write_pdu_bcch_dlsch(buff, nof_bytes);
push_buffer(buff, 0);
}
/* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will
* remain in buffer until demultiplex_pending_pdu() is called.
* This features is provided to enable the Random Access Procedure to decide
* wether the PDU shall pass to upper layers or not, which depends on the
* Contention Resolution result.
*
* Warning: this function does some processing here assuming ACK deadline is not an
* issue here because Temp C-RNTI messages have small payloads
*/
void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
{
// Unpack DLSCH MAC PDU
pending_mac_msg.init_rx(nof_bytes);
pending_mac_msg.parse_packet(buff);
// Look for Contention Resolution UE ID
is_uecrid_successful = false;
while(pending_mac_msg.next() && !is_uecrid_successful) {
if (pending_mac_msg.get()->ce_type() == sch_subh::CON_RES_ID) {
Debug("Found Contention Resolution ID CE\n");
is_uecrid_successful = uecrid_callback(uecrid_callback_arg, pending_mac_msg.get()->get_con_res_id());
}
}
pending_mac_msg.reset();
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
push_buffer(buff, nof_bytes);
}
/* Demultiplexing of logical channels and dissassemble of MAC CE
* This function enqueues the packet and returns quicly because ACK
* deadline is important here.
*/
void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes)
{
push_buffer(buff, nof_bytes);
}
void demux::release_buffer(uint8_t* ptr)
{
uint8_t *addr = ptr - sizeof(buff_header_t);
for (int i=0;i<NOF_PDU_Q;i++) {
if (pdu_q[i].request() == addr) {
used_q[i] = false;
break;
}
}
}
void demux::process_pdus()
{
uint32_t len;
uint8_t idx=0;
while(find_nonempty_queue(&idx)) {
uint8_t *mac_pdu = (uint8_t*) pdu_q[idx].pop(&len);
if (mac_pdu) {
process_pdu(&mac_pdu[sizeof(buff_header_t)], len);
}
pdu_q[idx].release();
idx++;
}
}
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes)
{
// Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
Debug("MAC PDU processed\n");
}
void demux::process_sch_pdu(sch_pdu *pdu_msg)
{
while(pdu_msg->next()) {
if (pdu_msg->get()->is_sdu()) {
// Route logical channel
Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_nbytes());
rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_sdu_nbytes());
} else {
// Process MAC Control Element
if (!process_ce(pdu_msg->get())) {
Warning("Received Subheader with invalid or unkonwn LCID\n");
}
}
}
}
bool demux::process_ce(sch_subh *subh) {
switch(subh->ce_type()) {
case sch_subh::CON_RES_ID:
// Do nothing
break;
case sch_subh::TA_CMD:
phy_h->set_timeadv(subh->get_ta_cmd());
// Start or restart timeAlignmentTimer
timers_db->get(mac::TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run();
Debug("Set TimeAdvance Command %d\n", subh->get_ta_cmd());
break;
case sch_subh::PADDING:
break;
default:
Error("MAC CE 0x%x not supported\n", subh->ce_type());
break;
}
return true;
}
}
}

@ -1,308 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/phy/phy.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/dl_harq.h"
namespace srslte {
namespace ue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
dl_harq_entity::dl_harq_entity()
{
pcap = NULL;
}
bool dl_harq_entity::init(log* log_h_, mac_params *params_db_, timers* timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
params_db = params_db_;
log_h = log_h_;
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void dl_harq_entity::start_pcap(mac_pcap* pcap_)
{
pcap = pcap_;
}
void dl_harq_entity::reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
uint32_t dl_harq_entity::get_harq_sps_pid(uint32_t tti) {
/*
uint32_t nof_proc = ((uint32_t) params_db->get_param(mac_interface_params::SPS_DL_NOF_PROC));
return tti/params_db.get_param(mac_interface_params::SPS_DL_SCHED_INTERVAL)%nof_proc;
*/
}
void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
// Set BCCH PID for SI RNTI
if (grant.rnti_type == SRSLTE_RNTI_SI) {
harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%NOF_HARQ_PROC;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%NOF_HARQ_PROC;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void dl_harq_entity::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[NOF_HARQ_PROC].tb_decoded(ack);
} else {
proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack);
}
}
bool dl_harq_entity::generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
dl_harq_entity::dl_harq_process::dl_harq_process() {
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void dl_harq_entity::dl_harq_process::reset() {
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
bool dl_harq_entity::dl_harq_process::init(uint32_t pid_, dl_harq_entity *parent) {
if (srslte_softbuffer_rx_init(&softbuffer, 100)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
bool dl_harq_entity::dl_harq_process::is_sps()
{
return false;
}
bool dl_harq_entity::dl_harq_process::is_new_transmission(mac_interface_phy::mac_grant_t grant) {
bool is_new_transmission;
bool is_new_tb = true;
if (srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && grant.n_bytes == cur_grant.n_bytes) {
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
Info("DL PID %d: %s RV=%d, NDI=%d, LastNDI=%d\n", pid, is_new_transmission?"new TX":"reTX", grant.rv,
grant.ndi, cur_grant.ndi);
return is_new_transmission;
}
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (pid == HARQ_BCCH_PID) {
// Compute RV
uint32_t k;
if (grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
} else {
uint32_t nw = harq_entity->params_db->get_param(mac_interface_params::BCCH_SI_WINDOW_LEN);
k = (grant.tti%nw)%4;
}
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
if (is_new_transmission(grant)) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
}
// Save grant
memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t));
// Fill action structure
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
void dl_harq_entity::dl_harq_process::tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
if (ack) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.n_bytes);
}
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.n_bytes);
}
}
}
} else {
harq_entity->demux_unit->release_buffer(payload_buffer_ptr);
}
Info("DL PID %d: TBS=%d, RV=%d, ACK=%s\n", pid, cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO");
}
}
}

@ -1,345 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <string.h>
#include <strings.h>
#include <pthread.h>
#include <unistd.h>
#include "srsapps/common/log.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/pcap.h"
namespace srslte {
namespace ue {
mac::mac() : ttisync(10240), timers_db((uint32_t) NOF_MAC_TIMERS)
{
started = false;
pcap = NULL;
si_search_in_progress = false;
si_window_length = -1;
si_window_start = -1;
signals_pregenerated = false;
}
bool mac::init(phy_interface *phy, rlc_interface_mac *rlc, log *log_h_)
{
started = false;
phy_h = phy;
rlc_h = rlc;
log_h = log_h_;
tti = 0;
is_synchronized = false;
last_temporal_crnti = 0;
phy_rnti = 0;
bsr_procedure.init( rlc_h, log_h, &params_db, &timers_db);
mux_unit.init ( rlc_h, log_h, &bsr_procedure);
demux_unit.init (phy_h, rlc_h, log_h, &timers_db);
ra_procedure.init (phy_h, log_h, &params_db, &timers_db, &mux_unit, &demux_unit);
sr_procedure.init (phy_h, log_h, &params_db);
ul_harq.init ( log_h, &params_db, &timers_db, &mux_unit);
dl_harq.init ( log_h, &params_db, &timers_db, &demux_unit);
reset();
started = true;
start(MAC_THREAD_PRIO);
return started;
}
void mac::stop()
{
started = false;
ttisync.increase();
wait_thread_finish();
}
void mac::start_pcap(mac_pcap* pcap_)
{
pcap = pcap_;
dl_harq.start_pcap(pcap);
ul_harq.start_pcap(pcap);
ra_procedure.start_pcap(pcap);
}
// Implement Section 5.8
void mac::reconfiguration()
{
}
// Implement Section 5.9
void mac::reset()
{
timers_db.stop_all();
timeAlignmentTimerExpire();
ul_harq.reset_ndi();
mux_unit.msg3_flush();
mux_unit.reset();
ra_procedure.stop();
ra_procedure.reset();
sr_procedure.stop();
sr_procedure.reset();
bsr_procedure.stop();
bsr_procedure.reset();
phr_procedure.stop();
phr_procedure.reset();
dl_harq.reset();
phy_h->pdcch_dl_search_reset();
phy_h->pdcch_ul_search_reset();
signals_pregenerated = false;
params_db.set_param(mac_interface_params::BCCH_SI_WINDOW_ST, -1);
params_db.set_param(mac_interface_params::BCCH_SI_WINDOW_LEN, -1);
}
void mac::run_thread() {
setup_timers();
Info("Waiting PHY to synchronize with cell\n");
phy_h->sync_start();
while(!phy_h->get_current_tti()) {
usleep(50000);
}
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());
ttisync.set_producer_cntr(phy_h->get_current_tti());
while(started) {
/* Warning: Here order of invocation of procedures is important!! */
tti = (ttisync.wait() + 1)%10240;
if (started) {
log_h->step(tti);
search_si_rnti();
// Step all procedures
bsr_procedure.step(tti);
// Check if BSR procedure need to start SR
if (bsr_procedure.need_to_send_sr()) {
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", phy_h->get_current_tti());
sr_procedure.start();
}
if (bsr_procedure.need_to_reset_sr()) {
Debug("Resetting SR procedure by BSR request\n");
sr_procedure.reset();
}
sr_procedure.step(tti);
// Check SR if we need to start RA
if (sr_procedure.need_random_access()) {
Warning("Starting RA procedure by MAC order is DISABLED\n");
//ra_procedure.start_mac_order();
}
// Check if there is pending CCCH SDU in Mux unit
if (mux_unit.is_pending_ccch_sdu()) {
if (!ra_procedure.in_progress() && !ra_procedure.is_successful()) {
ra_procedure.start_rlc_order();
}
}
ra_procedure.step(tti);
//phr_procedure.step(tti);
// FIXME: Do here DTX and look for UL grants only when needed
if (ra_procedure.is_successful() && !signals_pregenerated) {
// Configure PHY to look for UL C-RNTI grants
uint16_t crnti = params_db.get_param(mac_interface_params::RNTI_C);
phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, crnti);
phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, crnti);
// Pregenerate UL signals and C-RNTI scrambling sequences
Info("Pre-generating UL signals and C-RNTI scrambling sequences\n");
((phy*) phy_h)->enable_pregen_signals(true);
((phy*) phy_h)->set_crnti(crnti);
Info("Done\n");
signals_pregenerated = true;
}
timers_db.step_all();
demux_unit.process_pdus();
}
}
}
void mac::search_si_rnti()
{
// Setup PDCCH search
int _si_window_start = params_db.get_param(mac_interface_params::BCCH_SI_WINDOW_ST);
int _si_window_length = params_db.get_param(mac_interface_params::BCCH_SI_WINDOW_LEN);
if ((tti >= si_window_start + si_window_length) && si_search_in_progress) {
si_search_in_progress = false;
phy_h->pdcch_dl_search_reset();
Debug("SI search window expired (%d >= %d+%d)\n", tti, si_window_start, si_window_length);
params_db.set_param(mac_interface_params::BCCH_SI_WINDOW_ST, -1);
params_db.set_param(mac_interface_params::BCCH_SI_WINDOW_LEN, -1);
}
if (_si_window_length > 0 && _si_window_start >= 0 && !si_search_in_progress) {
si_window_length = _si_window_length;
si_window_start = _si_window_start;
Debug("Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, 0xffff, si_window_start, si_window_start+si_window_length);
si_search_in_progress = true;
}
if ((_si_window_length < 0 || _si_window_start < 0) && si_search_in_progress) {
phy_h->pdcch_dl_search_reset();
si_search_in_progress = false;
Debug("SI search interrupted by higher layers\n");
}
}
void mac::tti_clock(uint32_t tti)
{
ttisync.increase();
}
void mac::bch_decoded_ok(uint8_t* payload, uint32_t len)
{
// Send MIB to RRC
rlc_h->write_pdu_bcch_bch(payload, len);
if (pcap) {
pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti());
}
}
void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
ul_harq.harq_recv(tti, ack, action);
}
void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_RAR) {
ra_procedure.new_grant_dl(grant, action);
} else {
// If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it
if (grant.rnti_type == SRSLTE_RNTI_USER) {
if (ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(false);
}
}
dl_harq.new_grant_dl(grant, action);
}
}
uint32_t mac::get_current_tti()
{
return phy_h->get_current_tti();
}
void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER) {
if (ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(true);
}
}
ul_harq.new_grant_ul(grant, action);
}
void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
ul_harq.new_grant_ul_ack(grant, ack, action);
}
void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_RAR) {
if (ack) {
ra_procedure.tb_decoded_ok();
}
} else {
dl_harq.tb_decoded(ack, rnti_type, harq_pid);
}
}
void mac::setup_timers()
{
if (params_db.get_param(mac_interface_params::TIMER_TIMEALIGN) > 0) {
timers_db.get(TIME_ALIGNMENT)->set(this, params_db.get_param(mac_interface_params::TIMER_TIMEALIGN));
}
}
void mac::timer_expired(uint32_t timer_id)
{
switch(timer_id) {
case TIME_ALIGNMENT:
timeAlignmentTimerExpire();
break;
default:
break;
}
}
/* Function called on expiry of TimeAlignmentTimer */
void mac::timeAlignmentTimerExpire()
{
dl_harq.reset();
ul_harq.reset();
}
void mac::set_param(mac_interface_params::mac_param_t param, int64_t value)
{
params_db.set_param((uint32_t) param, value);
}
int64_t mac::get_param(mac_interface_params::mac_param_t param)
{
return params_db.get_param((uint32_t) param);
}
void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD)
{
Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n",
lcid, lcg, priority, PBR_x_tti, BSD);
mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD);
bsr_procedure.setup_lcg(lcid, lcg);
bsr_procedure.set_priority(lcid, priority);
}
}
}

@ -1,97 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdint.h>
#include "srslte/srslte.h"
#include "srsapps/ue/mac/pcap.h"
#include "srsapps/ue/mac/mac_pcap.h"
namespace srslte {
namespace ue {
void mac_pcap::enable(bool en)
{
enable_write = true;
}
bool mac_pcap::open(const char* filename, uint32_t ue_id)
{
pcap_file = MAC_LTE_PCAP_Open(filename);
ue_id = ue_id;
enable_write = true;
}
void mac_pcap::close()
{
fprintf(stdout, "Saving PCAP file\n");
MAC_LTE_PCAP_Close(pcap_file);
}
void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti,
uint16_t crnti, uint8_t direction, uint8_t rnti_type)
{
if (enable_write) {
MAC_Context_Info_t context =
{
FDD_RADIO, direction, rnti_type,
crnti, /* RNTI */
ue_id, /* UEId */
reTX, /* Retx */
crc_ok, /* CRC Stsatus (i.e. OK) */
tti/10, /* Sysframe number */
tti%10 /* Subframe number */
};
if (pdu) {
MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
void mac_pcap::write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_pcap::write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_pcap::write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, reTX, true, tti, rnti, DIRECTION_UPLINK, C_RNTI);
}
void mac_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, 0, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI);
}
}
}

@ -1,356 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/mac/mux.h"
#include "srsapps/ue/mac/mac.h"
namespace srslte {
namespace ue {
mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS)
{
msg3_buff.init(1, MSG3_BUFF_SZ);
pthread_mutex_init(&mutex, NULL);
msg3_has_been_transmitted = false;
for (int i=0;i<NOF_UL_LCH;i++) {
priority[i] = i;
priority_sorted[i] = i;
PBR[i] = -1; // -1 is infinite
BSD[i] = 10;
lchid_sorted[i] = i;
}
phr_included = false;
pending_crnti_ce = 0;
}
void mux::init(rlc_interface_mac *rlc_, log *log_h_, bsr_proc *bsr_procedure_)
{
log_h = log_h_;
rlc = rlc_;
bsr_procedure = bsr_procedure_;
}
void mux::reset()
{
for (int i=0;i<NOF_UL_LCH;i++) {
Bj[i] = 0;
}
pending_crnti_ce = 0;
}
bool mux::is_pending_ccch_sdu()
{
return is_pending_sdu(0);
}
bool mux::is_pending_any_sdu()
{
for (int i=0;i<NOF_UL_LCH;i++) {
if (rlc->get_buffer_state(i)) {
return true;
}
}
return false;
}
bool mux::is_pending_sdu(uint32_t lch_id) {
return rlc->get_buffer_state(lch_id)>0;
}
void mux::set_priority(uint32_t lch_id, uint32_t set_priority, int set_PBR, uint32_t set_BSD)
{
pthread_mutex_lock(&mutex);
if (lch_id < NOF_UL_LCH) {
priority[lch_id] = set_priority;
PBR[lch_id] = set_PBR;
BSD[lch_id] = set_BSD;
// Insert priority in sorted idx array
int new_index = 0;
while(set_priority > priority_sorted[new_index] && new_index < NOF_UL_LCH) {
new_index++;
}
int old_index = 0;
while(lch_id != lchid_sorted[old_index] && new_index < NOF_UL_LCH) {
old_index++;
}
if (new_index == NOF_UL_LCH) {
Error("Can't find LchID=%d in sorted list\n", lch_id);
return;
}
// Replace goes in one direction or the other
int add=new_index>old_index?1:-1;
for (int i=old_index;i!=new_index;i+=add) {
priority_sorted[i] = priority_sorted[i+add];
lchid_sorted[i] = lchid_sorted[i+add];
}
priority_sorted[new_index] = set_priority;
lchid_sorted[new_index] = lch_id;
}
pthread_mutex_unlock(&mutex);
}
sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) {
switch(format) {
case bsr_proc::LONG_BSR:
return sch_subh::LONG_BSR;
case bsr_proc::SHORT_BSR:
return sch_subh::SHORT_BSR;
case bsr_proc::TRUNC_BSR:
return sch_subh::TRUNC_BSR;
}
}
// Multiplexing and logical channel priorization as defined in Section 5.4.3
uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz)
{
if (pthread_mutex_trylock(&mutex)) {
printf("M");fflush(stdout);
pthread_mutex_lock(&mutex);
}
// Update Bj
for (int i=0;i<NOF_UL_LCH;i++) {
// Add PRB unless it's infinity
if (PBR[i] >= 0) {
Bj[i] += PBR[i];
}
if (Bj[i] >= BSD[i]) {
Bj[i] = BSD[i];
}
}
// Logical Channel Procedure
pdu_msg.init_tx(payload, pdu_sz, true);
// MAC control element for C-RNTI or data from UL-CCCH
bool is_first = true;
if (!allocate_sdu(0, &pdu_msg, &is_first)) {
if (pending_crnti_ce) {
if (pdu_msg.new_subh()) {
pdu_msg.next();
if (!pdu_msg.get()->set_c_rnti(pending_crnti_ce)) {
Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n");
}
}
}
}
pending_crnti_ce = 0;
uint32_t bsr_payload_sz = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_msg.rem_size());
bsr_proc::bsr_t bsr;
// MAC control element for BSR, with exception of BSR included for padding;
sch_subh *bsr_subh = NULL;
if (bsr_payload_sz) {
Debug("Including BSR CE size %d\n", bsr_payload_sz);
if (pdu_msg.new_subh()) {
pdu_msg.next();
bsr_subh = pdu_msg.get();
pdu_msg.update_space_ce(bsr_payload_sz);
}
}
// MAC control element for PHR
if (!phr_included) {
if (pdu_msg.new_subh()) {
phr_included = true;
pdu_msg.next();
pdu_msg.get()->set_phr(46);
}
}
// data from any Logical Channel, except data from UL-CCCH;
// first only those with positive Bj
uint32_t sdu_sz = 0;
for (int i=1;i<NOF_UL_LCH;i++) {
uint32_t lcid = lchid_sorted[i];
if (lcid != 0) {
bool res = true;
while ((Bj[lcid] > 0 || PBR[lcid] < 0) && res) {
res = allocate_sdu(lcid, &pdu_msg, (PBR[lcid]<0)?-1:Bj[lcid], &sdu_sz, &is_first);
if (res && PBR[lcid] >= 0) {
Bj[lcid] -= sdu_sz;
}
}
}
}
// If resources remain, allocate regardless of their Bj value
for (int i=1;i<NOF_UL_LCH;i++) {
while (allocate_sdu(lchid_sorted[i], &pdu_msg));
}
bool send_bsr = bsr_procedure->generate_bsr_on_ul_grant(pdu_msg.rem_size(), &bsr);
// Insert Padding BSR if not inserted Regular/Periodic BSR
if (!bsr_payload_sz && send_bsr) {
if (pdu_msg.new_subh()) {
pdu_msg.next();
bsr_subh = pdu_msg.get();
}
}
// And set the BSR
if (bsr_subh) {
bsr_subh->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format), bsr_payload_sz?false:true);
}
Debug("Assembled MAC PDU msg size %d/%d bytes\n", pdu_msg.size(), pdu_sz);
/* Generate MAC PDU and save to buffer */
uint8_t *ret = pdu_msg.write_packet();
pthread_mutex_unlock(&mutex);
return ret;
}
void mux::append_crnti_ce_next_tx(uint16_t crnti) {
pending_crnti_ce = crnti;
}
bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg)
{
return allocate_sdu(lcid, pdu_msg, -1, NULL, NULL);
}
bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg, bool *is_first)
{
return allocate_sdu(lcid, pdu_msg, -1, NULL, is_first);
}
bool mux::allocate_sdu(uint32_t lcid, sch_pdu *pdu_msg, int max_sdu_sz, uint32_t *sdu_sz, bool *is_first)
{
// Get n-th pending SDU pointer and length
int sdu_len = rlc->get_buffer_state(lcid);
if (sdu_len > 0) { // there is pending SDU to allocate
int buffer_state = sdu_len;
if (sdu_len > max_sdu_sz && max_sdu_sz >= 0) {
sdu_len = max_sdu_sz;
}
if (sdu_len > pdu_msg->rem_size() - 3) {
sdu_len = pdu_msg->rem_size() - 3;
}
if (sdu_len > MIN_RLC_SDU_LEN) {
if (pdu_msg->new_subh()) { // there is space for a new subheader
pdu_msg->next();
int sdu_len2 = sdu_len;
sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc, is_first?*is_first:false);
if (sdu_len > 0) { // new SDU could be added
if (is_first) {
*is_first = false;
}
if (sdu_sz) {
*sdu_sz = sdu_len;
}
Info("Allocated SDU lcid=%d nbytes=%d, buffer_state=%d\n", lcid, sdu_len, buffer_state);
/*
char str[64];
int len = 10;
if (len > sdu_len) {
len = sdu_len;
}
uint8_t *x=pdu_msg->get()->get_sdu_ptr();
for (int i=0;i<len;i++) {
sprintf(str, "0x%x, ", x[i]);
}
Info("Payload: %s\n", str);
*/
return true;
} else {
Info("Could not add SDU rem_size=%d, sdu_len=%d\n", pdu_msg->rem_size(), sdu_len2);
pdu_msg->del_subh();
}
}
}
}
return false;
}
void mux::msg3_flush()
{
Info("Msg3 buffer flushed\n");
msg3_buff.flush();
msg3_has_been_transmitted = false;
}
bool mux::msg3_is_transmitted()
{
return msg3_has_been_transmitted;
}
bool mux::pdu_move_to_msg3(uint32_t pdu_sz)
{
uint8_t *msg3_start = (uint8_t*) msg3_buff.request();
if (msg3_start) {
uint8_t *msg3_pdu = pdu_get(msg3_start, pdu_sz);
if (msg3_pdu) {
memmove(msg3_start, msg3_pdu, pdu_sz*sizeof(uint8_t));
msg3_buff.push(pdu_sz);
return true;
} else {
Error("Assembling PDU\n");
}
} else {
Error("Generating PDU: PDU pending in buffer for transmission\n");
}
return false;
}
/* Returns a pointer to the Msg3 buffer */
uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz)
{
if (msg3_buff.isempty()) {
Info("Moving PDU from Mux unit to Msg3 buffer\n");
if (!pdu_move_to_msg3(pdu_sz)) {
Error("Moving PDU from Mux unit to Msg3 buffer\n");
return NULL;
}
}
uint8_t *msg3 = (uint8_t*) msg3_buff.pop();
if (msg3) {
memcpy(payload, msg3, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true;
return payload;
} else {
Error("Generating Msg3\n");
}
return NULL;
}
}
}

@ -1,732 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <strings.h>
#include <string.h>
#include <stdlib.h>
#include "srsapps/ue/mac/pdu.h"
#include "srslte/srslte.h"
namespace srslte {
namespace ue {
void sch_pdu::fprint(FILE* stream)
{
fprintf(stream, "MAC SDU for UL/DL-SCH. ");
pdu::fprint(stream);
}
void sch_subh::fprint(FILE* stream)
{
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
} else {
if (parent->is_ul()) {
switch(lcid) {
case C_RNTI:
fprintf(stream, "C-RNTI CE\n");
break;
case PHR_REPORT:
fprintf(stream, "PHR\n");
break;
case TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
} else {
switch(lcid) {
case CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id());
break;
case TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
break;
case DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
}
}
void sch_pdu::parse_packet(uint8_t *ptr)
{
pdu::parse_packet(ptr);
// Correct size for last SDU
if (nof_subheaders > 0) {
uint32_t read_len = 0;
for (int i=0;i<nof_subheaders-1;i++) {
read_len += subheaders[i].size_plus_header();
}
if (pdu_len-read_len-1 >= 0) {
subheaders[nof_subheaders-1].set_payload_size(pdu_len-read_len-1);
} else {
fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n");
}
}
}
// Section 6.1.2
uint8_t* sch_pdu::write_packet()
{
bool last_is_padding = false;
// Find last SDU or CE
int last_sh = 0;
int last_sdu = nof_subheaders-1;
bool is_sdu = false;
while(last_sdu >= 0 && !is_sdu) {
is_sdu = subheaders[last_sdu].is_sdu();
if (!is_sdu && last_sdu>=0) {
last_sdu--;
}
}
int last_ce = nof_subheaders-1;
is_sdu = true;
while(last_ce >= 0 && is_sdu) {
is_sdu = subheaders[last_ce].is_sdu();
if (is_sdu && last_ce>=0) {
last_ce--;
}
}
if (last_sdu >=0 ) {
last_sh = subheaders[last_sdu].is_sdu()?last_sdu:last_ce;
}
// Add subheaders and MAC CE before SDU's
uint32_t head_and_ce_sz = pdu_len-total_sdu_len;
if (rem_len < 2) {
head_and_ce_sz -= rem_len;
} else {
head_and_ce_sz -= rem_len - 2;
}
if (head_and_ce_sz >= sdu_offset_start) {
fprintf(stderr, "Writting PDU: head_and_ce_sz>=sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n",
head_and_ce_sz, sdu_offset_start, pdu_len, total_sdu_len);
return NULL;
}
uint8_t *ptr = &buffer_tx[sdu_offset_start-head_and_ce_sz];
uint8_t *pdu_start_ptr = ptr;
//printf("Head + CE size: %d bytes, data start 0x%x, pdu_len=%d, total_sdu_len=%d, rem_len=%d\n",
// head_and_ce_sz, buffer_tx[sdu_offset_start], pdu_len, total_sdu_len, rem_len);
// Add multi-byte padding if there are more than 2 bytes or there are 2 bytes
// and there is at least one SDU
if (rem_len > 2) {
last_is_padding = true;
} else if (rem_len > 0) {
// Add single or two-byte padding if required
if (rem_len == 1 || rem_len == 2) {
sch_subh padding;
padding.set_padding();
for (int i=0;i<rem_len;i++) {
padding.write_subheader(&ptr, false);
}
rem_len = 0;
}
}
if (last_is_padding) {
last_sh = -1;
}
// Write subheaders for MAC CE first
for (int i=0;i<nof_subheaders;i++) {
if (!subheaders[i].is_sdu()) {
subheaders[i].write_subheader(&ptr, i==last_sh);
}
}
// Then for SDUs
for (int i=0;i<nof_subheaders;i++) {
if (subheaders[i].is_sdu()) {
subheaders[i].write_subheader(&ptr, i==last_sh);
}
}
// Then for padding
if (last_is_padding) {
sch_subh padding;
padding.set_padding(rem_len);
padding.write_subheader(&ptr, true);
rem_len -= 2;
}
// Write CE payloads (SDU payloads already in the buffer)
for (int i=0;i<nof_subheaders;i++) {
if (!subheaders[i].is_sdu()) {
subheaders[i].write_payload(&ptr);
}
}
// Set paddint to zeros (if any)
bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t));
return pdu_start_ptr;
}
uint32_t sch_pdu::rem_size() {
return rem_len;
}
uint32_t sch_pdu::size()
{
return pdu_len - rem_len;
}
uint32_t sch_pdu::size_plus_header_sdu(uint32_t nbytes)
{
if (nbytes < 128) {
return nbytes + 2;
} else {
return nbytes + 3;
}
}
bool sch_pdu::has_space_ce(uint32_t nbytes)
{
if (rem_len >= nbytes + 1) {
return true;
} else {
return false;
}
}
bool sch_pdu::has_space_sdu(uint32_t nbytes)
{
return has_space_sdu(nbytes, false);
}
bool sch_pdu::has_space_sdu(uint32_t nbytes, bool is_first)
{
uint32_t sizeh_first=is_first?1:0;
if (rem_len >= size_plus_header_sdu(nbytes)-sizeh_first) {
return true;
} else {
return false;
}
}
bool sch_pdu::update_space_ce(uint32_t nbytes)
{
if (has_space_ce(nbytes)) {
rem_len -= nbytes + 1;
}
}
bool sch_pdu::update_space_sdu(uint32_t nbytes) {
return update_space_sdu(nbytes, false);
}
bool sch_pdu::update_space_sdu(uint32_t nbytes, bool is_first)
{
uint32_t sizeh_first=is_first?1:0;
if (has_space_sdu(nbytes, is_first)) {
rem_len -= (size_plus_header_sdu(nbytes)-sizeh_first);
}
}
void sch_subh::init()
{
lcid = 0;
nof_bytes = 0;
payload = NULL;
}
sch_subh::cetype sch_subh::ce_type()
{
if (lcid >= PHR_REPORT) {
return (cetype) lcid;
} else {
return SDU;
}
}
void sch_subh::set_payload_size(uint32_t size) {
nof_bytes = size;
}
uint32_t sch_subh::size_plus_header() {
if (is_sdu()) {
return sch_pdu::size_plus_header_sdu(nof_bytes);
} else {
return nof_bytes + 1;
}
}
uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul)
{
if (is_ul) {
switch(lcid) {
case PHR_REPORT:
return 1;
case C_RNTI:
return 2;
case TRUNC_BSR:
return 1;
case SHORT_BSR:
return 1;
case LONG_BSR:
return 3;
case PADDING:
return 0;
}
} else {
switch(lcid) {
case CON_RES_ID:
return 6;
case TA_CMD:
return 1;
case DRX_CMD:
return 0;
case PADDING:
return 0;
}
}
}
bool sch_subh::is_sdu()
{
return ce_type() == SDU;
}
uint16_t sch_subh::get_c_rnti()
{
if (payload) {
return (uint16_t) payload[0] | payload[1]<<8;
} else {
return 0;
}
}
uint64_t sch_subh::get_con_res_id()
{
if (payload) {
return ((uint64_t) payload[5]) | (((uint64_t) payload[4])<<8) | (((uint64_t) payload[3])<<16) | (((uint64_t) payload[2])<<24) |
(((uint64_t) payload[1])<<32) | (((uint64_t) payload[0])<<40);
} else {
return 0;
}
}
uint8_t sch_subh::get_phr()
{
if (payload) {
return (uint8_t) payload[0]&0x3f;
} else {
return 0;
}
}
uint8_t sch_subh::get_ta_cmd()
{
if (payload) {
return (uint8_t) payload[0]&0x3f;
} else {
return 0;
}
}
uint32_t sch_subh::get_sdu_lcid()
{
return lcid;
}
uint32_t sch_subh::get_sdu_nbytes()
{
return nof_bytes;
}
uint8_t* sch_subh::get_sdu_ptr()
{
return payload;
}
void sch_subh::set_padding(uint32_t padding_len)
{
lcid = PADDING;
nof_bytes = padding_len;
}
void sch_subh::set_padding()
{
set_padding(0);
}
bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format, bool update_size)
{
uint32_t nonzero_lcg=0;
for (int i=0;i<4;i++) {
if (buff_size[i]) {
nonzero_lcg=i;
}
}
uint32_t ce_size = format==LONG_BSR?3:1;
if (((sch_pdu*)parent)->has_space_ce(ce_size) || !update_size) {
if (format==LONG_BSR) {
w_payload_ce[0] = (buff_size_table(buff_size[0])&0x3f) << 2 | (buff_size_table(buff_size[1])&0xc0)>>6;
w_payload_ce[1] = (buff_size_table(buff_size[1])&0xf) << 4 | (buff_size_table(buff_size[2])&0xf0)>>4;
w_payload_ce[2] = (buff_size_table(buff_size[2])&0x3) << 6 | (buff_size_table(buff_size[3])&0x3f);
} else {
w_payload_ce[0] = (nonzero_lcg&0x3)<<6 | buff_size_table(buff_size[nonzero_lcg])&0x3f;
}
lcid = format;
if (update_size) {
((sch_pdu*)parent)->update_space_ce(ce_size);
}
return true;
} else {
return false;
}
}
bool sch_subh::set_c_rnti(uint16_t crnti)
{
if (((sch_pdu*)parent)->has_space_ce(2)) {
w_payload_ce[0] = (uint8_t) (crnti&0xff00)>>8;
w_payload_ce[1] = (uint8_t) (crnti&0x00ff);
lcid = C_RNTI;
((sch_pdu*)parent)->update_space_ce(2);
return true;
} else {
return false;
}
}
bool sch_subh::set_con_res_id(uint64_t con_res_id)
{
if (((sch_pdu*)parent)->has_space_ce(6)) {
w_payload_ce[0] = (uint8_t) ((con_res_id&0xff0000000000)>>48);
w_payload_ce[1] = (uint8_t) ((con_res_id&0x00ff00000000)>>32);
w_payload_ce[2] = (uint8_t) ((con_res_id&0x0000ff000000)>>24);
w_payload_ce[3] = (uint8_t) ((con_res_id&0x000000ff0000)>>16);
w_payload_ce[4] = (uint8_t) ((con_res_id&0x00000000ff00)>>8);
w_payload_ce[5] = (uint8_t) ((con_res_id&0x0000000000ff));
lcid = CON_RES_ID;
((sch_pdu*)parent)->update_space_ce(6);
return true;
} else {
return false;
}
}
bool sch_subh::set_phr(uint8_t phr)
{
if (((sch_pdu*)parent)->has_space_ce(1)) {
w_payload_ce[0] = phr&0x3f;
lcid = PHR_REPORT;
((sch_pdu*)parent)->update_space_ce(1);
return true;
} else {
return false;
}
}
bool sch_subh::set_ta_cmd(uint8_t ta_cmd)
{
if (((sch_pdu*)parent)->has_space_ce(1)) {
w_payload_ce[0] = ta_cmd&0x3f;
lcid = TA_CMD;
((sch_pdu*)parent)->update_space_ce(1);
return true;
} else {
return false;
}
}
int sch_subh::set_sdu(uint32_t lcid_, uint32_t nof_bytes_, rlc_interface_mac *rlc)
{
return set_sdu(lcid_, nof_bytes_, rlc, false);
}
int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, rlc_interface_mac *rlc, bool is_first)
{
if (((sch_pdu*)parent)->has_space_sdu(requested_bytes, is_first)) {
lcid = lcid_;
payload = ((sch_pdu*)parent)->get_current_sdu_ptr();
// Copy data and get final number of bytes written to the MAC PDU
int sdu_sz = rlc->read_pdu(lcid, payload, requested_bytes);
if (sdu_sz < 0 || sdu_sz > requested_bytes) {
return -1;
} else if (sdu_sz == 0) {
return 0;
}
// Save final number of written bytes
nof_bytes = sdu_sz;
((sch_pdu*)parent)->add_sdu(nof_bytes);
((sch_pdu*)parent)->update_space_sdu(nof_bytes, is_first);
return (int) nof_bytes;
} else {
return -1;
}
}
// Section 6.2.1
void sch_subh::write_subheader(uint8_t** ptr, bool is_last)
{
*(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f);
*ptr += 1;
if (is_sdu()) {
// MAC SDU: R/R/E/LCID/F/L subheader
// 2nd and 3rd octet
if (!is_last) {
if (nof_bytes >= 128) {
*(*ptr) = (uint8_t) 1<<7 | ((nof_bytes & 0x7f00) >> 8);
*ptr += 1;
*(*ptr) = (uint8_t) (nof_bytes & 0xff);
*ptr += 1;
} else {
*(*ptr) = (uint8_t) (nof_bytes & 0x7f);
*ptr += 1;
}
}
}
}
void sch_subh::write_payload(uint8_t** ptr)
{
if (is_sdu()) {
// SDU is written directly during subheader creation
} else {
nof_bytes = sizeof_ce(lcid, parent->is_ul());
memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t));
}
*ptr += nof_bytes;
}
bool sch_subh::read_subheader(uint8_t** ptr)
{
// Skip R
bool e_bit = (bool) (*(*ptr) & 0x20)?true:false;
lcid = (uint8_t) *(*ptr) & 0x1f;
*ptr += 1;
if (is_sdu()) {
if (e_bit) {
F_bit = (bool) (*(*ptr) & 0x80)?true:false;
nof_bytes = (uint32_t)*(*ptr) & 0x7f;
*ptr += 1;
if (F_bit) {
nof_bytes = nof_bytes<<8 | (uint32_t) *(*ptr) & 0xff;
*ptr += 1;
}
} else {
nof_bytes = 0;
F_bit = 0;
}
} else {
nof_bytes = sizeof_ce(lcid, parent->is_ul());
}
return e_bit;
}
void sch_subh::read_payload(uint8_t** ptr)
{
payload = *ptr;
*ptr += nof_bytes;
}
// Table 6.1.3.1-1 Buffer size levels for BSR
uint32_t btable[61] = {
10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132,
1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4667, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304,
42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125};
uint8_t sch_subh::buff_size_table(uint32_t buffer_size) {
if (buffer_size == 0) {
return 0;
} else if (buffer_size > 150000) {
return 63;
} else {
for (int i=0;i<61;i++) {
if (buffer_size < btable[i]) {
return 1+i;
}
}
return 62;
}
}
void rar_pdu::fprint(FILE* stream)
{
fprintf(stream, "MAC PDU for RAR. ");
if (has_backoff_indicator) {
fprintf(stream, "Backoff Indicator %d. ", backoff_indicator);
}
pdu::fprint(stream);
}
void rar_subh::fprint(FILE* stream)
{
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
srslte_vec_fprint_hex(stream, grant, 20);
}
rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_)
{
backoff_indicator = 0;
has_backoff_indicator = false;
}
uint8_t rar_pdu::get_backoff()
{
return backoff_indicator;
}
bool rar_pdu::has_backoff()
{
return has_backoff_indicator;
}
void rar_pdu::set_backoff(uint8_t bi)
{
has_backoff_indicator = true;
backoff_indicator = bi;
}
// Section 6.1.5
bool rar_pdu::write_packet(uint8_t* ptr)
{
// Write Backoff Indicator, if any
if (has_backoff_indicator) {
if (nof_subheaders > 0) {
*(ptr) = 1<<7 | backoff_indicator&0xf;
}
}
// Write RAR subheaders
for (int i=0;i<nof_subheaders;i++) {
subheaders[i].write_subheader(&ptr, i==nof_subheaders-1);
}
// Write payload
for (int i=0;i<nof_subheaders;i++) {
subheaders[i].write_payload(&ptr);
}
// Set paddint to zeros (if any)
bzero(ptr, rem_len*sizeof(uint8_t));
return true;
}
void rar_subh::init()
{
bzero(grant, sizeof(uint8_t) * RAR_GRANT_LEN);
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)
{
*(*ptr + 0) = (uint8_t) (is_last<<7 | 1<<6 | preamble & 0x3f);
*ptr += 1;
}
// Section 6.2.3
void rar_subh::write_payload(uint8_t** ptr)
{
*(*ptr + 0) = (uint8_t) (ta&0x7f0)>>4;
*(*ptr + 1) = (uint8_t) (ta&0xf) <<4 | grant[0]<<3 | grant[1] << 2 | grant[2] << 1 | grant[3];
uint8_t *x = &grant[4];
*(*ptr + 2) = (uint8_t) srslte_bit_unpack(&x, 8);
*(*ptr + 3) = (uint8_t) srslte_bit_unpack(&x, 8);
*(*ptr + 4) = (uint8_t) ((temp_rnti&0xff00) >> 8);
*(*ptr + 5) = (uint8_t) (temp_rnti&0x00ff);
*ptr += 6;
}
void rar_subh::read_payload(uint8_t** ptr)
{
ta = ((uint32_t) *(*ptr + 0)&0x7f)<<4 | (*(*ptr + 1)&0xf0)>>4;
grant[0] = *(*ptr + 1)&0x8;
grant[1] = *(*ptr + 1)&0x4;
grant[2] = *(*ptr + 1)&0x2;
grant[3] = *(*ptr + 1)&0x1;
uint8_t *x = &grant[4];
srslte_bit_pack(*(*ptr+2), &x, 8);
srslte_bit_pack(*(*ptr+3), &x, 8);
temp_rnti = ((uint16_t) *(*ptr + 4))<<8 | *(*ptr + 5);
*ptr += 6;
}
bool rar_subh::read_subheader(uint8_t** ptr)
{
bool e_bit = *(*ptr) & 0x80;
bool type = *(*ptr) & 0x40;
if (type) {
preamble = *(*ptr) & 0x3f;
} else {
((rar_pdu*)parent)->set_backoff(*(*ptr) & 0xf);
}
*ptr += 1;
return e_bit;
}
}
}

@ -1,361 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/mac/proc_bsr.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/mux.h"
namespace srslte {
namespace ue {
bsr_proc::bsr_proc()
{
initiated = false;
timer_periodic = false;
timer_retx = false;
reset_sr = false;
for (int i=0;i<MAX_LCID;i++) {
lcg[i] = -1;
priorities[i] = -1;
last_pending_data[i] = 0;
}
last_print = 0;
triggered_bsr_type=NONE;
}
void bsr_proc::init(rlc_interface_mac *rlc_, log* log_h_, mac_params* params_db_, timers *timers_db_)
{
log_h = log_h_;
rlc = rlc_;
params_db = params_db_;
timers_db = timers_db_;
initiated = true;
}
void bsr_proc::reset()
{
triggered_bsr_type = NONE;
}
/* Process Periodic BSR */
void bsr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) {
case mac::BSR_TIMER_PERIODIC:
if (triggered_bsr_type == NONE) {
// Check condition 4 in Sec 5.4.5
triggered_bsr_type = PERIODIC;
Info("Triggering BSR PERIODIC\n");
}
break;
case mac::BSR_TIMER_RETX:
// Enable reTx of SR
triggered_bsr_type = REGULAR;
Info("Triggering BSR reTX\n");
sr_is_sent = false;
break;
}
}
// Checks if data is available for a a channel with higher priority than others
bool bsr_proc::check_highest_channel() {
int pending_data_lcid = -1;
for (int i=0;i<MAX_LCID && pending_data_lcid == -1;i++) {
if (lcg[i] >= 0) {
if (rlc->get_buffer_state(i) > 0) {
pending_data_lcid = i;
for (int j=0;j<MAX_LCID;j++) {
if (rlc->get_buffer_state(j) > 0) {
if (priorities[j] > priorities[i]) {
pending_data_lcid = -1;
}
}
}
}
}
}
if (pending_data_lcid >= 0) {
// If there is new data available for this logical channel
uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid);
if (nbytes > last_pending_data[pending_data_lcid])
{
if (triggered_bsr_type != REGULAR) {
Info("Triggered REGULAR BSR for Max Priority LCID=%d\n", pending_data_lcid);
}
triggered_bsr_type = REGULAR;
return true;
}
}
return false;
}
// Checks if only one logical channel has data avaiable for Tx
bool bsr_proc::check_single_channel() {
uint32_t pending_data_lcid = 0;
uint32_t nof_nonzero_lcid = 0;
for (int i=0;i<MAX_LCID;i++) {
if (lcg[i] >= 0) {
if (rlc->get_buffer_state(i) > 0) {
pending_data_lcid = i;
nof_nonzero_lcid++;
}
}
}
if (nof_nonzero_lcid == 1) {
uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid);
// If there is new data available for this logical channel
if (nbytes > last_pending_data[pending_data_lcid]) {
triggered_bsr_type = REGULAR;
Info("Triggered REGULAR BSR for single LCID=%d\n", pending_data_lcid);
return true;
}
}
}
void bsr_proc::update_pending_data() {
for (int i=0;i<MAX_LCID;i++) {
last_pending_data[i] = rlc->get_buffer_state(i);
}
}
bool bsr_proc::generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes) {
bool ret = false;
uint32_t nof_lcg=0;
bzero(bsr, sizeof(bsr_t));
for (int i=0;i<MAX_LCID;i++) {
if (lcg[i] >= 0) {
uint32_t n = rlc->get_buffer_state(i);
bsr->buff_size[lcg[i]] += n;
if (n > 0) {
nof_lcg++;
ret = true;
}
}
}
if (triggered_bsr_type == PADDING) {
if (nof_padding_bytes < 4) {
// If space only for short
if (nof_lcg > 1) {
bsr->format = TRUNC_BSR;
uint32_t max_prio_ch = find_max_priority_lcid();
for (int i=0;i<4;i++) {
if (lcg[max_prio_ch] != i) {
bsr->buff_size[i] = 0;
}
}
} else {
bsr->format = SHORT_BSR;
}
} else {
// If space for long BSR
bsr->format = LONG_BSR;
}
} else {
bsr->format = SHORT_BSR;
if (nof_lcg > 1) {
bsr->format = LONG_BSR;
}
}
return ret;
}
// Checks if Regular BSR must be assembled, as defined in 5.4.5
// Padding BSR is assembled when called by mux_unit when UL grant is received
// Periodic BSR is triggered by the expiration of the timers
void bsr_proc::step(uint32_t tti)
{
if (!initiated) {
return;
}
if (!timer_periodic) {
if (params_db->get_param(mac_interface_params::BSR_TIMER_PERIODIC)) {
timer_periodic = true;
timers_db->get(mac::BSR_TIMER_PERIODIC)->set(this, params_db->get_param(mac_interface_params::BSR_TIMER_PERIODIC));
}
}
if (!timer_retx) {
if (params_db->get_param(mac_interface_params::BSR_TIMER_RETX)) {
timer_retx = true;
timers_db->get(mac::BSR_TIMER_RETX)->set(this, params_db->get_param(mac_interface_params::BSR_TIMER_RETX));
}
}
// Check condition 1 in Sec 5.4.5
if (triggered_bsr_type == NONE) {
check_single_channel();
}
// Higher priority channel is reported regardless of a BSR being already triggered
check_highest_channel();
update_pending_data();
if ((tti - last_print)%10240 > QUEUE_STATUS_PERIOD_MS) {
char str[128];
bzero(str, 128);
for (int i=0;i<MAX_LCID;i++) {
sprintf(str, "%s%d (%d), ", str, rlc->get_buffer_state(i), last_pending_data[i]);
}
Info("QUEUE status: %s\n", str);
last_print = tti;
}
}
char* bsr_proc::bsr_type_tostring(triggered_bsr_type_t type) {
switch(type) {
case bsr_proc::REGULAR:
return (char*) "Regular";
case bsr_proc::PADDING:
return (char*) "Padding";
case bsr_proc::PERIODIC:
return (char*) "Periodic";
}
}
char* bsr_proc::bsr_format_tostring(bsr_format_t format) {
switch(format) {
case bsr_proc::LONG_BSR:
return (char*) "Long";
case bsr_proc::SHORT_BSR:
return (char*) "Short";
case bsr_proc::TRUNC_BSR:
return (char*) "Truncated";
}
}
uint32_t bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size)
{
uint32_t bsr_sz = 0;
if (triggered_bsr_type == PERIODIC || triggered_bsr_type == REGULAR) {
/* Check if grant + MAC SDU headers is enough to accomodate all pending data */
uint32_t total_data = 0;
for (int i=0;i<MAX_LCID && total_data < grant_size;i++) {
total_data += sch_pdu::size_plus_header_sdu(rlc->get_buffer_state(i));
}
total_data--; // Because last SDU has no size header
/* All triggered BSRs shall be cancelled in case the UL grant can accommodate all pending data available for transmission
but is not sufficient to additionally accommodate the BSR MAC control element plus its subheader.
*/
bsr_t bsr;
generate_bsr(&bsr, 0);
bsr_sz = bsr.format==LONG_BSR?3:1;
if (total_data <= grant_size && total_data + 1 + bsr_sz > grant_size) {
bsr_sz = 0;
Info("Grant is not enough to accomodate the BSR MAC CE\n");
triggered_bsr_type = NONE;
}
Info("Checking if Regular BSR is sent: grant_size=%d, total_data=%d, bsr_sz=%d\n",
grant_size, total_data, bsr_sz);
}
return bsr_sz;
}
bool bsr_proc::generate_bsr_on_ul_grant(uint32_t nof_padding_bytes, bsr_t *bsr)
{
bool ret = false;
if (triggered_bsr_type != NONE || nof_padding_bytes >= 2) {
if (triggered_bsr_type == NONE) {
triggered_bsr_type = PADDING;
}
generate_bsr(bsr, nof_padding_bytes);
ret = true;
Info("Including BSR type %s, format %s, nof_padding_bytes=%d\n",
bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), nof_padding_bytes);
if (timer_periodic && bsr->format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run();
}
// Cancel all triggered BSR
triggered_bsr_type = NONE;
reset_sr = true;
}
// Restart or Start ReTX timer
if (timer_retx) {
timers_db->get(mac::BSR_TIMER_RETX)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->run();
}
return ret;
}
bool bsr_proc::need_to_reset_sr() {
if (reset_sr) {
reset_sr = false;
sr_is_sent = false;
Info("SR reset. sr_is_sent and reset_rs false\n");
return true;
} else {
return false;
}
}
bool bsr_proc::need_to_send_sr() {
if (!sr_is_sent && triggered_bsr_type == REGULAR) {
reset_sr = false;
sr_is_sent = true;
Info("Need to send sr: sr_is_sent=true, reset_sr=false\n");
return true;
}
return false;
}
void bsr_proc::setup_lcg(uint32_t lcid, uint32_t new_lcg)
{
if (lcid < MAX_LCID && new_lcg < 4) {
lcg[lcid] = new_lcg;
}
}
void bsr_proc::set_priority(uint32_t lcid, uint32_t priority) {
if (lcid < MAX_LCID) {
priorities[lcid] = priority;
}
}
uint32_t bsr_proc::find_max_priority_lcid() {
uint32_t max_prio = 0, max_idx = 0;
for (int i=0;i<MAX_LCID;i++) {
if (priorities[i] > max_prio) {
max_prio = priorities[i];
max_idx = i;
}
}
return max_idx;
}
}
}

@ -1,519 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include "srsapps/ue/mac/proc_ra.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/mux.h"
/* Random access procedure as specified in Section 5.1 of 36.321 */
namespace srslte {
namespace ue {
// Table 7.2-1. Backoff Parameter values
uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 960, 960, 960};
// Table 7.6-1: DELTA_PREAMBLE values.
int delta_preamble_db_table[5] = {0, 0, -3, -3, 8};
bool ra_proc::init(phy_interface* phy_h_, log* log_h_, mac_params* params_db_, timers* timers_db_,
mux* mux_unit_, demux* demux_unit_)
{
phy_h = phy_h_;
log_h = log_h_;
params_db = params_db_;
timers_db = timers_db_;
mux_unit = mux_unit_;
demux_unit= demux_unit_;
srslte_softbuffer_rx_init(&softbuffer_rar, 10);
reset();
}
void ra_proc::reset() {
state = IDLE;
}
void ra_proc::start_pcap(mac_pcap* pcap_)
{
pcap = pcap_;
}
void ra_proc::read_params() {
// Read initialization parameters
configIndex = params_db->get_param(mac_interface_params::RA_CONFIGINDEX);
preambleIndex = params_db->get_param(mac_interface_params::RA_PREAMBLEINDEX);
maskIndex = params_db->get_param(mac_interface_params::RA_MASKINDEX);
nof_preambles = params_db->get_param(mac_interface_params::RA_NOFPREAMBLES);
if (!nof_preambles || nof_preambles > 64) {
nof_preambles = 64;
}
nof_groupA_preambles = params_db->get_param(mac_interface_params::RA_NOFGROUPAPREAMBLES);
if (!nof_groupA_preambles) {
nof_groupA_preambles = nof_preambles;
}
if (nof_groupA_preambles > nof_preambles) {
nof_groupA_preambles = nof_preambles;
}
nof_groupB_preambles = nof_preambles - nof_groupA_preambles;
if (nof_groupB_preambles) {
messagePowerOffsetGroupB= params_db->get_param(mac_interface_params::RA_MESSAGEPOWEROFFSETB);
messageSizeGroupA = params_db->get_param(mac_interface_params::RA_MESSAGESIZEA);
Pcmax = params_db->get_param(mac_interface_params::RA_PCMAX);
deltaPreambleMsg3 = params_db->get_param(mac_interface_params::RA_DELTAPREAMBLEMSG3);
}
responseWindowSize = params_db->get_param(mac_interface_params::RA_RESPONSEWINDOW);
powerRampingStep = params_db->get_param(mac_interface_params::RA_POWERRAMPINGSTEP);
preambleTransMax = params_db->get_param(mac_interface_params::RA_PREAMBLETRANSMAX);
iniReceivedTargetPower = params_db->get_param(mac_interface_params::RA_INITRECEIVEDPOWER);
contentionResolutionTimer = params_db->get_param(mac_interface_params::RA_CONTENTIONTIMER);
delta_preamble_db = delta_preamble_db_table[configIndex%5];
if (contentionResolutionTimer > 0) {
timers_db->get(mac::CONTENTION_TIMER)->set(this, contentionResolutionTimer);
}
}
bool ra_proc::in_progress()
{
return (state > IDLE && state != COMPLETION);
}
bool ra_proc::is_successful() {
return state == COMPLETION;
}
bool ra_proc::is_response_error() {
return state == RESPONSE_ERROR;
}
bool ra_proc::is_contention_resolution() {
return state == CONTENTION_RESOLUTION;
}
bool ra_proc::is_error() {
return state == RA_PROBLEM;
}
const char* state_str[11] = {"Idle",
"RA Initializat.: ",
"RA ResSelection: ",
"RA PreambleTx : ",
"RA PDCCH setup : ",
"RA PreambleRx : ",
"RA ResponseErr : ",
"RA BackoffWait : ",
"RA ContentResol: ",
"RA Completed : ",
"RA Problem : "};
#define rError(fmt, ...) Error("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rInfo(fmt, ...) Info("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rDebug(fmt, ...) Debug("%s" fmt, state_str[state], ##__VA_ARGS__)
// Process Timing Advance Command as defined in Section 5.2
void ra_proc::process_timeadv_cmd(uint32_t ta) {
if (preambleIndex > 0) {
// Preamble not selected by UE MAC
phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run();
Info("Applying RAR TA CMD %d\n", ta);
} else {
// Preamble selected by UE MAC
if (!timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->run();
Info("Applying RAR TA CMD %d\n", ta);
} else {
// Ignore TA CMD
Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n");
}
}
}
void ra_proc::step_initialization() {
read_params();
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
transmitted_contention_id = 0;
preambleTransmissionCounter = 1;
first_rar_received = true;
mux_unit->msg3_flush();
msg3_flushed = false;
backoff_param_ms = 0;
// Instruct phy to configure PRACH
phy_h->configure_prach_params();
state = RESOURCE_SELECTION;
}
void ra_proc::step_resource_selection() {
ra_group_t sel_group;
if (preambleIndex > 0) {
// Preamble is chosen by Higher layers (ie Network)
sel_maskIndex = maskIndex;
sel_preamble = (uint32_t) preambleIndex%nof_preambles;
} else {
// Preamble is chosen by MAC UE
if (!msg3_transmitted) {
if (nof_groupB_preambles > 0) { // Check also messageSizeGroupA and pathloss (Pcmax,deltaPreamble and powerOffset)
sel_group = RA_GROUP_B;
} else {
sel_group = RA_GROUP_A;
}
last_msg3_group = sel_group;
} else {
sel_group = last_msg3_group;
}
if (sel_group == RA_GROUP_A) {
sel_preamble = rand()%(nof_groupA_preambles-1);
} else {
sel_preamble = nof_groupA_preambles + rand()%(nof_groupB_preambles-1);
}
sel_maskIndex = 0;
}
rInfo("Selected preambleIndex=%d maskIndex=%d nof_GroupApreambles=%d\n",
sel_preamble, sel_maskIndex,nof_groupA_preambles);
state = PREAMBLE_TRANSMISSION;
}
void ra_proc::step_preamble_transmission() {
received_target_power_dbm = iniReceivedTargetPower +
delta_preamble_db +
(preambleTransmissionCounter-1)*powerRampingStep;
phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm);
rInfo("Selected received_target_power_dbm=%d dBm\n", received_target_power_dbm);
state = PDCCH_SETUP;
}
void ra_proc::step_pdcch_setup() {
int ra_tti = phy_h->prach_tx_tti();
if (ra_tti > 0) {
ra_rnti = 1+ra_tti%10;
phy_h->pdcch_dl_search(SRSLTE_RNTI_RAR, ra_rnti, ra_tti+3, ra_tti+3+responseWindowSize);
state = RESPONSE_RECEPTION;
}
}
void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.n_bytes < MAX_RAR_PDU_LEN) {
rInfo("DL grant found RA-RNTI=%d\n", ra_rnti);
action->decode_enabled = true;
action->default_ack = false;
action->generate_ack = false;
action->payload_ptr = rar_pdu_buffer;
action->rnti = grant.rnti;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->rv = grant.rv;
action->softbuffer = &softbuffer_rar;
rar_grant_nbytes = grant.n_bytes;
rar_grant_tti = grant.tti;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rar);
}
} else {
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN);
action->decode_enabled = false;
state = RESPONSE_ERROR;
}
}
void ra_proc::tb_decoded_ok() {
if (pcap) {
pcap->write_dl_crnti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, rar_grant_tti);
}
rDebug("RAR decoded successfully TBS=%d\n", rar_grant_nbytes);
rar_pdu_msg.init_rx(rar_grant_nbytes);
rar_pdu_msg.parse_packet(rar_pdu_buffer);
// Set Backoff parameter
if (rar_pdu_msg.has_backoff()) {
backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff()%16];
} else {
backoff_param_ms = 0;
}
while(rar_pdu_msg.next()) {
if (rar_pdu_msg.get()->get_rapid() == sel_preamble) {
rInfo("Received RAPID=%d\n", sel_preamble);
process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd());
// FIXME: Indicate received target power
//phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep);
uint8_t grant[rar_subh::RAR_GRANT_LEN];
rar_pdu_msg.get()->get_sched_grant(grant);
phy_h->pdcch_dl_search_reset();
phy_h->set_rar_grant(rar_grant_tti, grant);
if (preambleIndex > 0) {
// Preamble selected by Network
state = COMPLETION;
} else {
// Preamble selected by UE MAC
params_db->set_param(mac_interface_params::RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti());
phy_h->pdcch_dl_search(SRSLTE_RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti());
if (first_rar_received) {
first_rar_received = false;
// Save transmitted C-RNTI (if any)
transmitted_crnti = params_db->get_param(mac_interface_params::RNTI_C);
// If we have a C-RNTI, tell Mux unit to append C-RNTI CE if no CCCH SDU transmission
if (transmitted_crnti) {
mux_unit->append_crnti_ce_next_tx(transmitted_crnti);
}
// Tell demux to call us when a UE CRID is received
demux_unit->set_uecrid_callback(uecrid_callback, this);
}
rDebug("Going to Contention Resolution state\n");
state = CONTENTION_RESOLUTION;
// Start contention resolution timer
timers_db->get(mac::CONTENTION_TIMER)->reset();
timers_db->get(mac::CONTENTION_TIMER)->run();
}
} else {
rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid());
}
}
}
void ra_proc::step_response_reception() {
// do nothing. Processing done in tb_decoded_ok()
}
void ra_proc::step_response_error() {
preambleTransmissionCounter++;
if (preambleTransmissionCounter >= preambleTransMax + 1) {
rError("Maximum number of transmissions reached (%d)\n", preambleTransMax);
state = RA_PROBLEM;
} else {
backoff_interval_start = phy_h->get_current_tti();
if (backoff_param_ms) {
backoff_inteval = rand()%backoff_param_ms;
} else {
backoff_inteval = 0;
}
if (backoff_inteval) {
rInfo("Backoff wait interval %d\n", backoff_inteval);
state = BACKOFF_WAIT;
} else {
rInfo("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, preambleTransMax);
state = RESOURCE_SELECTION;
}
}
}
void ra_proc::step_backoff_wait() {
if (srslte_tti_interval(phy_h->get_current_tti(), backoff_interval_start) >= backoff_inteval) {
state = RESOURCE_SELECTION;
}
}
bool ra_proc::uecrid_callback(void *arg, uint64_t uecri) {
return ((ra_proc*) arg)->contention_resolution_id_received(uecri);
}
// Random Access initiated by RRC by the transmission of CCCH SDU
bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) {
bool uecri_successful = false;
rDebug("MAC PDU Contains Contention Resolution ID CE\n");
// MAC PDU successfully decoded and contains MAC CE contention Id
timers_db->get(mac::CONTENTION_TIMER)->stop();
if (transmitted_contention_id == rx_contention_id)
{
rDebug("MAC PDU Contention Resolution ID matches the one transmitted in CCCH SDU\n");
// UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3
params_db->set_param(mac_interface_params::RNTI_C, params_db->get_param(mac_interface_params::RNTI_TEMP));
// finish the disassembly and demultiplexing of the MAC PDU
uecri_successful = true;
state = COMPLETION;
} else {
rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%lx != 0x%lx)\n",
transmitted_contention_id, rx_contention_id);
// Discard MAC PDU
uecri_successful = false;
// Contention Resolution not successfully is like RAR not successful
// FIXME: Need to flush Msg3 HARQ buffer. Why?
state = RESPONSE_ERROR;
}
params_db->set_param(mac_interface_params::RNTI_TEMP, 0);
return uecri_successful;
}
void ra_proc::step_contention_resolution() {
// If Msg3 has been sent
if (mux_unit->msg3_is_transmitted())
{
// Save transmitted UE contention id, as defined by higher layers
if (!transmitted_contention_id) {
transmitted_contention_id = params_db->get_param(mac_interface_params::CONTENTION_ID);
params_db->set_param(mac_interface_params::CONTENTION_ID, 0);
}
msg3_transmitted = true;
if (pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)
{
rInfo("PDCCH for C-RNTI received\n");
// Random Access initiated by MAC itself or PDCCH order (transmission of MAC C-RNTI CE)
if (start_mode == MAC_ORDER && pdcch_to_crnti_received == PDCCH_CRNTI_UL_GRANT ||
start_mode == PDCCH_ORDER)
{
timers_db->get(mac::CONTENTION_TIMER)->stop();
params_db->set_param(mac_interface_params::RNTI_TEMP, 0);
state = COMPLETION;
}
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
}
// RA initiated by RLC order is resolved in contention_resolution_id_received() callback function
} else {
rDebug("Msg3 not yet transmitted\n");
}
}
void ra_proc::step_completition() {
params_db->set_param(mac_interface_params::RA_PREAMBLEINDEX, 0);
params_db->set_param(mac_interface_params::RA_MASKINDEX, 0);
if (!msg3_flushed) {
mux_unit->msg3_flush();
msg3_flushed = true;
}
msg3_transmitted = false;
}
void ra_proc::step(uint32_t tti_)
{
if (is_running()) {
switch(state) {
case IDLE:
break;
case INITIALIZATION:
step_initialization();
break;
case RESOURCE_SELECTION:
step_resource_selection();
break;
case PREAMBLE_TRANSMISSION:
step_preamble_transmission();
break;
case PDCCH_SETUP:
step_pdcch_setup();
break;
case RESPONSE_RECEPTION:
step_response_reception();
break;
case RESPONSE_ERROR:
step_response_error();
break;
case BACKOFF_WAIT:
step_backoff_wait();
break;
case CONTENTION_RESOLUTION:
step_contention_resolution();
break;
case COMPLETION:
step_completition();
break;
}
}
}
void ra_proc::start_mac_order()
{
if (state == IDLE || state == COMPLETION || state == RA_PROBLEM) {
start_mode = MAC_ORDER;
state = INITIALIZATION;
Info("Starting PRACH by MAC order\n");
run();
}
}
void ra_proc::start_pdcch_order()
{
if (state == IDLE || state == COMPLETION || state == RA_PROBLEM) {
start_mode = PDCCH_ORDER;
state = INITIALIZATION;
Info("Starting PRACH by PDCCH order\n");
run();
}
}
void ra_proc::start_rlc_order()
{
if (state == IDLE || state == COMPLETION || state == RA_PROBLEM) {
start_mode = RLC_ORDER;
state = INITIALIZATION;
Info("Starting PRACH by RLC CCCH SDU order\n");
run();
}
}
// Contention Resolution Timer is expired (Section 5.1.5)
void ra_proc::timer_expired(uint32_t timer_id)
{
rInfo("Contention Resolution Timer expired. Going to Response Error\n");
params_db->set_param(mac_interface_params::RNTI_TEMP, 0);
state = RESPONSE_ERROR;
}
void ra_proc::pdcch_to_crnti(bool is_uplink_grant) {
if (is_uplink_grant) {
pdcch_to_crnti_received = PDCCH_CRNTI_UL_GRANT;
} else {
pdcch_to_crnti_received = PDCCH_CRNTI_DL_GRANT;
}
}
}
}

@ -1,102 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/ue/mac/proc_sr.h"
#include "srsapps/ue/mac/mac_params.h"
namespace srslte {
namespace ue {
sr_proc::sr_proc() {
initiated = false;
}
void sr_proc::init(phy_interface* phy_h_, log* log_h_, mac_params* params_db_)
{
log_h = log_h_;
params_db = params_db_;
phy_h = phy_h_;
initiated = true;
do_ra = false;
}
void sr_proc::reset()
{
is_pending_sr = false;
}
void sr_proc::step(uint32_t tti)
{
if (initiated) {
if (is_pending_sr) {
if (params_db->get_param(mac_interface_params::SR_PUCCH_CONFIGURED)) {
if (sr_counter < dsr_transmax) {
int last_tx_tti = phy_h->sr_last_tx_tti();
if (last_tx_tti >= 0 && last_tx_tti + 4 < tti || sr_counter == 0) {
sr_counter++;
Info("SR signalling PHY. sr_counter=%d, PHY TTI=%d\n", sr_counter, phy_h->get_current_tti());
phy_h->sr_send();
}
} else {
do_ra = true;
reset();
}
} else {
do_ra = true;
reset();
}
}
}
}
bool sr_proc::need_random_access() {
if (initiated) {
if (do_ra) {
do_ra = false;
return true;
} else {
return false;
}
}
}
void sr_proc::start()
{
if (initiated) {
if (!is_pending_sr) {
sr_counter = 0;
is_pending_sr = true;
}
dsr_transmax = params_db->get_param(mac_interface_params::SR_TRANS_MAX);
Info("SR starting dsrTransMax=%d. sr_counter=%d\n", dsr_transmax, sr_counter);
}
}
}
}

@ -1,349 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srsapps/common/log.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/ul_harq.h"
namespace srslte {
namespace ue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
bool ul_harq_entity::init(log *log_h_, mac_params *params_db_, timers *timers_db_, mux *mux_unit_) {
log_h = log_h_;
mux_unit = mux_unit_;
params_db = params_db_;
timers_db = timers_db_;
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
uint32_t ul_harq_entity::pidof(uint32_t tti) {
return (uint32_t) tti%NOF_HARQ_PROC;
}
void ul_harq_entity::start_pcap(mac_pcap* pcap_)
{
pcap = pcap_;
}
void ul_harq_entity::reset() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
}
void ul_harq_entity::reset_ndi() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset_ndi();
}
}
void ul_harq_entity::set_ack(uint32_t tti, bool ack) {
int tti_harq = (int) tti - 4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && proc[pid_harq].last_tx_tti() <= tti_harq) {
proc[pid_harq].set_harq_feedback(ack);
}
}
void ul_harq_entity::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(tti, ack);
run_tti(tti, NULL, action);
}
// Implements Section 5.4.1
void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
void ul_harq_entity::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(grant.tti, ack);
new_grant_ul(grant, action);
}
// Implements Section 5.4.2.1
// Called with UL grant
void ul_harq_entity::run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t tti_tx = (tti+4)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
static int rv_of_irv[4] = {0, 2, 3, 1};
static int irv_of_rv[4] = {0, 3, 1, 2};
ul_harq_entity::ul_harq_process::ul_harq_process() {
current_tx_nb = 0;
current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void ul_harq_entity::ul_harq_process::reset() {
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
if (is_initiated) {
srslte_softbuffer_tx_reset(&softbuffer);
}
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool ul_harq_entity::ul_harq_process::has_grant() {
return is_grant_configured;
}
void ul_harq_entity::ul_harq_process::reset_ndi() {
ndi = false;
}
bool ul_harq_entity::ul_harq_process::get_ndi()
{
return ndi;
}
uint32_t ul_harq_entity::ul_harq_process::get_rv()
{
return rv_of_irv[current_irv%4];
}
void ul_harq_entity::ul_harq_process::set_harq_feedback(bool ack) {
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL PID %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL PID %d: HARQ = NACK for UL transmission\n", pid);
}
}
bool ul_harq_entity::ul_harq_process::init(uint32_t pid_, ul_harq_entity* parent) {
if (srslte_softbuffer_tx_init(&softbuffer, 100)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void ul_harq_entity::ul_harq_process::run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t* grant, mac_interface_phy::tb_action_ul_t* action)
{
// Receive and route HARQ feedbacks
if (grant) {
if ((!grant->rnti_type == SRSLTE_RNTI_TEMP && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
// Uplink grant in a RAR
if (grant->is_from_rar) {
Info("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
generate_retx(tti_tx, grant, action);
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
generate_retx(tti_tx, action);
}
if (harq_entity->pcap && grant) {
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
generate_retx(tti_tx, NULL, action);
}
// Retransmission with or w/o grant (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
current_tx_nb++;
if (grant) {
// HARQ entity requests an adaptive transmission
current_irv = irv_of_rv[grant->rv%4];
harq_feedback = false;
Info("UL PID %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL PID %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(mac::CONTENTION_TIMER)->reset();
}
}
// New transmission (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_new_tx(uint32_t tti_tx, bool is_msg3_,
mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
srslte_softbuffer_tx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL PID %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
action->current_tx_nb = current_tx_nb;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->params_db->get_param(mac_interface_params::RNTI_TEMP):cur_grant.rnti;
action->rv = get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
if (is_msg3) {
if (current_tx_nb == harq_entity->params_db->get_param(mac_interface_params::HARQ_MAXMSG3TX)) {
Info("UL PID %d: Maximum number of ReTX for Msg3 reached (%d). Discarting TB.\n", pid,
harq_entity->params_db->get_param(mac_interface_params::HARQ_MAXMSG3TX));
reset();
action->expect_ack = false;
}
} else {
if (current_tx_nb == harq_entity->params_db->get_param(mac_interface_params::HARQ_MAXTX)) {
Info("UL PID %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid,
harq_entity->params_db->get_param(mac_interface_params::HARQ_MAXTX));
reset();
action->expect_ack = false;
}
}
}
bool ul_harq_entity::ul_harq_process::is_sps()
{
return false;
}
uint32_t ul_harq_entity::ul_harq_process::last_tx_tti()
{
return tti_last_tx;
}
uint32_t ul_harq_entity::ul_harq_process::get_nof_retx()
{
return current_tx_nb;
}
}
}

@ -1,28 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
FIND_PACKAGE(openLTE)
IF(UHD_FOUND AND OPENLTE_FOUND)
INCLUDE_DIRECTORIES(${OPENLTE_INCLUDE_DIRS})
ADD_EXECUTABLE(mac_test mac_test.cc)
TARGET_LINK_LIBRARIES(mac_test srsapps_common srsapps_ue_mac srsapps_ue_phy srsapps_radio srslte ${OPENLTE_LIBRARIES} srslte_uhd)
ENDIF(UHD_FOUND AND OPENLTE_FOUND)

@ -1,572 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <unistd.h>
#include <signal.h>
#include "liblte_rrc.h"
#include "srsapps/radio/radio_uhd.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/common/log_stdout.h"
#include "srsapps/ue/mac/mac.h"
#include "srsapps/ue/mac/mac_pcap.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float uhd_rx_freq;
float uhd_tx_freq;
float uhd_rx_gain;
float uhd_tx_gain;
int verbose;
bool do_trace;
bool do_pcap;
}prog_args_t;
void args_default(prog_args_t *args) {
args->uhd_rx_freq = -1.0;
args->uhd_tx_freq = -1.0;
args->uhd_rx_gain = -1; // set to autogain
args->uhd_tx_gain = -1;
args->verbose = 0;
args->do_trace = false;
args->do_pcap = false;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gGtpv] -f rx_frequency (in Hz) -F tx_frequency (in Hz)\n", prog);
printf("\t-g UHD RX gain [Default AGC]\n");
printf("\t-G UHD TX gain [Default same as RX gain (AGC)]\n");
printf("\t-t Enable trace [Default disabled]\n");
printf("\t-p Enable PCAP capture [Default disabled]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gGftpFv")) != -1) {
switch (opt) {
case 'g':
args->uhd_rx_gain = atof(argv[optind]);
break;
case 'G':
args->uhd_tx_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_rx_freq = atof(argv[optind]);
break;
case 'F':
args->uhd_tx_freq = atof(argv[optind]);
break;
case 't':
args->do_trace = true;
break;
case 'p':
args->do_pcap = true;
break;
case 'v':
args->verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_rx_freq < 0 || args->uhd_tx_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
}
void setup_mac_phy_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, srslte::ue::mac *mac, srslte::ue::phy *phy) {
// RACH-CONFIGCOMMON
if (sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.present) {
mac->set_param(srslte::ue::mac_interface_params::RA_NOFGROUPAPREAMBLES,
liblte_rrc_message_size_group_a_num[sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.size_of_ra]);
mac->set_param(srslte::ue::mac_interface_params::RA_MESSAGESIZEA,
liblte_rrc_message_size_group_a_num[sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_size]);
mac->set_param(srslte::ue::mac_interface_params::RA_MESSAGEPOWEROFFSETB,
liblte_rrc_message_power_offset_group_b_num[sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_pwr_offset_group_b]);
}
mac->set_param(srslte::ue::mac_interface_params::RA_NOFPREAMBLES,
liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles]);
mac->set_param(srslte::ue::mac_interface_params::RA_POWERRAMPINGSTEP,
liblte_rrc_power_ramping_step_num[sib2->rr_config_common_sib.rach_cnfg.pwr_ramping_step]);
mac->set_param(srslte::ue::mac_interface_params::RA_INITRECEIVEDPOWER,
liblte_rrc_preamble_initial_received_target_power_num[sib2->rr_config_common_sib.rach_cnfg.preamble_init_rx_target_pwr]);
mac->set_param(srslte::ue::mac_interface_params::RA_PREAMBLETRANSMAX,
liblte_rrc_preamble_trans_max_num[sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max]);
mac->set_param(srslte::ue::mac_interface_params::RA_RESPONSEWINDOW,
liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size]);
mac->set_param(srslte::ue::mac_interface_params::RA_CONTENTIONTIMER,
liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer]);
mac->set_param(srslte::ue::mac_interface_params::HARQ_MAXMSG3TX,
sib2->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx);
printf("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms, MaxTrials=%d\n",
liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles],
liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size],
liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer],
liblte_rrc_preamble_trans_max_num[sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max]);
// PDSCH ConfigCommon
mac->set_param(srslte::ue::mac_interface_params::PDSCH_RSPOWER,
sib2->rr_config_common_sib.pdsch_cnfg.rs_power);
mac->set_param(srslte::ue::mac_interface_params::PDSCH_PB,
sib2->rr_config_common_sib.pdsch_cnfg.p_b);
// PUSCH ConfigCommon
phy->set_param(srslte::ue::phy_interface_params::PUSCH_EN_64QAM,
sib2->rr_config_common_sib.pusch_cnfg.enable_64_qam);
phy->set_param(srslte::ue::phy_interface_params::PUSCH_HOPPING_OFFSET,
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset);
phy->set_param(srslte::ue::phy_interface_params::PUSCH_HOPPING_N_SB,
sib2->rr_config_common_sib.pusch_cnfg.n_sb);
phy->set_param(srslte::ue::phy_interface_params::PUSCH_HOPPING_INTRA_SF,
sib2->rr_config_common_sib.pusch_cnfg.hopping_mode == LIBLTE_RRC_HOPPING_MODE_INTRA_AND_INTER_SUBFRAME?1:0);
phy->set_param(srslte::ue::phy_interface_params::DMRS_GROUP_HOPPING_EN,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled?1:0);
phy->set_param(srslte::ue::phy_interface_params::DMRS_SEQUENCE_HOPPING_EN,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled?1:0);
phy->set_param(srslte::ue::phy_interface_params::PUSCH_RS_CYCLIC_SHIFT,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift);
phy->set_param(srslte::ue::phy_interface_params::PUSCH_RS_GROUP_ASSIGNMENT,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch);
printf("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
sib2->rr_config_common_sib.pusch_cnfg.n_sb);
// PUCCH ConfigCommon
phy->set_param(srslte::ue::phy_interface_params::PUCCH_DELTA_SHIFT,
liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift]);
phy->set_param(srslte::ue::phy_interface_params::PUCCH_CYCLIC_SHIFT,
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an);
phy->set_param(srslte::ue::phy_interface_params::PUCCH_N_PUCCH_1,
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an);
phy->set_param(srslte::ue::phy_interface_params::PUCCH_N_RB_2,
sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi);
printf("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an,
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an,
sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi);
// PRACH Configcommon
phy->set_param(srslte::ue::phy_interface_params::PRACH_ROOT_SEQ_IDX,
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index);
phy->set_param(srslte::ue::phy_interface_params::PRACH_HIGH_SPEED_FLAG,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0);
phy->set_param(srslte::ue::phy_interface_params::PRACH_FREQ_OFFSET,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset);
phy->set_param(srslte::ue::phy_interface_params::PRACH_ZC_CONFIG,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config);
phy->set_param(srslte::ue::phy_interface_params::PRACH_CONFIG_INDEX,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
printf("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
// SRS ConfigCommon
if (sib2->rr_config_common_sib.srs_ul_cnfg.present) {
phy->set_param(srslte::ue::phy_interface_params::SRS_CS_BWCFG, sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg);
phy->set_param(srslte::ue::phy_interface_params::SRS_CS_SFCFG, sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg);
phy->set_param(srslte::ue::phy_interface_params::SRS_CS_ACKNACKSIMUL, sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx);
}
printf("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n",
sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg,
sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg,
sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx);
phy->configure_ul_params();
}
void process_connsetup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *msg, srslte::ue::mac *mac, srslte::ue::phy *phy) {
// FIXME: There's an error parsing the connectionSetup message. This value is hard-coded:
if (msg->rr_cnfg.phy_cnfg_ded_present) {
phy->set_param(srslte::ue::phy_interface_params::PUCCH_N_PUCCH_SR,
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_pucch_resource_idx);
phy->set_param(srslte::ue::phy_interface_params::SR_CONFIG_INDEX,
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_cnfg_idx);
phy->set_param(srslte::ue::phy_interface_params::UCI_I_OFFSET_ACK, msg->rr_cnfg.phy_cnfg_ded.pusch_cnfg_ded.beta_offset_ack_idx);
phy->set_param(srslte::ue::phy_interface_params::UCI_I_OFFSET_CQI, msg->rr_cnfg.phy_cnfg_ded.pusch_cnfg_ded.beta_offset_cqi_idx);
phy->set_param(srslte::ue::phy_interface_params::UCI_I_OFFSET_RI, msg->rr_cnfg.phy_cnfg_ded.pusch_cnfg_ded.beta_offset_ri_idx);
if (msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded_present && msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.setup_present) {
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_CS, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.cyclic_shift);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_DURATION, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.duration);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_NRRC, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.freq_domain_pos);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_BW, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_bandwidth);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_CONFIGINDEX, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_cnfg_idx);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_HOP, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_hopping_bandwidth);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_CYCLICSHIFT, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.cyclic_shift);
phy->set_param(srslte::ue::phy_interface_params::SRS_UE_TXCOMB, msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.tx_comb);
phy->set_param(srslte::ue::phy_interface_params::SRS_IS_CONFIGURED, 1);
}
}
printf("Set PHY configuration: SR-n_pucch=%d, SR-ConfigIndex=%d, SRS-ConfigIndex=%d, SRS-bw=%d, SRS-Nrcc=%d, SRS-hop=%d, SRS-Ncs=%d\n",
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_pucch_resource_idx,
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_cnfg_idx,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_cnfg_idx,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_bandwidth,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.freq_domain_pos,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_hopping_bandwidth,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.cyclic_shift);
mac->set_param(srslte::ue::mac_interface_params::HARQ_MAXTX,
liblte_rrc_max_harq_tx_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.max_harq_tx]);
mac->set_param(srslte::ue::mac_interface_params::SR_TRANS_MAX,
liblte_rrc_dsr_trans_max_num[msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.dsr_trans_max]);
mac->set_param(srslte::ue::mac_interface_params::SR_PUCCH_CONFIGURED, 1);
mac->set_param(srslte::ue::mac_interface_params::BSR_TIMER_RETX,
liblte_rrc_retransmission_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.retx_bsr_timer]);
mac->set_param(srslte::ue::mac_interface_params::BSR_TIMER_PERIODIC,
liblte_rrc_periodic_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.periodic_bsr_timer]);
printf("Set MAC configuration: dsr-TransMAX: %d, harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n",
liblte_rrc_dsr_trans_max_num[msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.dsr_trans_max],
liblte_rrc_max_harq_tx_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.max_harq_tx],
liblte_rrc_retransmission_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.retx_bsr_timer],
liblte_rrc_periodic_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.periodic_bsr_timer]);
phy->configure_ul_params();
// Setup radio bearers
for (int i=0;i<msg->rr_cnfg.srb_to_add_mod_list_size;i++) {
if (msg->rr_cnfg.srb_to_add_mod_list[i].lc_default_cnfg_present) {
printf("Setting up Default Configuration for SRB%d \n", msg->rr_cnfg.srb_to_add_mod_list[i].srb_id);
switch(msg->rr_cnfg.srb_to_add_mod_list[i].srb_id) {
case 1:
mac->setup_lcid(1, 0, 1, -1, -1);
break;
case 2:
mac->setup_lcid(2, 0, 3, -1, -1);
break;
}
}
}
// for (int i=0;i<msg->rr_cnfg.drb_to_add_mod_list_size;i++) {
// printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id);
// // todo
// }
}
// Hex bytes for the connection setup complete packet
// Got hex bytes from http://www.sharetechnote.com/html/RACH_LTE.html
uint8_t setupComplete_segm[2][41] ={ {
0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04,
0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0,
0xe5, 0x60, 0x13, 0x81, 0x83},
{0xb0, 0x01, 0x01, 0x01, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80,
0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62,
0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00}
};
uint8_t setupComplete[80] = {
0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04,
0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0,
0xe5, 0x60, 0x13, 0x81, 0x83, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80,
0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62,
0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00};
uint32_t lengths[2] = {37, 41};
uint8_t reply[2] = {0x00, 0x04};
srslte::radio_uhd radio_uhd;
srslte::ue::phy phy;
srslte::ue::mac mac;
srslte::ue::mac_pcap mac_pcap;
prog_args_t prog_args;
void sig_int_handler(int signo)
{
if (prog_args.do_trace) {
//radio_uhd.write_trace("radio");
phy.write_trace("phy");
}
if (prog_args.do_pcap) {
mac_pcap.close();
}
mac.stop();
exit(0);
}
class rlctest : public srslte::ue::rlc_interface_mac {
public:
bool mib_decoded;
bool sib1_decoded;
bool sib2_decoded;
bool connsetup_decoded;
int nsegm_dcch;
int send_ack;
uint8_t si_window_len, sib2_period;
rlctest() {
mib_decoded = false;
sib1_decoded = false;
sib2_decoded = false;
connsetup_decoded = false;
nsegm_dcch = 0;
si_window_len = 0;
sib2_period = 0;
send_ack = 0;
}
uint32_t get_buffer_state(uint32_t lcid) {
if (lcid == 0) {
if (sib2_decoded && !connsetup_decoded) {
return 6;
}
} else if (lcid == 1) {
if (connsetup_decoded && nsegm_dcch < 2) {
return lengths[nsegm_dcch];
} else if (send_ack == 1) {
return 2;
}
}
return 0;
}
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if (lcid == 0) {
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
// Prepare ConnectionRequest packet
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000;
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, &bit_msg);
uint64_t uecri=0;
uint8_t *ue_cri_ptr = (uint8_t*) &uecri;
uint32_t nbytes = bit_msg.N_bits/8;
uint8_t *ptr = bit_msg.msg;
for (int i=0;i<nbytes;i++) {
ue_cri_ptr[nbytes-i-1] = (uint8_t) srslte_bit_unpack(&ptr, 8);
}
mac.set_param(srslte::ue::mac_interface_params::CONTENTION_ID, uecri);
// Send ConnectionRequest Packet
printf("Send ConnectionRequest %d/%d bytes\n", nbytes, nof_bytes);
srslte_bit_unpack_vector(bit_msg.msg, payload, nbytes*8);
bzero(&payload[nbytes], (nof_bytes-nbytes)*sizeof(uint8_t));
return nof_bytes;
} else if (lcid == 1) {
if (nsegm_dcch < 2) {
if (nof_bytes >= 80) {
printf("Sending Connection Setup Complete length 80\n");
memcpy(payload, setupComplete, 80);
return 80;
} else {
uint32_t r = 0;
if (nof_bytes >= lengths[nsegm_dcch]) {
printf("Sending Connection Setup Complete %d/2 length %d\n", nsegm_dcch, lengths[nsegm_dcch]);
memcpy(payload, setupComplete_segm[nsegm_dcch], lengths[nsegm_dcch]);
r = lengths[nsegm_dcch];
nsegm_dcch++;
} else {
r = 0;
}
return r;
}
} else if (send_ack == 1) {
printf("Send RLC ACK\n");
memcpy(payload, reply, 2*sizeof(uint8_t));
send_ack = 2;
return 2;
}
}
return 0;
}
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) {
if (lcid == 0) {
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
printf("ConnSetup received %d bytes\n", nof_bytes);
srslte_vec_fprint_byte(stdout, payload, nof_bytes);
srslte_bit_pack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_dl_ccch_msg(&bit_msg, &dl_ccch_msg);
printf("Response: %s\n", liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]);
switch (dl_ccch_msg.msg_type) {
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP:
// Process ConnectionSetup
process_connsetup(&dl_ccch_msg.msg.rrc_con_setup, &mac, &phy);
connsetup_decoded = true;
break;
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ:
mac.set_param(srslte::ue::mac_interface_params::RNTI_C, 0);
break;
}
} else if (lcid == 1) {
printf("Received on DCCH0 %d bytes\n", nof_bytes);
if (send_ack == 0) {
send_ack = 1;
}
}
}
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes)
{
LIBLTE_RRC_MIB_STRUCT mib;
srslte_vec_fprint_byte(stdout, payload, nof_bytes);
srslte_bit_pack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_bcch_bch_msg(&bit_msg, &mib);
printf("MIB received %d bytes, BW=%s MHz\n", nof_bytes, liblte_rrc_dl_bandwidth_text[mib.dl_bw]);
mib_decoded = true;
}
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
{
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
srslte_bit_pack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_bcch_dlsch_msg(&bit_msg, &dlsch_msg);
if (dlsch_msg.N_sibs > 0) {
if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 && !sib1_decoded) {
si_window_len = liblte_rrc_si_window_length_num[dlsch_msg.sibs[0].sib.sib1.si_window_length];
sib2_period = liblte_rrc_si_periodicity_num[dlsch_msg.sibs[0].sib.sib1.sched_info[0].si_periodicity];
printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n",
nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
sib1_decoded = true;
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_ST, -1);
} else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) {
printf("SIB2 received %d bytes\n", nof_bytes);
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
sib2_decoded = true;
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_ST, -1);
}
}
}
private:
LIBLTE_BIT_MSG_STRUCT bit_msg;
LIBLTE_BYTE_MSG_STRUCT byte_msg;
};
int main(int argc, char *argv[])
{
srslte::log_stdout mac_log("MAC"), phy_log("PHY");
rlctest my_rlc;
parse_args(&prog_args, argc, argv);
switch (prog_args.verbose) {
case 1:
mac_log.set_level_info();
phy_log.set_level_info();
break;
case 2:
mac_log.set_level_debug();
phy_log.set_level_debug();
break;
}
// Capture SIGINT to write traces
if (prog_args.do_trace) {
signal(SIGINT, sig_int_handler);
//radio_uhd.start_trace();
phy.start_trace();
}
if (prog_args.do_pcap) {
if (!prog_args.do_trace) {
signal(SIGINT, sig_int_handler);
}
mac_pcap.open("/tmp/ue_mac.pcap");
mac.start_pcap(&mac_pcap);
}
// Init Radio and PHY
if (prog_args.uhd_rx_gain > 0 && prog_args.uhd_tx_gain > 0) {
radio_uhd.init();
radio_uhd.set_rx_gain(prog_args.uhd_rx_gain);
radio_uhd.set_tx_gain(prog_args.uhd_tx_gain);
phy.init(&radio_uhd, &mac, &phy_log);
} else {
radio_uhd.init_agc();
radio_uhd.set_tx_rx_gain_offset(10);
phy.init_agc(&radio_uhd, &mac, &phy_log);
}
// Init MAC
mac.init(&phy, &my_rlc, &mac_log);
// Set RX freq
radio_uhd.set_rx_freq(prog_args.uhd_rx_freq);
radio_uhd.set_tx_freq(prog_args.uhd_tx_freq);
while(1) {
uint32_t tti;
if (my_rlc.mib_decoded && mac.get_current_tti()) {
if (!my_rlc.sib1_decoded) {
usleep(10000);
tti = mac.get_current_tti();
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_ST, sib_start_tti(tti, 2, 5));
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_LEN, 1);
} else if (!my_rlc.sib2_decoded) {
usleep(10000);
tti = mac.get_current_tti();
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_ST, sib_start_tti(tti, my_rlc.sib2_period, 0));
mac.set_param(srslte::ue::mac_interface_params::BCCH_SI_WINDOW_LEN, my_rlc.si_window_len);
}
}
usleep(50000);
}
}

@ -1,37 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
INSTALL(DIRECTORY include/
DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
FILE(GLOB SOURCES "src/*.cc")
ADD_LIBRARY(srsapps_ue_phy SHARED ${SOURCES})
INSTALL(TARGETS srsapps_ue_phy DESTINATION ${LIBRARY_DIR})
SRSLTE_SET_PIC(srsapps_ue_phy)
FILE(GLOB HEADERS_ALL "include/srsapps/ue/phy/*.h")
ADD_CUSTOM_TARGET (add_ue_phy_headers SOURCES ${HEADERS_ALL})
ADD_SUBDIRECTORY(test)

@ -1,114 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <pthread.h>
#include <string.h>
#include <vector>
#include "srslte/srslte.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/radio/radio.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phy_params.h"
#ifndef UEPHYWORKERCOMMON_H
#define UEPHYWORKERCOMMON_H
namespace srslte {
namespace ue {
/* Subclass that manages variables common to all workers */
class phch_common {
public:
/* Common variables used by all phy workers */
phy_params *params_db;
log *log_h;
mac_interface_phy *mac;
phch_common(uint32_t nof_workers);
void init(phy_params *_params, log *_log, radio *_radio, mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool sr_enabled;
int sr_last_tx_tti;
private:
std::vector<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
radio *radio_h;
float cfo;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[10];
bool is_first_tx;
uint32_t nof_workers;
};
}
}
#endif

@ -1,105 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/common/log.h"
#include "srsapps/common/threads.h"
#include "srsapps/common/thread_pool.h"
#include "srsapps/radio/radio.h"
#include "srsapps/ue/phy/prach.h"
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/ue/phy/phch_common.h"
#ifndef UEPHYRECV_H
#define UEPHYRECV_H
namespace srslte {
namespace ue {
typedef _Complex float cf_t;
class phch_recv : public thread
{
public:
phch_recv();
bool init(radio* radio_handler, mac_interface_phy *mac, prach *prach_buffer, thread_pool *_workers_pool,
phch_common *_worker_com, log* _log_h, bool do_agc = false, uint32_t prio = 1);
void stop();
uint32_t get_current_tti();
void sync_start();
void sync_stop();
bool status_is_sync();
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t *cell);
private:
void run_thread();
int sync_sfn();
bool running;
radio *radio_h;
mac_interface_phy *mac;
log *log_h;
thread_pool *workers_pool;
phch_common *worker_com;
prach *prach_buffer;
srslte_ue_sync_t ue_sync;
srslte_ue_mib_t ue_mib;
enum {
IDLE, CELL_SEARCH, SYNCING, SYNC_DONE
} phy_state;
srslte_cell_t cell;
bool cell_is_set;
bool is_sfn_synched;
bool started;
float time_adv_sec;
bool radio_is_streaming;
uint32_t tti;
bool do_agc;
float last_gain;
float cellsearch_cfo;
bool cell_search(int force_N_id_2 = -1);
bool init_cell();
void free_cell();
};
}
}
#endif

@ -1,136 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <string.h>
#include "srslte/srslte.h"
#include "srsapps/common/thread_pool.h"
#include "srsapps/common/phy_interface.h"
#include "srsapps/common/trace.h"
#include "srsapps/ue/phy/phch_common.h"
#ifndef UEPHYWORKER_H
#define UEPHYWORKER_H
namespace srslte {
namespace ue {
class phch_worker : public thread_pool::worker
{
public:
phch_worker();
void set_common(phch_common *phy);
bool init_cell(srslte_cell_t cell);
void free_cell();
/* Functions used by main PHY thread */
cf_t *get_buffer();
void set_tti(uint32_t tti);
void set_tx_time(srslte_timestamp_t tx_time);
void set_cfo(float cfo);
void set_ul_params();
void reset_ul_params();
void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled);
void start_trace();
void write_trace(std::string filename);
private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
void work_imp();
/* Internal methods */
bool extract_fft_and_pdcch_llr();
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
bool decode_phich(bool *ack);
bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, uint32_t rv, uint16_t rnti);
/* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, uint32_t rv, uint16_t rnti);
void encode_pucch();
void encode_srs();
void reset_uci();
void set_uci_sr();
void set_uci_cqi();
void set_uci_ack(bool ack);
bool srs_is_ready_to_send();
void normalize();
void tr_log_start();
void tr_log_end();
struct timeval tr_time[3];
trace<uint32_t> tr_exec;
bool trace_enabled;
/* Common objects */
phch_common *phy;
srslte_cell_t cell;
bool cell_initiated;
cf_t *signal_buffer;
uint32_t tti;
bool pregen_enabled;
uint32_t last_dl_pdcch_ncce;
/* Objects for DL */
srslte_ue_dl_t ue_dl;
uint32_t cfi;
uint16_t dl_rnti;
/* Objects for UL */
srslte_ue_ul_t ue_ul;
srslte_timestamp_t tx_time;
srslte_uci_data_t uci_data;
uint16_t ul_rnti;
// UL configuration parameters
srslte_refsignal_srs_cfg_t srs_cfg;
srslte_pucch_cfg_t pucch_cfg;
srslte_refsignal_dmrs_pusch_cfg_t dmrs_cfg;
srslte_pusch_hopping_cfg_t pusch_hopping;
srslte_pucch_sched_t pucch_sched;
srslte_uci_cfg_t uci_cfg;
srslte_cqi_cfg_t cqi_cfg;
uint32_t I_sr;
float cfo;
bool rar_cqi_request;
};
}
}
#endif

@ -1,138 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/common/phy_interface.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phch_recv.h"
#include "srsapps/ue/phy/prach.h"
#include "srsapps/ue/phy/phy_params.h"
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/ue/phy/phch_common.h"
#include "srsapps/radio/radio.h"
#include "srsapps/common/task_dispatcher.h"
#include "srsapps/common/trace.h"
#include "srsapps/common/mac_interface.h"
#ifndef UEPHY_H
#define UEPHY_H
namespace srslte {
namespace ue {
typedef _Complex float cf_t;
class phy : public phy_interface, phy_interface_params
{
public:
phy();
bool init(radio *radio_handler, mac_interface_phy *mac, log *log_h);
bool init_agc(radio *radio_handler, mac_interface_phy *mac, log *log_h);
void stop();
void set_crnti(uint16_t rnti);
// Get status
bool status_is_sync();
static uint32_t tti_to_SFN(uint32_t tti);
static uint32_t tti_to_subf(uint32_t tti);
void enable_pregen_signals(bool enable);
void start_trace();
void write_trace(std::string filename);
/********** MAC INTERFACE ********************/
/* Instructs the PHY to configure using the parameters written by set_param() */
void configure_prach_params();
void configure_ul_params();
/* Functions to synchronize with a cell */
void sync_start();
void sync_stop();
/* Transmits PRACH in the next opportunity */
void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0);
int prach_tx_tti();
/* Indicates the transmission of a SR signal in the next opportunity */
void sr_send();
int sr_last_tx_tti();
// Time advance commands
void set_timeadv_rar(uint32_t ta_cmd);
void set_timeadv(uint32_t ta_cmd);
/* Sets RAR grant payload */
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_ul_search_reset();
void pdcch_dl_search_reset();
/* Get/Set PHY parameters */
void set_param(phy_param_t param, int64_t value);
int64_t get_param(phy_param_t param);
void reset();
uint32_t get_current_tti();
void get_current_cell(srslte_cell_t *cell);
private:
const static int NOF_WORKERS = 2;
const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 0;
radio *radio_handler;
log *log_h;
thread_pool workers_pool;
std::vector<phch_worker> workers;
phch_common workers_common;
phch_recv sf_recv;
prach prach_buffer;
phy_params params_db;
/* Current time advance */
uint32_t n_ta;
bool init_(radio *radio_handler, mac_interface_phy *mac, log *log_h, bool do_agc);
};
}
}
#endif

@ -1,53 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/common/params_db.h"
#include "srsapps/common/phy_interface.h"
#ifndef PHYPARAMS_H
#define PHYPARAMS_H
namespace srslte {
namespace ue {
class phy_params : public params_db
{
public:
phy_params() : params_db(phy_interface_params::NOF_PARAMS) { }
~phy_params() {}
};
}
}
#endif

@ -1,77 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 "srslte/srslte.h"
#include "srsapps/radio/radio.h"
#include "srsapps/common/log.h"
#include "srsapps/common/phy_interface.h"
#include "srsapps/ue/phy/phy_params.h"
#ifndef UEPRACH_H
#define UEPRACH_H
namespace srslte {
namespace ue {
class prach {
public:
prach() {
params_db = NULL;
initiated = false;
signal_buffer = NULL;
}
void init(phy_params *params_db, log *log_h);
bool init_cell(srslte_cell_t cell);
void free_cell();
bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1);
bool is_ready_to_send(uint32_t current_tti);
int tx_tti();
bool send(radio* radio_handler, float cfo, srslte_timestamp_t rx_time);
private:
static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission
phy_params *params_db;
log *log_h;
int preamble_idx;
int allowed_subframe;
bool initiated;
uint32_t len;
cf_t *buffer[64];
srslte_prach_t prach_obj;
int transmitted_tti;
srslte_cell_t cell;
cf_t *signal_buffer;
srslte_cfo_t cfo_h;
};
}
}
#endif

@ -1,202 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <string.h>
#include "srslte/srslte.h"
#include "srsapps/ue/phy/phch_common.h"
namespace srslte {
namespace ue {
phch_common::phch_common(uint32_t nof_workers_) : tx_mutex(nof_workers_)
{
params_db = NULL;
log_h = NULL;
radio_h = NULL;
mac = NULL;
nof_workers = nof_workers_;
sr_enabled = false;
is_first_of_burst = true;
is_first_tx = true;
rar_grant_pending = false;
sr_last_tx_tti = -1;
}
void phch_common::init(phy_params *_params, log *_log, radio *_radio, mac_interface_phy *_mac)
{
params_db = _params;
log_h = _log;
radio_h = _radio;
mac = _mac;
is_first_tx = true;
sr_last_tx_tti = -1;
for (int i=0;i<nof_workers;i++) {
pthread_mutex_init(&tx_mutex[i], NULL);
}
}
bool phch_common::ul_rnti_active(uint32_t tti) {
if ((tti >= ul_rnti_start && ul_rnti_start >= 0 || ul_rnti_start < 0) &&
(tti < ul_rnti_end && ul_rnti_end >= 0 || ul_rnti_end < 0))
{
return true;
} else {
return false;
}
}
bool phch_common::dl_rnti_active(uint32_t tti) {
if (((tti >= dl_rnti_start && dl_rnti_start >= 0) || dl_rnti_start < 0) &&
((tti < dl_rnti_end && dl_rnti_end >= 0) || dl_rnti_end < 0))
{
return true;
} else {
return false;
}
}
// Unpack RAR grant as defined in Section 6.2 of 36.213
void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{
srslte_dci_rar_grant_unpack(&rar_grant, grant_payload);
rar_grant_pending = true;
// PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis
if (rar_grant.ul_delay) {
rar_grant_tti = (tti + 3) % 10240;
} else {
rar_grant_tti = (tti + 2) % 10240;
}
}
bool phch_common::get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant_)
{
if (rar_grant_pending && (tti >= rar_grant_tti || (tti < 10 && rar_grant_pending > 10235))) {
if (rar_grant_) {
rar_grant_pending = false;
memcpy(rar_grant_, &rar_grant, sizeof(srslte_dci_rar_grant_t));
}
return true;
}
return false;
}
/* Common variables used by all phy workers */
uint16_t phch_common::get_ul_rnti(uint32_t tti) {
if (ul_rnti_active(tti)) {
return ul_rnti;
} else {
return 0;
}
}
srslte_rnti_type_t phch_common::get_ul_rnti_type() {
return ul_rnti_type;
}
void phch_common::set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
ul_rnti = rnti_value;
ul_rnti_type = type;
ul_rnti_start = tti_start;
ul_rnti_end = tti_end;
}
uint16_t phch_common::get_dl_rnti(uint32_t tti) {
if (dl_rnti_active(tti)) {
return dl_rnti;
} else {
return 0;
}
}
srslte_rnti_type_t phch_common::get_dl_rnti_type() {
return dl_rnti_type;
}
void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
dl_rnti = rnti_value;
dl_rnti_type = type;
dl_rnti_start = tti_start;
dl_rnti_end = tti_end;
if (rnti_value) {
Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value);
}
}
void phch_common::reset_pending_ack(uint32_t tti) {
pending_ack[tti%10].enabled = false;
}
void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) {
pending_ack[tti%10].enabled = true;
pending_ack[tti%10].I_lowest = I_lowest;
pending_ack[tti%10].n_dmrs = n_dmrs;
Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs);
}
bool phch_common::get_pending_ack(uint32_t tti) {
return get_pending_ack(tti, NULL, NULL);
}
bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) {
if (I_lowest) {
*I_lowest = pending_ack[tti%10].I_lowest;
}
if (n_dmrs) {
*n_dmrs = pending_ack[tti%10].n_dmrs;
}
return pending_ack[tti%10].enabled;
}
/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate
* that all processing is done and data is ready for transmission or there is no transmission at all (tx_enable).
* In that case, the end of burst message will be send to the radio
*/
void phch_common::worker_end(uint32_t tti, bool tx_enable,
cf_t *buffer, uint32_t nof_samples,
srslte_timestamp_t tx_time)
{
// Wait previous TTIs to be transmitted
if (is_first_tx) {
is_first_tx = false;
} else {
pthread_mutex_lock(&tx_mutex[tti%nof_workers]);
}
radio_h->set_tti(tti);
if (tx_enable) {
radio_h->tx(buffer, nof_samples, tx_time);
is_first_of_burst = false;
} else if (!is_first_of_burst) {
radio_h->tx_end();
is_first_of_burst = true;
}
// Trigger next transmission
pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_workers]);
}
}
}

@ -1,371 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <unistd.h>
#include "srslte/srslte.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/ue/phy/phch_common.h"
#include "srsapps/ue/phy/phch_recv.h"
namespace srslte {
namespace ue {
phch_recv::phch_recv() {
running = false;
}
bool phch_recv::init(radio* _radio_handler, mac_interface_phy *_mac, prach* _prach_buffer, thread_pool* _workers_pool,
phch_common* _worker_com, log* _log_h, bool do_agc_, uint32_t prio)
{
radio_h = _radio_handler;
log_h = _log_h;
mac = _mac;
workers_pool = _workers_pool;
worker_com = _worker_com;
prach_buffer = _prach_buffer;
running = true;
phy_state = IDLE;
time_adv_sec = 0;
cell_is_set = false;
do_agc = do_agc_;
start(prio);
}
void phch_recv::stop() {
running = false;
wait_thread_finish();
}
int radio_recv_wrapper_cs(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *rx_time)
{
radio *radio_h = (radio*) h;
if (radio_h->rx_now(data, nsamples, rx_time)) {
return nsamples;
} else {
return -1;
}
}
double callback_set_rx_gain(void *h, double gain) {
radio *radio_handler = (radio*) h;
return radio_handler->set_rx_gain_th(gain);
}
void phch_recv::set_time_adv_sec(float _time_adv_sec) {
time_adv_sec = _time_adv_sec;
}
bool phch_recv::init_cell() {
cell_is_set = false;
if (!srslte_ue_mib_init(&ue_mib, cell))
{
if (!srslte_ue_sync_init(&ue_sync, cell, radio_recv_wrapper_cs, radio_h))
{
for (int i=0;i<workers_pool->get_nof_workers();i++) {
if (!((phch_worker*) workers_pool->get_worker(i))->init_cell(cell)) {
Error("Error setting cell: initiating PHCH worker\n");
return false;
}
}
if (do_agc) {
srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo);
cell_is_set = true;
} else {
Error("Error setting cell: initiating ue_sync");
}
} else {
Error("Error setting cell: initiating ue_mib\n");
}
return cell_is_set;
}
void phch_recv::free_cell()
{
if (cell_is_set) {
for (int i=0;i<workers_pool->get_nof_workers();i++) {
((phch_worker*) workers_pool->get_worker(i))->free_cell();
}
prach_buffer->free_cell();
}
}
bool phch_recv::cell_search(int force_N_id_2)
{
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN/8];
srslte_ue_cellsearch_result_t found_cells[3];
srslte_ue_cellsearch_t cs;
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, radio_recv_wrapper_cs, radio_h)) {
Error("Initiating UE cell search\n");
return false;
}
if (do_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs,
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_NFRAMES));
srslte_ue_cellsearch_set_threshold(&cs, (float)
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_CORRELATION_THRESHOLD)/10);
radio_h->set_rx_srate(1920000.0);
radio_h->start_rx();
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
int ret = SRSLTE_ERROR;
if (force_N_id_2 >= 0 && force_N_id_2 < 3) {
ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
last_gain = srslte_agc_get_gain(&cs.ue_sync.agc);
radio_h->stop_rx();
srslte_ue_cellsearch_free(&cs);
if (ret < 0) {
Error("Error decoding MIB: Error searching PSS\n");
return false;
} else if (ret == 0) {
Error("Error decoding MIB: Could not find any PSS in this frequency\n");
return false;
}
// Save result
cell.id = found_cells[max_peak_cell].cell_id;
cell.cp = found_cells[max_peak_cell].cp;
cellsearch_cfo = found_cells[max_peak_cell].cfo;
Info("\nFound CELL ID: %d CP: %s, CFO: %f\n", cell.id, srslte_cp_string(cell.cp), cellsearch_cfo);
srslte_ue_mib_sync_t ue_mib_sync;
if (srslte_ue_mib_sync_init(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, radio_h)) {
Error("Initiating UE MIB synchronization\n");
return false;
}
if (do_agc) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain);
}
/* Find and decode MIB */
uint32_t sfn, sfn_offset;
radio_h->start_rx();
ret = srslte_ue_mib_sync_decode(&ue_mib_sync,
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_MIB_NFRAMES),
bch_payload, &cell.nof_ports, &sfn_offset);
radio_h->stop_rx();
last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc);
srslte_ue_mib_sync_free(&ue_mib_sync);
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, NULL);
srslte_cell_fprint(stdout, &cell, 0);
//FIXME: this is temporal
srslte_bit_unpack_vector(bch_payload, bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN);
mac->bch_decoded_ok(bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN/8);
return true;
} else {
Warning("Error decoding MIB: Error decoding PBCH\n");
return false;
}
}
int phch_recv::sync_sfn(void) {
cf_t *sf_buffer = NULL;
int ret = SRSLTE_ERROR;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
Error("Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
uint32_t sfn_offset=0;
srslte_pbch_decode_reset(&ue_mib.pbch);
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
if (n < 0) {
Error("Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
tti = sfn*10 + srslte_ue_sync_get_sfidx(&ue_sync);
srslte_ue_sync_decode_sss_on_track(&ue_sync, false);
return 1;
}
}
}
return 0;
}
void phch_recv::run_thread()
{
phch_worker *worker = NULL;
cf_t *buffer = NULL;
while(running) {
switch(phy_state) {
case CELL_SEARCH:
if (cell_search()) {
init_cell();
radio_h->set_rx_srate((float) srslte_sampling_freq_hz(cell.nof_prb));
radio_h->set_tx_srate((float) srslte_sampling_freq_hz(cell.nof_prb));
Info("Cell found. Synchronizing...\n");
phy_state = SYNCING;
} else {
phy_state = IDLE;
}
break;
case SYNCING:
if (!radio_is_streaming) {
// Start streaming
radio_h->start_rx();
radio_is_streaming = true;
}
switch(sync_sfn()) {
default:
phy_state = IDLE;
break;
case 1:
Info("Synchronized.\n");
phy_state = SYNC_DONE;
break;
case 0:
break;
}
break;
case SYNC_DONE:
tti = (tti + 1) % 10240;
worker = (phch_worker*) workers_pool->wait_worker(tti);
if (worker) {
buffer = worker->get_buffer();
if (srslte_ue_sync_zerocopy(&ue_sync, buffer) == 1) {
log_h->step(tti);
Debug("Worker %d synchronized\n", worker->get_id());
float cfo = srslte_ue_sync_get_cfo(&ue_sync)/15000;
worker->set_cfo(cfo);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_copy(&tx_time_prach, &rx_time);
srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec);
srslte_timestamp_add(&tx_time_prach, 0, 4e-3);
worker->set_tx_time(tx_time);
Debug("Settting TTI=%d to worker %d\n", tti, worker->get_id());
worker->set_tti(tti);
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_t cur_time;
radio_h->get_time(&cur_time);
Info("TX PRACH now. RX time: %d:%f, Now: %d:%f\n", rx_time.full_secs, rx_time.frac_secs,
cur_time.full_secs, cur_time.frac_secs);
// send prach if we have to
prach_buffer->send(radio_h, cfo, tx_time_prach);
radio_h->tx_end();
}
workers_pool->start_worker(worker);
mac->tti_clock(tti);
} else {
worker->release();
}
} else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
running = false;
}
break;
case IDLE:
usleep(1000);
break;
}
}
}
uint32_t phch_recv::get_current_tti()
{
return tti;
}
bool phch_recv::status_is_sync()
{
return phy_state == SYNC_DONE;
}
void phch_recv::get_current_cell(srslte_cell_t* cell_)
{
if (cell_) {
memcpy(cell_, &cell, sizeof(srslte_cell_t));
}
}
void phch_recv::sync_start()
{
phy_state = CELL_SEARCH;
}
void phch_recv::sync_stop()
{
free_cell();
radio_h->stop_rx();
radio_is_streaming = false;
phy_state = IDLE;
}
}
}

@ -1,640 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <string.h>
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/common/phy_interface.h"
namespace srslte {
namespace ue {
#define log_h phy->log_h
phch_worker::phch_worker() : tr_exec(10240)
{
phy = NULL;
signal_buffer = NULL;
cell_initiated = false;
pregen_enabled = false;
rar_cqi_request = false;
trace_enabled = false;
cfi = 0;
reset_ul_params();
}
void phch_worker::set_common(phch_common* phy_)
{
phy = phy_;
}
bool phch_worker::init_cell(srslte_cell_t cell_)
{
memcpy(&cell, &cell_, sizeof(srslte_cell_t));
// ue_sync in phy.cc requires a buffer for 2 subframes
signal_buffer = (cf_t*) srslte_vec_malloc(2 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (!signal_buffer) {
Error("Allocating memory\n");
return false;
}
if (srslte_ue_dl_init(&ue_dl, cell)) {
Error("Initiating UE DL\n");
return false;
}
if (srslte_ue_ul_init(&ue_ul, cell)) {
Error("Initiating UE UL\n");
return false;
}
srslte_ue_ul_set_normalization(&ue_ul, false);
srslte_ue_ul_set_cfo_enable(&ue_ul, true);
cell_initiated = true;
return true;
}
void phch_worker::free_cell()
{
if (cell_initiated) {
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_dl_free(&ue_dl);
srslte_ue_ul_free(&ue_ul);
}
}
cf_t* phch_worker::get_buffer()
{
return signal_buffer;
}
void phch_worker::set_tti(uint32_t tti_)
{
tti = tti_;
}
void phch_worker::set_cfo(float cfo_)
{
cfo = cfo_;
}
void phch_worker::set_crnti(uint16_t rnti)
{
srslte_ue_dl_set_rnti(&ue_dl, rnti);
srslte_ue_ul_set_rnti(&ue_ul, rnti);
}
void phch_worker::work_imp()
{
if (!cell_initiated) {
return;
}
Debug("TTI %d running\n", tti);
tr_log_start();
reset_uci();
bool ul_grant_available = false;
bool dl_ack = false;
mac_interface_phy::mac_grant_t dl_mac_grant;
mac_interface_phy::tb_action_dl_t dl_action;
bzero(&dl_action, sizeof(mac_interface_phy::tb_action_dl_t));
mac_interface_phy::mac_grant_t ul_mac_grant;
mac_interface_phy::tb_action_ul_t ul_action;
bzero(&ul_action, sizeof(mac_interface_phy::tb_action_ul_t));
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
if (extract_fft_and_pdcch_llr()) {
/***** Downlink Processing *******/
/* PDCCH DL + PDSCH */
if(decode_pdcch_dl(&dl_mac_grant)) {
/* Send grant to MAC and get action for this TB */
phy->mac->new_grant_dl(dl_mac_grant, &dl_action);
/* Decode PDSCH if instructed to do so */
dl_ack = dl_action.default_ack;
if (dl_action.decode_enabled) {
dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr,
dl_action.softbuffer, dl_action.rv, dl_action.rnti);
}
if (dl_action.generate_ack_callback && dl_action.decode_enabled) {
phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid);
dl_ack = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg);
Info("Calling generate ACK callback returned=%d\n", dl_ack);
}
if (dl_action.generate_ack) {
set_uci_ack(dl_ack);
}
}
// Decode PHICH
bool ul_ack;
bool ul_ack_available = decode_phich(&ul_ack);
/***** Uplink Processing + Transmission *******/
/* Generate UCI */
set_uci_sr();
set_uci_cqi();
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
/* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) {
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
} else if (ul_grant_available && !ul_ack_available) {
phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
} else if (!ul_grant_available && ul_ack_available) {
phy->mac->harq_recv(tti, ul_ack, &ul_action);
}
/* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, cfo);
}
/* Transmit PUSCH, PUCCH or SRS */
bool tx_signal = false;
if (ul_action.tx_enabled) {
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr, ul_action.current_tx_nb,
ul_action.softbuffer, ul_action.rv, ul_action.rnti);
tx_signal = true;
if (ul_action.expect_ack) {
phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
}
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) {
encode_pucch();
tx_signal = true;
} else if (srs_is_ready_to_send()) {
encode_srs();
tx_signal = true;
}
tr_log_end();
phy->worker_end(tti, tx_signal, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb), tx_time);
if (dl_action.decode_enabled && !dl_action.generate_ack_callback) {
phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid);
}
}
bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = false;
if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti) || phy->get_pending_rar(tti)) {
decode_pdcch = true;
}
/* Without a grant, we might need to do fft processing if need to decode PHICH */
if (phy->get_pending_ack(tti) || decode_pdcch) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
}
if (decode_pdcch) { /* and not in DRX mode */
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
Error("Extracting PDCCH LLR\n");
return false;
}
}
return (decode_pdcch || phy->get_pending_ack(tti));
}
/********************* Downlink processing functions ****************************/
bool phch_worker::decode_pdcch_dl(srslte::ue::mac_interface_phy::mac_grant_t* grant)
{
dl_rnti = phy->get_dl_rnti(tti);
if (dl_rnti) {
srslte_rnti_type_t type = phy->get_dl_rnti_type();
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, &dci_msg, cfi, tti%10, dl_rnti, type) != 1) {
return false;
}
if (srslte_dci_msg_to_dl_grant(&dci_msg, dl_rnti, cell.nof_prb, &dci_unpacked, &grant->phy_grant.dl)) {
Error("Converting DCI message to DL grant\n");
return false;
}
/* Fill MAC grant structure */
grant->ndi = dci_unpacked.ndi;
grant->pid = dci_unpacked.harq_process;
grant->n_bytes = grant->phy_grant.dl.mcs.tbs/8;
grant->tti = tti;
grant->rv = dci_unpacked.rv_idx;
grant->rnti = dl_rnti;
grant->rnti_type = type;
last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl);
Info("PDCCH: DL DCI %s cce_index=%d, n_data_bits=%d\n", srslte_ra_dl_dci_string(&dci_unpacked),
ue_dl.last_n_cce, dci_msg.nof_bits);
return true;
} else {
return false;
}
}
bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
srslte_softbuffer_rx_t* softbuffer, uint32_t rv, uint16_t rnti)
{
Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti);
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rnti, rv)) {
if (ue_dl.pdsch_cfg.grant.mcs.mod > 0 && ue_dl.pdsch_cfg.grant.mcs.tbs >= 0) {
if (srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols,
ue_dl.ce, 0, rnti, payload) == 0)
{
Debug("TB decoded OK\n");
return true;
} else {
Debug("TB decoded KO\n");
return false;
}
} else {
Warning("Received grant for TBS=0\n");
}
} else {
Error("Error configuring DL grant\n");
}
return true;
}
bool phch_worker::decode_phich(bool *ack)
{
uint32_t I_lowest, n_dmrs;
if (phy->get_pending_ack(tti, &I_lowest, &n_dmrs)) {
if (ack) {
Debug("Decoding PHICH I_lowest=%d, n_dmrs=%d\n", I_lowest, n_dmrs);
*ack = srslte_ue_dl_decode_phich(&ue_dl, tti%10, I_lowest, n_dmrs);
}
phy->reset_pending_ack(tti);
return true;
} else {
return false;
}
}
/********************* Uplink processing functions ****************************/
bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
{
phy->reset_pending_ack(tti + 8);
srslte_dci_msg_t dci_msg;
srslte_ra_ul_dci_t dci_unpacked;
srslte_dci_rar_grant_t rar_grant;
srslte_rnti_type_t type = phy->get_ul_rnti_type();
bool ret = false;
if (phy->get_pending_rar(tti, &rar_grant)) {
Info("Pending RAR UL grant\n");
if (srslte_dci_rar_to_ul_grant(&rar_grant, cell.nof_prb, pusch_hopping.hopping_offset,
&dci_unpacked, &grant->phy_grant.ul))
{
Error("Converting RAR message to UL grant\n");
return false;
}
grant->rnti_type = SRSLTE_RNTI_TEMP;
grant->is_from_rar = true;
Info("RAR grant found for TTI=%d\n", tti);
rar_cqi_request = rar_grant.cqi_request;
ret = true;
} else {
ul_rnti = phy->get_ul_rnti(tti);
if (ul_rnti) {
if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, ul_rnti) != 1) {
return false;
}
if (srslte_dci_msg_to_ul_grant(&dci_msg, cell.nof_prb, pusch_hopping.hopping_offset,
&dci_unpacked, &grant->phy_grant.ul))
{
Error("Converting DCI message to UL grant\n");
return false;
}
grant->rnti_type = type;
grant->is_from_rar = false;
ret = true;
Info("PDCCH: UL DCI Format0 cce_index=%d, n_data_bits=%d\n", ue_dl.last_n_cce, dci_msg.nof_bits);
}
}
if (ret) {
grant->ndi = dci_unpacked.ndi;
grant->pid = 0; // This is computed by MAC from TTI
grant->n_bytes = grant->phy_grant.ul.mcs.tbs/8;
grant->tti = tti;
grant->rnti = ul_rnti;
if (SRSLTE_VERBOSE_ISINFO()) {
srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb);
}
return true;
} else {
return false;
}
}
void phch_worker::reset_uci()
{
bzero(&uci_data, sizeof(srslte_uci_data_t));
}
void phch_worker::set_uci_ack(bool ack)
{
uci_data.uci_ack = ack?1:0;
uci_data.uci_ack_len = 1;
}
void phch_worker::set_uci_sr()
{
uci_data.scheduling_request = false;
if (phy->sr_enabled) {
// Get I_sr parameter
if (srslte_ue_ul_sr_send_tti(I_sr, tti+4)) {
Info("SR transmission at TTI=%d\n", tti+4);
uci_data.scheduling_request = true;
phy->sr_last_tx_tti = tti+4;
phy->sr_enabled = false;
}
}
}
void phch_worker::set_uci_cqi()
{
if (cqi_cfg.configured || rar_cqi_request) {
if (srslte_cqi_send(cqi_cfg.pmi_idx, tti+4)) {
uci_data.uci_cqi_len = 4;
uint8_t cqi[4] = {1, 1, 1, 1};
uci_data.uci_cqi = cqi;
rar_cqi_request = false;
}
}
}
bool phch_worker::srs_is_ready_to_send() {
if (srs_cfg.configured) {
if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, (tti+4)%10) == 1 &&
srslte_refsignal_srs_send_ue(srs_cfg.I_srs, tti+4) == 1)
{
return true;
}
}
return false;
}
void phch_worker::set_tx_time(srslte_timestamp_t _tx_time)
{
memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t));
}
void phch_worker::normalize() {
srslte_vec_norm_cfc(signal_buffer, 0.8, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb,
srslte_softbuffer_tx_t* softbuffer, uint32_t rv, uint16_t rnti)
{
if (srslte_ue_ul_cfg_grant(&ue_ul, grant, tti+4, rv, current_tx_nb)) {
Error("Configuring UL grant\n");
}
if (srslte_ue_ul_pusch_encode_rnti_softbuffer(&ue_ul,
payload, uci_data,
softbuffer,
rnti,
signal_buffer))
{
Error("Encoding PUSCH\n");
}
Info("PUSCH: TTI=%d, CFO= %.1f KHz TBS=%d, mod=%s, rb_start=%d n_prb=%d, ack=%s, sr=%s, rnti=%d, shortened=%s\n",
tti+4, cfo*15e3, grant->mcs.tbs, srslte_mod_string(grant->mcs.mod),
grant->n_prb[0], grant->L_prb,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no",
rnti, ue_ul.pusch.shortened?"yes":"no");
normalize();
/*
char filename[128];
sprintf(filename, "pusch%d",tti+4);
srslte_vec_save_file(filename, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)*sizeof(cf_t));
*/
}
void phch_worker::encode_pucch()
{
if (uci_data.scheduling_request || uci_data.uci_ack_len > 0)
{
if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, tti+4, signal_buffer)) {
Error("Encoding PUCCH\n");
}
Info("PUCCH: TTI=%d, CFO= %.1f KHz n_cce=%d, ack=%s, sr=%s, shortened=%s\n", tti+4, cfo*15e3, last_dl_pdcch_ncce,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no",
ue_ul.pucch.shortened?"yes":"no");
}
if (uci_data.scheduling_request) {
phy->sr_enabled = false;
}
normalize();
}
void phch_worker::encode_srs()
{
if (srslte_ue_ul_srs_encode(&ue_ul, tti+4, signal_buffer))
{
Error("Encoding SRS\n");
}
Info("SRS: TTI=%d, CFO= %.1f KHz \n", tti+4, cfo*15e3);
normalize();
}
void phch_worker::enable_pregen_signals(bool enabled)
{
pregen_enabled = enabled;
}
void phch_worker::reset_ul_params()
{
bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t));
bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t));
bzero(&uci_cfg, sizeof(srslte_uci_cfg_t));
bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t));
bzero(&pucch_sched, sizeof(srslte_pucch_sched_t));
bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t));
bzero(&cqi_cfg, sizeof(srslte_cqi_cfg_t));
I_sr = 0;
}
void phch_worker::set_ul_params()
{
/* PUSCH DMRS signal configuration */
bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t));
dmrs_cfg.group_hopping_en = (bool) phy->params_db->get_param(phy_interface_params::DMRS_GROUP_HOPPING_EN);
dmrs_cfg.sequence_hopping_en = (bool) phy->params_db->get_param(phy_interface_params::DMRS_SEQUENCE_HOPPING_EN);
dmrs_cfg.cyclic_shift = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_RS_CYCLIC_SHIFT);
dmrs_cfg.delta_ss = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_RS_GROUP_ASSIGNMENT);
/* PUSCH Hopping configuration */
bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t));
pusch_hopping.n_sb = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_N_SB);
pusch_hopping.hop_mode = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_INTRA_SF) ?
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF :
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
pusch_hopping.hopping_offset = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_OFFSET);
/* PUSCH UCI configuration */
bzero(&uci_cfg, sizeof(srslte_uci_cfg_t));
uci_cfg.I_offset_ack = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_ACK);
uci_cfg.I_offset_cqi = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_CQI);
uci_cfg.I_offset_ri = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_RI);
/* PUCCH configuration */
bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t));
pucch_cfg.delta_pucch_shift = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_DELTA_SHIFT);
pucch_cfg.N_cs = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_CYCLIC_SHIFT);
pucch_cfg.n_rb_2 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_RB_2);
pucch_cfg.srs_configured = (bool) phy->params_db->get_param(phy_interface_params::SRS_IS_CONFIGURED)?true:false;
pucch_cfg.srs_cs_subf_cfg = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_SFCFG);
pucch_cfg.srs_simul_ack = (bool) phy->params_db->get_param(phy_interface_params::SRS_CS_ACKNACKSIMUL)?true:false;
/* PUCCH Scheduling configuration */
bzero(&pucch_sched, sizeof(srslte_pucch_sched_t));
pucch_sched.n_pucch_1[0] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_0);
pucch_sched.n_pucch_1[1] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_1);
pucch_sched.n_pucch_1[2] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_2);
pucch_sched.n_pucch_1[3] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_3);
pucch_sched.N_pucch_1 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1);
pucch_sched.n_pucch_2 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_2);
pucch_sched.n_pucch_sr = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_SR);
/* SRS Configuration */
bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t));
srs_cfg.configured = (bool) phy->params_db->get_param(phy_interface_params::SRS_IS_CONFIGURED)?true:false;
srs_cfg.subframe_config = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_SFCFG);
srs_cfg.bw_cfg = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_BWCFG);
srs_cfg.I_srs = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_CONFIGINDEX);
srs_cfg.B = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_BW);
srs_cfg.b_hop = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_HOP);
srs_cfg.n_rrc = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_NRRC);
srs_cfg.k_tc = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_TXCOMB);
srs_cfg.n_srs = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_CYCLICSHIFT);
srslte_ue_ul_set_cfg(&ue_ul, &dmrs_cfg, &srs_cfg, &pucch_cfg, &pucch_sched, &uci_cfg, &pusch_hopping);
/* CQI configuration */
bzero(&cqi_cfg, sizeof(srslte_cqi_cfg_t));
cqi_cfg.configured = (bool) phy->params_db->get_param(phy_interface_params::CQI_PERIODIC_CONFIGURED)?true:false;
cqi_cfg.pmi_idx = (uint32_t) phy->params_db->get_param(phy_interface_params::CQI_PERIODIC_PMI_IDX);
/* SR configuration */
I_sr = (uint32_t) phy->params_db->get_param(phy_interface_params::SR_CONFIG_INDEX);
if (pregen_enabled) {
printf("Pre-generating UL signals\n");
srslte_ue_ul_pregen_signals(&ue_ul);
}
}
/********** Execution time trace function ************/
void phch_worker::start_trace() {
trace_enabled = true;
}
void phch_worker::write_trace(std::string filename) {
tr_exec.writeToBinary(filename + ".exec");
}
void phch_worker::tr_log_start()
{
if (trace_enabled) {
gettimeofday(&tr_time[1], NULL);
}
}
void phch_worker::tr_log_end()
{
if (trace_enabled) {
gettimeofday(&tr_time[2], NULL);
get_time_interval(tr_time);
tr_exec.push(tti, tr_time[0].tv_usec);
}
}
}
}

@ -1,265 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <string>
#include <sstream>
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include "srslte/srslte.h"
#include "srsapps/common/threads.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/ue/phy/phch_worker.h"
using namespace std;
namespace srslte {
namespace ue {
phy::phy() : workers_pool(NOF_WORKERS),
workers(NOF_WORKERS),
workers_common(NOF_WORKERS)
{
}
bool phy::init(radio* radio_handler_, mac_interface_phy *mac, log *log_h) {
return init_(radio_handler_, mac, log_h, false);
}
bool phy::init_agc(radio* radio_handler_, mac_interface_phy *mac, log *log_h) {
return init_(radio_handler_, mac, log_h, true);
}
bool phy::init_(radio* radio_handler_, mac_interface_phy *mac, log *log_h_, bool do_agc)
{
mlockall(MCL_CURRENT | MCL_FUTURE);
log_h = log_h_;
radio_handler = radio_handler_;
// Set default params
params_db.set_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_NFRAMES, 100);
params_db.set_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_CORRELATION_THRESHOLD, 160);
params_db.set_param(phy_interface_params::CELLSEARCH_TIMEOUT_MIB_NFRAMES, 100);
prach_buffer.init(&params_db, log_h);
workers_common.init(&params_db, log_h, radio_handler, mac);
// Add workers to workers pool and start threads
for (int i=0;i<NOF_WORKERS;i++) {
workers[i].set_common(&workers_common);
workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO);
//printf("init worker here is at 0x%x\n", &workers[i]);
}
sf_recv.init(radio_handler, mac, &prach_buffer, &workers_pool, &workers_common, log_h, do_agc, SF_RECV_THREAD_PRIO);
return true;
}
void phy::start_trace()
{
for (int i=0;i<NOF_WORKERS;i++) {
workers[i].start_trace();
}
printf("trace started\n");
}
void phy::write_trace(std::string filename)
{
for (int i=0;i<NOF_WORKERS;i++) {
string i_str = static_cast<ostringstream*>( &(ostringstream() << i) )->str();
workers[i].write_trace(filename + "_" + i_str);
}
}
void phy::stop()
{
sf_recv.stop();
workers_pool.stop();
}
void phy::set_timeadv_rar(uint32_t ta_cmd) {
n_ta = srslte_N_ta_new_rar(ta_cmd);
sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS);
Info("Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6);
}
void phy::set_timeadv(uint32_t ta_cmd) {
n_ta = srslte_N_ta_new(n_ta, ta_cmd);
sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS);
Info("Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6);
}
void phy::set_param(phy_interface_params::phy_param_t param, int64_t value) {
params_db.set_param((uint32_t) param, value);
}
int64_t phy::get_param(phy_interface_params::phy_param_t param) {
return params_db.get_param((uint32_t) param);
}
void phy::configure_prach_params()
{
if (sf_recv.status_is_sync()) {
Info("Configuring PRACH parameters\n");
srslte_cell_t cell;
sf_recv.get_current_cell(&cell);
if (!prach_buffer.init_cell(cell)) {
Error("Configuring PRACH parameters\n");
} else {
Info("Done\n");
}
} else {
Error("Cell is not synchronized\n");
}
}
void phy::configure_ul_params()
{
Info("Configuring UL parameters\n");
for (int i=0;i<NOF_WORKERS;i++) {
workers[i].set_ul_params();
}
}
void phy::pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end)
{
workers_common.set_ul_rnti(rnti_type, rnti, tti_start, tti_end);
}
void phy::pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end)
{
workers_common.set_dl_rnti(rnti_type, rnti, tti_start, tti_end);
}
void phy::pdcch_dl_search_reset()
{
workers_common.set_dl_rnti(SRSLTE_RNTI_USER, 0);
}
void phy::pdcch_ul_search_reset()
{
workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0);
}
void phy::get_current_cell(srslte_cell_t *cell)
{
sf_recv.get_current_cell(cell);
}
void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm)
{
if (!prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm)) {
Error("Preparing PRACH to send\n");
}
}
int phy::prach_tx_tti()
{
return prach_buffer.tx_tti();
}
void phy::reset()
{
// TODO
}
uint32_t phy::get_current_tti()
{
return sf_recv.get_current_tti();
}
void phy::sr_send()
{
workers_common.sr_enabled = true;
workers_common.sr_last_tx_tti = -1;
}
int phy::sr_last_tx_tti()
{
return workers_common.sr_last_tx_tti;
}
bool phy::status_is_sync()
{
return sf_recv.status_is_sync();
}
void phy::sync_start()
{
sf_recv.sync_start();
}
void phy::sync_stop()
{
sf_recv.sync_stop();
}
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{
workers_common.set_rar_grant(tti, grant_payload);
}
void phy::set_crnti(uint16_t rnti) {
for(uint32_t i=0;i<NOF_WORKERS;i++) {
workers[i].set_crnti(rnti);
}
}
void phy::enable_pregen_signals(bool enable)
{
for(uint32_t i=0;i<NOF_WORKERS;i++) {
workers[i].enable_pregen_signals(enable);
}
}
uint32_t phy::tti_to_SFN(uint32_t tti) {
return tti/10;
}
uint32_t phy::tti_to_subf(uint32_t tti) {
return tti%10;
}
}
}

@ -1,155 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/prach.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/common/phy_interface.h"
namespace srslte {
namespace ue {
void prach::free_cell()
{
if (initiated) {
for (int i=0;i<64;i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
if (signal_buffer) {
free(signal_buffer);
}
srslte_cfo_free(&cfo_h);
srslte_prach_free(&prach_obj);
}
}
void prach::init(phy_params* params_db_, log* log_h_)
{
log_h = log_h_;
params_db = params_db_;
}
bool prach::init_cell(srslte_cell_t cell_)
{
cell = cell_;
preamble_idx = -1;
Info("ConfigIdx=%d, RootSeq=%d, ZC=%d\n",
params_db->get_param(phy_interface_params::PRACH_CONFIG_INDEX),
params_db->get_param(phy_interface_params::PRACH_ROOT_SEQ_IDX),
params_db->get_param(phy_interface_params::PRACH_ZC_CONFIG));
if (srslte_prach_init(&prach_obj, srslte_symbol_sz(cell.nof_prb),
srslte_prach_get_preamble_format(params_db->get_param(phy_interface_params::PRACH_CONFIG_INDEX)),
params_db->get_param(phy_interface_params::PRACH_ROOT_SEQ_IDX),
params_db->get_param(phy_interface_params::PRACH_HIGH_SPEED_FLAG)?true:false,
params_db->get_param(phy_interface_params::PRACH_ZC_CONFIG)))
{
Error("Initiating PRACH library\n");
return false;
}
len = prach_obj.N_seq + prach_obj.N_cp;
for (int i=0;i<64;i++) {
buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t));
if(!buffer[i]) {
return false;
}
if(srslte_prach_gen(&prach_obj, i, params_db->get_param(phy_interface_params::PRACH_FREQ_OFFSET), buffer[i])) {
Error("Generating PRACH preamble %d\n", i);
return false;
}
}
srslte_cfo_init(&cfo_h, len);
signal_buffer = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t));
initiated = signal_buffer?true:false;
transmitted_tti = -1;
Info("PRACH Initiated %s\n", initiated?"OK":"KO");
return initiated;
}
bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm)
{
if (initiated && preamble_idx_ < 64) {
preamble_idx = preamble_idx_;
allowed_subframe = allowed_subframe_;
transmitted_tti = -1;
Info("PRACH prepare to send preamble %d\n", preamble_idx);
return true;
} else {
if (!initiated) {
Error("PRACH not initiated\n");
} else if (preamble_idx_ >= 64) {
Error("Invalid preamble %d\n", preamble_idx_);
}
return false;
}
}
bool prach::is_ready_to_send(uint32_t current_tti_) {
if (initiated && preamble_idx >= 0 && preamble_idx < 64 && params_db != NULL) {
// consider the number of subframes the transmission must be anticipated
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240;
uint32_t config_idx = (uint32_t) params_db->get_param(phy_interface_params::PRACH_CONFIG_INDEX);
if (srslte_prach_send_tti(config_idx, current_tti, allowed_subframe)) {
Info("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_);
transmitted_tti = current_tti;
return true;
}
}
return false;
}
int prach::tx_tti() {
return transmitted_tti;
}
bool prach::send(radio *radio_handler, float cfo, srslte_timestamp_t tx_time)
{
// Correct CFO before transmission
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo /srslte_symbol_sz(cell.nof_prb));
// Normalize signal amplitude
srslte_vec_norm_cfc(signal_buffer, 0.9, signal_buffer, len);
radio_handler->tx(signal_buffer, len, tx_time);
Debug("PRACH transmitted CFO: %f, preamble=%d, len=%d tx_time=%f\n",
cfo*15000, preamble_idx, len, tx_time.frac_secs);
preamble_idx = -1;
}
} // namespace ue
} // namespace srslte

@ -1,29 +0,0 @@
#
# Copyright 2013-2015 The srsLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the srsLTE library.
#
# 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/.
#
IF(UHD_FOUND)
ADD_EXECUTABLE(ue_itf_test_sib1 ue_itf_test_sib1.cc)
TARGET_LINK_LIBRARIES(ue_itf_test_sib1 srsapps_common srsapps_ue_phy srsapps_radio srslte srslte_uhd)
ADD_EXECUTABLE(ue_itf_test_prach ue_itf_test_prach.cc)
TARGET_LINK_LIBRARIES(ue_itf_test_prach srsapps_common srsapps_ue_phy srsapps_radio srslte srslte_uhd)
ENDIF(UHD_FOUND)

@ -1,384 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <unistd.h>
#include "srslte/utils/debug.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/common/log_stdout.h"
#include "srsapps/radio/radio_uhd.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float uhd_rx_freq;
float uhd_tx_freq;
float uhd_rx_gain;
float uhd_tx_gain;
bool continous;
}prog_args_t;
prog_args_t prog_args;
uint32_t srsapps_verbose = 0;
void args_default(prog_args_t *args) {
args->uhd_rx_freq = -1.0;
args->uhd_tx_freq = -1.0;
args->uhd_rx_gain = -1; // set to autogain
args->uhd_tx_gain = -1;
args->continous = false;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gGcv] -f rx_frequency -F tx_frequency (in Hz)\n", prog);
printf("\t-g UHD RX gain [Default AGC]\n");
printf("\t-G UHD TX gain [Default same as RX gain (AGC)]\n");
printf("\t-c Run continuously [Default only once]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gGfFcv")) != -1) {
switch (opt) {
case 'g':
args->uhd_rx_gain = atof(argv[optind]);
break;
case 'G':
args->uhd_tx_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_rx_freq = atof(argv[optind]);
break;
case 'F':
args->uhd_tx_freq = atof(argv[optind]);
break;
case 'c':
args->continous = true;
break;
case 'v':
srsapps_verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_rx_freq < 0 || args->uhd_tx_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
typedef enum{
rar_header_type_bi = 0,
rar_header_type_rapid,
rar_header_type_n_items,
}rar_header_t;
static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"};
typedef struct {
rar_header_t hdr_type;
bool hopping_flag;
uint32_t tpc_command;
bool ul_delay;
bool csi_req;
uint16_t rba;
uint16_t timing_adv_cmd;
uint16_t temp_c_rnti;
uint8_t mcs;
uint8_t RAPID;
uint8_t BI;
}rar_msg_t;
int rar_unpack(uint8_t *buffer, rar_msg_t *msg)
{
int ret = SRSLTE_ERROR;
uint8_t *ptr = buffer;
if(buffer != NULL &&
msg != NULL)
{
ptr++;
msg->hdr_type = (rar_header_t) *ptr++;
if(msg->hdr_type == rar_header_type_bi) {
ptr += 2;
msg->BI = srslte_bit_unpack(&ptr, 4);
ret = SRSLTE_SUCCESS;
} else if (msg->hdr_type == rar_header_type_rapid) {
msg->RAPID = srslte_bit_unpack(&ptr, 6);
ptr++;
msg->timing_adv_cmd = srslte_bit_unpack(&ptr, 11);
msg->hopping_flag = *ptr++;
msg->rba = srslte_bit_unpack(&ptr, 10);
msg->mcs = srslte_bit_unpack(&ptr, 4);
msg->tpc_command = srslte_bit_unpack(&ptr, 3);
msg->ul_delay = *ptr++;
msg->csi_req = *ptr++;
msg->temp_c_rnti = srslte_bit_unpack(&ptr, 16);
ret = SRSLTE_SUCCESS;
}
}
return(ret);
}
srslte::ue::phy my_phy;
bool bch_decoded = false;
uint8_t payload[10240];
uint8_t payload_bits[10240];
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA;
uint32_t preamble_idx = 0;
rar_msg_t rar_msg;
uint32_t nof_rtx_connsetup = 0;
uint32_t rv_value[4] = {0, 2, 3, 1};
void config_phy() {
my_phy.set_param(srslte::ue::phy_interface_params::PRACH_CONFIG_INDEX, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PRACH_FREQ_OFFSET, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PRACH_HIGH_SPEED_FLAG, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PRACH_ROOT_SEQ_IDX, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PRACH_ZC_CONFIG, 11);
my_phy.set_param(srslte::ue::phy_interface_params::DMRS_GROUP_HOPPING_EN, 0);
my_phy.set_param(srslte::ue::phy_interface_params::DMRS_SEQUENCE_HOPPING_EN, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PUSCH_HOPPING_N_SB, 2);
my_phy.set_param(srslte::ue::phy_interface_params::PUSCH_RS_CYCLIC_SHIFT, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PUSCH_RS_GROUP_ASSIGNMENT, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PUSCH_HOPPING_OFFSET, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PUCCH_DELTA_SHIFT, 2);
my_phy.set_param(srslte::ue::phy_interface_params::PUCCH_CYCLIC_SHIFT, 0);
my_phy.set_param(srslte::ue::phy_interface_params::PUCCH_N_PUCCH_1, 1);
my_phy.set_param(srslte::ue::phy_interface_params::PUCCH_N_RB_2, 2);
my_phy.configure_ul_params();
my_phy.configure_prach_params();
}
srslte_softbuffer_rx_t softbuffer_rx;
srslte_softbuffer_tx_t softbuffer_tx;
uint16_t temp_c_rnti;
/******** MAC Interface implementation */
class testmac : public srslte::ue::mac_interface_phy
{
public:
testmac() {
rar_rnti_set = false;
}
bool rar_rnti_set;
void tti_clock(uint32_t tti) {
if (!rar_rnti_set) {
int prach_tti = my_phy.prach_tx_tti();
if (prach_tti > 0) {
my_phy.pdcch_dl_search(SRSLTE_RNTI_RAR, 1+prach_tti%10, prach_tti+3, prach_tti+13);
rar_rnti_set = true;
}
}
}
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) {
printf("New grant UL\n");
memcpy(payload, conn_request_msg, grant.n_bytes*sizeof(uint8_t));
action->current_tx_nb = nof_rtx_connsetup;
action->rv = rv_value[nof_rtx_connsetup%4];
action->softbuffer = &softbuffer_tx;
action->rnti = temp_c_rnti;
action->expect_ack = (nof_rtx_connsetup < 5)?true:false;
action->payload_ptr = payload;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
action->tx_enabled = true;
if (action->rv == 0) {
srslte_softbuffer_tx_reset(&softbuffer_tx);
}
my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti);
}
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) {
printf("New grant UL ACK\n");
}
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) {
printf("harq recv hi=%d\n", ack?1:0);
if (!ack) {
nof_rtx_connsetup++;
action->current_tx_nb = nof_rtx_connsetup;
action->rv = rv_value[nof_rtx_connsetup%4];
action->softbuffer = &softbuffer_tx;
action->rnti = temp_c_rnti;
action->expect_ack = true;
memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t));
action->tx_enabled = true;
if (action->rv == 0) {
srslte_softbuffer_tx_reset(&softbuffer_tx);
}
printf("Retransmission %d, rv=%d\n", nof_rtx_connsetup, action->rv);
}
}
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) {
action->decode_enabled = true;
action->default_ack = false;
if (grant.rnti == 2) {
action->generate_ack = false;
} else {
action->generate_ack = true;
}
action->payload_ptr = payload;
action->rnti = grant.rnti;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
action->rv = grant.rv;
action->softbuffer = &softbuffer_rx;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rx);
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) {
if (ack) {
if (rnti_type == SRSLTE_RNTI_RAR) {
my_phy.pdcch_dl_search_reset();
srslte_bit_pack_vector(payload, payload_bits, last_grant.n_bytes*8);
rar_unpack(payload_bits, &rar_msg);
if (rar_msg.RAPID == preamble_idx) {
printf("Received RAR at TTI: %d\n", last_grant.tti);
my_phy.set_timeadv_rar(rar_msg.timing_adv_cmd);
temp_c_rnti = rar_msg.temp_c_rnti;
if (last_grant.n_bytes*8 > 20 + SRSLTE_RAR_GRANT_LEN) {
uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN];
memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN);
my_phy.set_rar_grant(last_grant.tti, rar_grant);
}
} else {
printf("Received RAR RAPID=%d\n", rar_msg.RAPID);
}
} else {
printf("Received Connection Setup\n");
my_phy.pdcch_dl_search_reset();
}
}
}
void bch_decoded_ok(uint8_t *payload, uint32_t len) {
printf("BCH decoded\n");
bch_decoded = true;
srslte_cell_t cell;
my_phy.get_current_cell(&cell);
srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb);
srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb);
}
private:
mac_grant_t last_grant;
};
testmac my_mac;
srslte::radio_uhd radio_uhd;
int main(int argc, char *argv[])
{
srslte::log_stdout log("PHY");
parse_args(&prog_args, argc, argv);
// Init Radio and PHY
if (prog_args.uhd_rx_gain > 0 && prog_args.uhd_tx_gain > 0) {
radio_uhd.init();
radio_uhd.set_rx_gain(prog_args.uhd_rx_gain);
radio_uhd.set_tx_gain(prog_args.uhd_tx_gain);
my_phy.init(&radio_uhd, &my_mac, &log);
} else {
radio_uhd.init_agc();
radio_uhd.set_tx_rx_gain_offset(10);
my_phy.init_agc(&radio_uhd, &my_mac, &log);
}
if (srsapps_verbose == 1) {
log.set_level_info();
printf("Log level info\n");
}
if (srsapps_verbose == 2) {
log.set_level_debug();
printf("Log level debug\n");
}
// Give it time to create thread
sleep(1);
// Set RX freq
radio_uhd.set_rx_freq(prog_args.uhd_rx_freq);
radio_uhd.set_tx_freq(prog_args.uhd_tx_freq);
// Instruct the PHY to configure PRACH parameters and sync to current cell
my_phy.sync_start();
while(!my_phy.status_is_sync()) {
usleep(20000);
}
// Setup PHY parameters
config_phy();
/* Instruct PHY to send PRACH and prepare it for receiving RAR */
my_phy.prach_send(preamble_idx);
/* go to idle and process each tti */
bool running = true;
while(running) {
sleep(1);
}
my_phy.stop();
radio_uhd.stop_rx();
}

@ -1,211 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* 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 <unistd.h>
#include "srslte/utils/debug.h"
#include "srsapps/ue/phy/phy.h"
#include "srsapps/common/log_stdout.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/radio/radio_uhd.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float uhd_freq;
float uhd_gain;
}prog_args_t;
uint32_t srsapps_verbose = 0;
prog_args_t prog_args;
void args_default(prog_args_t *args) {
args->uhd_freq = -1.0;
args->uhd_gain = -1.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gv] -f rx_frequency (in Hz)\n", prog);
printf("\t-g UHD RX gain [Default AGC]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gfv")) != -1) {
switch (opt) {
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'v':
srsapps_verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
srslte::ue::phy my_phy;
bool bch_decoded = false;
uint32_t total_pkts=0;
uint32_t total_dci=0;
uint32_t total_oks=0;
uint8_t payload[1024];
srslte_softbuffer_rx_t softbuffer;
/******** MAC Interface implementation */
class testmac : public srslte::ue::mac_interface_phy
{
public:
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) {
printf("New grant UL\n");
}
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) {
printf("New grant UL ACK\n");
}
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) {
printf("harq recv\n");
}
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) {
total_dci++;
action->decode_enabled = true;
action->default_ack = false;
action->generate_ack = false;
action->payload_ptr = payload;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->rv = ((uint32_t) ceilf((float)3*((my_phy.tti_to_SFN(grant.tti)/2)%4)/2))%4;
action->softbuffer = &softbuffer;
action->rnti = grant.rnti;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti, uint32_t harq_pid) {
if (ack) {
total_oks++;
}
}
void bch_decoded_ok(uint8_t *payload, uint32_t len) {
printf("BCH decoded\n");
bch_decoded = true;
srslte_cell_t cell;
my_phy.get_current_cell(&cell);
srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb);
}
void tti_clock(uint32_t tti) {
}
};
testmac my_mac;
srslte::radio_uhd radio_uhd;
int main(int argc, char *argv[])
{
srslte::log_stdout log("PHY");
parse_args(&prog_args, argc, argv);
// Init Radio and PHY
if (prog_args.uhd_gain > 0) {
radio_uhd.init();
radio_uhd.set_rx_gain(prog_args.uhd_gain);
my_phy.init(&radio_uhd, &my_mac, &log);
} else {
radio_uhd.init_agc();
my_phy.init_agc(&radio_uhd, &my_mac, &log);
}
if (srsapps_verbose == 1) {
log.set_level_info();
printf("Log level info\n");
}
if (srsapps_verbose == 2) {
log.set_level_debug();
printf("Log level debug\n");
}
// Give it time to create thread
sleep(1);
// Set RX freq and gain
radio_uhd.set_rx_freq(prog_args.uhd_freq);
my_phy.sync_start();
bool running = true;
while(running) {
if (bch_decoded && my_phy.status_is_sync()) {
uint32_t tti = my_phy.get_current_tti();
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
tti = (((tti/20)*20) + 25)%10240;
my_phy.pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, tti, tti+1);
total_pkts++;
}
usleep(30000);
if (bch_decoded && my_phy.status_is_sync() && total_pkts > 0) {
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
float gain = prog_args.uhd_gain;
if (gain < 0) {
gain = radio_uhd.get_rx_gain();
}
printf("PDCCH BLER %.1f \%% PDSCH BLER %.1f \%% (total pkts: %5u) Gain: %.1f dB\r",
100-(float) 100*total_dci/total_pkts,
(float) 100*(1 - total_oks/total_pkts),
total_pkts, gain);
}
}
}
my_phy.stop();
radio_uhd.stop_rx();
}
Loading…
Cancel
Save