mirror of https://github.com/pvnis/srsRAN_4G.git
Moved srsapps to srsue repository
parent
a5c43d9959
commit
510e4c892e
@ -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, ¶m)) {
|
|
||||||
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, ¶m);
|
|
||||||
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, ¶ms_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, ¶ms_db, &timers_db, &mux_unit, &demux_unit);
|
|
||||||
sr_procedure.init (phy_h, log_h, ¶ms_db);
|
|
||||||
ul_harq.init ( log_h, ¶ms_db, &timers_db, &mux_unit);
|
|
||||||
dl_harq.init ( log_h, ¶ms_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(¶ms_db, log_h);
|
|
||||||
workers_common.init(¶ms_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…
Reference in New Issue