mirror of https://github.com/pvnis/srsRAN_4G.git
Changed directory structure. Compilation working with w/o UHD and srsGUI
parent
c57d8969be
commit
132c919dcf
@ -1,48 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2012-2013 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 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/.
|
|
||||||
#
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
# Install headers
|
|
||||||
########################################################################
|
|
||||||
INSTALL(DIRECTORY include/
|
|
||||||
DESTINATION "${INCLUDE_DIR}"
|
|
||||||
FILES_MATCHING PATTERN "*.h"
|
|
||||||
PATTERN ".svn" EXCLUDE
|
|
||||||
)
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
# Add headers to cmake project (useful for IDEs)
|
|
||||||
########################################################################
|
|
||||||
SET(HEADERS_ALL "")
|
|
||||||
FILE(GLOB headers *)
|
|
||||||
FOREACH (_header ${headers})
|
|
||||||
IF(IS_DIRECTORY ${_header})
|
|
||||||
FILE(GLOB_RECURSE tmp "${_header}/*.h")
|
|
||||||
LIST(APPEND HEADERS_ALL ${tmp})
|
|
||||||
ENDIF(IS_DIRECTORY ${_header})
|
|
||||||
ENDFOREACH()
|
|
||||||
ADD_CUSTOM_TARGET (add_cuhd_headers SOURCES ${HEADERS_ALL})
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
# Add the subdirectories
|
|
||||||
########################################################################
|
|
||||||
ADD_SUBDIRECTORY(lib)
|
|
||||||
|
|
@ -1,30 +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 "srslte/config.h"
|
|
||||||
|
|
||||||
SRSLTE_API int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp);
|
|
@ -1,79 +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 <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "srslte/cuhd/cuhd.h"
|
|
||||||
#include "srslte/utils/vector.h"
|
|
||||||
#include "srslte/utils/debug.h"
|
|
||||||
|
|
||||||
int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) {
|
|
||||||
int i, j;
|
|
||||||
int ret = -1;
|
|
||||||
_Complex float *buffer;
|
|
||||||
double f;
|
|
||||||
|
|
||||||
buffer = calloc(nsamp, sizeof(_Complex float));
|
|
||||||
if (!buffer) {
|
|
||||||
goto free_and_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
cuhd_set_rx_gain(uhd, 20.0);
|
|
||||||
cuhd_set_rx_srate(uhd, fs);
|
|
||||||
|
|
||||||
for (i=0;i<nof_bands;i++) {
|
|
||||||
cuhd_stop_rx_stream(uhd);
|
|
||||||
|
|
||||||
f = (double) freqs[i];
|
|
||||||
cuhd_set_rx_freq(uhd, f);
|
|
||||||
cuhd_rx_wait_lo_locked(uhd);
|
|
||||||
usleep(10000);
|
|
||||||
cuhd_start_rx_stream(uhd);
|
|
||||||
|
|
||||||
/* discard first samples */
|
|
||||||
for (j=0;j<2;j++) {
|
|
||||||
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
|
|
||||||
goto free_and_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rssi[i] = srslte_vec_avg_power_cf(buffer, nsamp);
|
|
||||||
printf("[%3d]: Freq %4.1f Mhz - RSSI: %3.2f dBm\r", i, f/1000000, 10*log10f(rssi[i]) + 30); fflush(stdout);
|
|
||||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cuhd_stop_rx_stream(uhd);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
free_and_exit:
|
|
||||||
free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 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 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/.
|
||||||
|
#
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "src/*.cc")
|
||||||
|
ADD_LIBRARY(srsapps_common SHARED ${SOURCES})
|
||||||
|
INSTALL(TARGETS srsapps_common DESTINATION ${LIBRARY_DIR})
|
||||||
|
LIBLTE_SET_PIC(srsapps_common)
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "include/srsapps/common/*.h")
|
||||||
|
ADD_CUSTOM_TARGET (add_srsapps_common_headers SOURCES ${HEADERS_ALL})
|
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#ifndef BINSEM_H
|
||||||
|
#define BINSEM_H
|
||||||
|
|
||||||
|
/** Implementation of a binary semaphore using POSIX condition variable and mutex
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
|
||||||
|
class binsem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
binsem() {
|
||||||
|
pthread_mutex_init(&mutex, NULL);
|
||||||
|
pthread_cond_init(&cv, NULL);
|
||||||
|
state = true;
|
||||||
|
}
|
||||||
|
~binsem() {
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
pthread_cond_destroy(&cv);
|
||||||
|
}
|
||||||
|
void take() {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
while(!state) {
|
||||||
|
pthread_cond_wait(&cv, &mutex);
|
||||||
|
}
|
||||||
|
state = false;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
void give() {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
pthread_cond_signal(&cv);
|
||||||
|
state = true;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
pthread_cond_t cv;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
bool state;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 <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(uint32_t tti, string message, ...);
|
||||||
|
void warning(uint32_t tti, string message, ...);
|
||||||
|
void info(uint32_t tti, string message, ...);
|
||||||
|
void debug(uint32_t tti, string message, ...);
|
||||||
|
|
||||||
|
// Same with line and file info
|
||||||
|
void error(uint32_t tti, string file, int line, string message, ...);
|
||||||
|
void warning(uint32_t tti, string file, int line, string message, ...);
|
||||||
|
void info(uint32_t tti, string file, int line, string message, ...);
|
||||||
|
void debug(uint32_t tti, 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
|
||||||
|
|
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "srslte/config.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 SRSLTE_API 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
|
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "srslte/config.h"
|
||||||
|
|
||||||
|
#ifndef TIMERS_H
|
||||||
|
#define TIMERS_H
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
|
||||||
|
class SRSLTE_API timer_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void timer_expired(uint32_t timer_id) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SRSLTE_API timers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class SRSLTE_API 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_) {
|
||||||
|
nof_timers = nof_timers_;
|
||||||
|
timer_list = new timer[nof_timers];
|
||||||
|
for (uint32_t i=0;i<nof_timers;i++) {
|
||||||
|
timer_list[i].id = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~timers() {
|
||||||
|
delete timer_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
uint32_t nof_timers;
|
||||||
|
timer *timer_list;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 <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(uint32_t tti, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(ERROR, tti, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_stdout::info(uint32_t tti, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(INFO, tti, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_stdout::debug(uint32_t tti, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(DEBUG, tti, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_stdout::warning(uint32_t tti, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(WARNING, tti, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_stdout::error(uint32_t tti, 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(uint32_t tti, string file, int line, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(INFO, tti, file, line, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_stdout::debug(uint32_t tti, string file, int line, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(DEBUG, tti, file, line, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_stdout::warning(uint32_t tti, string file, int line, string msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
printlog(WARNING, tti, file, line, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,185 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
push(msg_size);
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 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 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_DIRECTORIES(phy/include/)
|
||||||
|
INCLUDE_DIRECTORIES(mac/include/)
|
||||||
|
|
||||||
|
add_subdirectory(phy)
|
||||||
|
add_subdirectory(mac)
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 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 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/.
|
||||||
|
#
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "src/*.cc")
|
||||||
|
ADD_LIBRARY(srsapps_ue_mac SHARED ${SOURCES})
|
||||||
|
INSTALL(TARGETS srsapps_ue_mac DESTINATION ${LIBRARY_DIR})
|
||||||
|
LIBLTE_SET_PIC(srsapps_ue_mac)
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "include/*.h")
|
||||||
|
ADD_CUSTOM_TARGET (add_srsapps_ue_mac_headers SOURCES ${HEADERS_ALL})
|
||||||
|
|
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
#include "srsapps/ue/mac/mac_io.h"
|
||||||
|
#include "srsapps/common/timers.h"
|
||||||
|
#include "srsapps/ue/mac/mac_params.h"
|
||||||
|
#include "srsapps/ue/mac/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* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_);
|
||||||
|
|
||||||
|
void push_pdu(uint32_t tti, uint8_t *mac_pdu, uint32_t nof_bits);
|
||||||
|
void push_pdu_bcch(uint32_t tti, uint8_t *mac_pdu, uint32_t nof_bits);
|
||||||
|
void push_pdu_temp_crnti(uint32_t tti, uint8_t *mac_pdu, uint32_t nof_bits);
|
||||||
|
bool is_temp_crnti_pending();
|
||||||
|
void demultiplex_pending_pdu(uint32_t tti);
|
||||||
|
|
||||||
|
uint64_t get_contention_resolution_id();
|
||||||
|
|
||||||
|
private:
|
||||||
|
mac_pdu mac_msg;
|
||||||
|
mac_pdu pending_mac_msg;
|
||||||
|
|
||||||
|
void process_pdu(mac_pdu *pdu);
|
||||||
|
bool process_ce(mac_pdu::mac_subh *subheader);
|
||||||
|
|
||||||
|
uint64_t contention_resolution_id;
|
||||||
|
bool pending_temp_rnti;
|
||||||
|
|
||||||
|
phy *phy_h;
|
||||||
|
log *log_h;
|
||||||
|
mac_io *mac_io_h;
|
||||||
|
timers *timers_db;
|
||||||
|
uint32_t tti;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#ifndef DLHARQ_H
|
||||||
|
#define DLHARQ_H
|
||||||
|
|
||||||
|
/* Downlink HARQ entity as defined in 5.3.2 of 36.321 */
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
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();
|
||||||
|
~dl_harq_entity();
|
||||||
|
bool init(srslte_cell_t cell, uint32_t max_payload_len, srslte::log *log_h_, timers *timers_, demux *demux_unit);
|
||||||
|
bool is_sps(uint32_t pid);
|
||||||
|
void set_harq_info(uint32_t tti, uint32_t pid, dl_sched_grant *grant);
|
||||||
|
void receive_data(uint32_t tti, uint32_t pid, dl_buffer *dl_buffer, phy *phy_h);
|
||||||
|
void reset();
|
||||||
|
bool is_ack_pending_resolution();
|
||||||
|
void send_pending_ack_contention_resolution();
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
class dl_harq_process {
|
||||||
|
public:
|
||||||
|
dl_harq_process();
|
||||||
|
bool init(srslte_cell_t cell, uint32_t max_payload_len, dl_harq_entity *parent);
|
||||||
|
void set_harq_info(uint32_t tti, dl_sched_grant *grant);
|
||||||
|
void receive_data(uint32_t tti, dl_buffer *dl_buffer, phy *phy_h);
|
||||||
|
void reset();
|
||||||
|
// Called after the contention resolution is terminated to send pending ACKs, if any
|
||||||
|
void send_pending_ack_contention_resolution();
|
||||||
|
uint32_t pid;
|
||||||
|
private:
|
||||||
|
|
||||||
|
dl_harq_entity *harq_entity;
|
||||||
|
uint8_t *payload;
|
||||||
|
uint32_t max_payload_len;
|
||||||
|
dl_sched_grant cur_grant;
|
||||||
|
dl_sched_grant pending_ack_grant;
|
||||||
|
ul_buffer *pending_ul_buffer;
|
||||||
|
bool is_first_tx;
|
||||||
|
bool is_first_decoded;
|
||||||
|
bool pending_ack;
|
||||||
|
srslte::log *log_h;
|
||||||
|
|
||||||
|
srslte_softbuffer_rx_t softbuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
dl_harq_process *proc;
|
||||||
|
timers *timers_db;
|
||||||
|
demux *demux_unit;
|
||||||
|
srslte::log *log_h;
|
||||||
|
int pending_ack_pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
class dl_sps
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void reset(uint32_t tti, dl_sched_grant *grant);
|
||||||
|
dl_sched_grant *get_pending_grant(uint32_t tti);
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
#include "srsapps/common/tti_sync.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/ue/mac/dl_sps.h"
|
||||||
|
#include "srsapps/ue/mac/ul_sps.h"
|
||||||
|
#include "srsapps/common/timers.h"
|
||||||
|
#include "srsapps/ue/mac/mac_io.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"
|
||||||
|
|
||||||
|
#ifndef UEMAC_H
|
||||||
|
#define UEMAC_H
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
class mac : public timer_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mac() : timers_db((uint32_t) NOF_MAC_TIMERS) {}
|
||||||
|
bool init(phy *phy_h, tti_sync *ttisync, log *log_h);
|
||||||
|
void stop();
|
||||||
|
int get_tti();
|
||||||
|
void main_radio_loop(); // called after thread creation
|
||||||
|
|
||||||
|
bool send_ccch_sdu(uint8_t *sdu_payload, uint32_t nbytes);
|
||||||
|
bool send_dtch0_sdu(uint8_t *sdu_payload, uint32_t nbytes); // SRB0
|
||||||
|
bool send_dcch0_sdu(uint8_t *sdu_payload, uint32_t nbytes); // DRB0
|
||||||
|
|
||||||
|
int recv_bcch_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes);
|
||||||
|
int recv_ccch_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes);
|
||||||
|
int recv_dtch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // SRB0
|
||||||
|
int recv_dcch0_sdu(uint8_t *sdu_payload, uint32_t buffer_len_nbytes); // DRB0
|
||||||
|
|
||||||
|
void set_dcch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD);
|
||||||
|
void set_dtch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD);
|
||||||
|
|
||||||
|
void set_param(mac_params::mac_param_t param, int64_t value);
|
||||||
|
|
||||||
|
void reconfiguration();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void timer_expired(uint32_t timer_id);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HARQ_RTT = 0,
|
||||||
|
TIME_ALIGNMENT,
|
||||||
|
CONTENTION_TIMER,
|
||||||
|
NOF_MAC_TIMERS
|
||||||
|
} mac_timers_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Interaction with PHY
|
||||||
|
tti_sync *ttisync;
|
||||||
|
phy *phy_h;
|
||||||
|
|
||||||
|
log *log_h;
|
||||||
|
|
||||||
|
/* Logical channel (lch) IO */
|
||||||
|
mac_io mac_io_lch;
|
||||||
|
|
||||||
|
|
||||||
|
mac_params params_db;
|
||||||
|
pthread_t mac_thread;
|
||||||
|
static void* mac_thread_fnc(void*);
|
||||||
|
|
||||||
|
int tti;
|
||||||
|
bool started = false;
|
||||||
|
bool is_synchronized;
|
||||||
|
bool is_first_temporal;
|
||||||
|
|
||||||
|
/* Multiplexing/Demultiplexing Units */
|
||||||
|
mux mux_unit;
|
||||||
|
demux demux_unit;
|
||||||
|
|
||||||
|
/* DL/UL HARQ */
|
||||||
|
dl_harq_entity dl_harq;
|
||||||
|
ul_harq_entity ul_harq;
|
||||||
|
|
||||||
|
/* DL/UL Semi-Persistent Sched */
|
||||||
|
dl_sps dl_sps_assig;
|
||||||
|
ul_sps ul_sps_assig;
|
||||||
|
uint32_t get_harq_sps_pid(uint32_t tti);
|
||||||
|
|
||||||
|
/* MAC Uplink-related Procedures */
|
||||||
|
ra_proc ra_procedure;
|
||||||
|
sr_proc sr_procedure;
|
||||||
|
bsr_proc bsr_procedure;
|
||||||
|
phr_proc phr_procedure;
|
||||||
|
|
||||||
|
/* Other procedures */
|
||||||
|
void process_dl_grants(uint32_t tti);
|
||||||
|
void process_ul_grants(uint32_t tti);
|
||||||
|
void receive_pch(uint32_t tti);
|
||||||
|
|
||||||
|
/* Functions for MAC Timers */
|
||||||
|
timers timers_db;
|
||||||
|
void setup_timers();
|
||||||
|
void timeAlignmentTimerExpire();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,84 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "srsapps/common/qbuff.h"
|
||||||
|
|
||||||
|
#ifndef MACIO_H
|
||||||
|
#define MACIO_H
|
||||||
|
|
||||||
|
/* Manages all MAC buffers including:
|
||||||
|
* - communication with higher layers through logical channels
|
||||||
|
* - communication between logical channels buffers and Dissassembly/Assembly unit
|
||||||
|
* - communication between Dissassembly/Assembly unit and Msg3 buffer
|
||||||
|
*
|
||||||
|
* For logical channels, IN means higher layers to MAC. OUT means MAC to higher layers.
|
||||||
|
*
|
||||||
|
* See queue.h for instructions on how to manage buffers
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
class mac_io
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// list of logical channels
|
||||||
|
// Keep this order to match LoCH id with RB
|
||||||
|
typedef enum {
|
||||||
|
// Downlink (UE MAC -> UE RRC)
|
||||||
|
MAC_LCH_CCCH_DL = 0, // SRB0
|
||||||
|
MAC_LCH_DCCH0_DL, // SRB1
|
||||||
|
MAC_LCH_DCCH1_DL, // SRB2
|
||||||
|
MAC_LCH_DTCH0_DL, // DRB0
|
||||||
|
MAC_LCH_DTCH1_DL, // DRB1
|
||||||
|
MAC_LCH_DTCH2_DL, // DRB2
|
||||||
|
MAC_LCH_BCCH_DL, // N/A
|
||||||
|
MAC_LCH_PCCH_DL, // N/A
|
||||||
|
|
||||||
|
// Uplink (UE RLC -> UE MAC)
|
||||||
|
MAC_LCH_CCCH_UL, // SRB0
|
||||||
|
MAC_LCH_DCCH0_UL, // SRB1
|
||||||
|
MAC_LCH_DCCH1_UL, // SRB2
|
||||||
|
MAC_LCH_DTCH0_UL, // DRB0
|
||||||
|
MAC_LCH_DTCH1_UL, // DRB1
|
||||||
|
MAC_LCH_DTCH2_UL, // DRB2
|
||||||
|
|
||||||
|
MAC_NOF_QUEUES
|
||||||
|
} mac_lch_t;
|
||||||
|
|
||||||
|
const static int NOF_DL_LCH = MAC_LCH_PCCH_DL - MAC_LCH_CCCH_DL;
|
||||||
|
const static int NOF_UL_LCH = MAC_LCH_DTCH2_UL - MAC_LCH_CCCH_UL;
|
||||||
|
|
||||||
|
const static int DEFAULT_MSG_SZ = 8*1024; // 8 Kbytes
|
||||||
|
const static int DEFAULT_NOF_MESSAGES = 8;
|
||||||
|
|
||||||
|
|
||||||
|
qbuff* get(mac_lch_t ch) {
|
||||||
|
return get((uint32_t) ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
qbuff* get(int32_t lchid) {
|
||||||
|
if (lchid < MAC_NOF_QUEUES) {
|
||||||
|
return &queues[lchid];
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move packets between queues with only 1 memcpy
|
||||||
|
void move(mac_lch_t src, mac_lch_t dst) {
|
||||||
|
get(src)->move_to(get(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_io() {
|
||||||
|
for (int i=0;i<MAC_NOF_QUEUES;i++) {
|
||||||
|
queues[i].init(DEFAULT_NOF_MESSAGES, DEFAULT_MSG_SZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
qbuff queues[MAC_NOF_QUEUES];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
#include "srsapps/common/params_db.h"
|
||||||
|
|
||||||
|
#ifndef MACPARAMS_H
|
||||||
|
#define MACPARAMS_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
class mac_params : public params_db
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
mac_params() : params_db(NOF_PARAMS) {}
|
||||||
|
~mac_params() {}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
// These 4 parameters must be together!!
|
||||||
|
RNTI_C = 0,
|
||||||
|
RNTI_SPS,
|
||||||
|
RNTI_TEMP,
|
||||||
|
RNTI_RA,
|
||||||
|
|
||||||
|
SPS_DL_SCHED_INTERVAL,
|
||||||
|
SPS_DL_NOF_PROC,
|
||||||
|
|
||||||
|
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,
|
||||||
|
RA_MAXTXMSG3,
|
||||||
|
|
||||||
|
PDSCH_RSPOWER,
|
||||||
|
PDSCH_PB,
|
||||||
|
|
||||||
|
|
||||||
|
NOF_PARAMS,
|
||||||
|
} mac_param_t;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,137 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
|
||||||
|
#ifndef MACPDU_H
|
||||||
|
#define MACPDU_H
|
||||||
|
|
||||||
|
/* MAC PDU Packing/Unpacking functions */
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
class mac_pdu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class mac_subh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
C_RNTI = 0,
|
||||||
|
CON_RES_ID,
|
||||||
|
TA_CMD,
|
||||||
|
PHD,
|
||||||
|
SDU
|
||||||
|
} cetype;
|
||||||
|
|
||||||
|
// Reading functions
|
||||||
|
bool is_sdu();
|
||||||
|
cetype ce_type();
|
||||||
|
|
||||||
|
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_phd();
|
||||||
|
|
||||||
|
// Writing functions
|
||||||
|
bool set_sdu(uint8_t *ptr, uint32_t nof_bytes);
|
||||||
|
bool set_c_rnti(uint16_t crnti);
|
||||||
|
bool set_con_res_id(uint64_t con_res_id);
|
||||||
|
bool set_ta_cmd(uint8_t ta_cmd);
|
||||||
|
bool set_phd(uint8_t phd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int MAX_CE_PAYLOAD_LEN = 8;
|
||||||
|
uint32_t lcid;
|
||||||
|
uint32_t nof_bytes;
|
||||||
|
uint8_t* sdu_payload_ptr;
|
||||||
|
uint8_t ce_payload[MAX_CE_PAYLOAD_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
mac_pdu(uint32_t max_subheaders);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void init(uint32_t pdu_len);
|
||||||
|
|
||||||
|
bool read_next();
|
||||||
|
bool write_next();
|
||||||
|
mac_subh* get();
|
||||||
|
|
||||||
|
bool write_packet(uint8_t *ptr);
|
||||||
|
void parse_packet(uint8_t *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mac_subh *subheaders;
|
||||||
|
uint32_t pdu_len;
|
||||||
|
uint32_t rem_len;
|
||||||
|
uint32_t rp, wp;
|
||||||
|
uint32_t nof_subheaders;
|
||||||
|
uint32_t max_subheaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
class mac_rar_pdu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class mac_rar
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const uint32_t RAR_GRANT_LEN = 20;
|
||||||
|
|
||||||
|
// Reading functions
|
||||||
|
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 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]);
|
||||||
|
private:
|
||||||
|
uint8_t grant[RAR_GRANT_LEN];
|
||||||
|
uint32_t ta;
|
||||||
|
uint16_t temp_rnti;
|
||||||
|
};
|
||||||
|
|
||||||
|
mac_rar_pdu(uint32_t max_rars);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void init(uint32_t pdu_len);
|
||||||
|
|
||||||
|
bool read_next();
|
||||||
|
bool write_next();
|
||||||
|
mac_rar* get();
|
||||||
|
|
||||||
|
void set_backoff(uint8_t bi);
|
||||||
|
bool is_backoff();
|
||||||
|
uint8_t get_backoff();
|
||||||
|
|
||||||
|
bool write_packet(uint8_t *ptr);
|
||||||
|
void parse_packet(uint8_t *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
mac_rar *rars;
|
||||||
|
uint32_t pdu_len;
|
||||||
|
uint32_t rem_len;
|
||||||
|
uint32_t rp, wp;
|
||||||
|
uint32_t nof_rars;
|
||||||
|
uint32_t max_rars;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,71 @@
|
|||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
#include "srsapps/ue/mac/mac_io.h"
|
||||||
|
#include "srsapps/ue/mac/mac_params.h"
|
||||||
|
#include "srsapps/ue/mac/mac_pdu.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(log *log_h, mac_io *mac_io_h);
|
||||||
|
|
||||||
|
uint8_t* pdu_pop(uint32_t tti_, uint32_t pdu_sz);
|
||||||
|
bool pdu_move_to_msg3(uint32_t tti, uint32_t pdu_sz);
|
||||||
|
void pdu_release();
|
||||||
|
|
||||||
|
uint8_t* msg3_pop(uint32_t tti_, uint32_t pdu_sz);
|
||||||
|
void msg3_flush();
|
||||||
|
void msg3_release();
|
||||||
|
bool msg3_isempty();
|
||||||
|
|
||||||
|
void append_crnti_ce_next_tx(uint16_t crnti);
|
||||||
|
|
||||||
|
void set_priority(uint32_t lch_id, uint32_t priority, int PBR_x_tti, uint32_t BSD);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool assemble_pdu(uint32_t pdu_sz);
|
||||||
|
bool allocate_sdu(uint32_t lcid, mac_pdu *pdu, uint32_t *sdu_sz);
|
||||||
|
bool allocate_sdu(uint32_t lcid, mac_pdu *pdu);
|
||||||
|
|
||||||
|
int64_t Bj[mac_io::NOF_UL_LCH];
|
||||||
|
int PBR[mac_io::NOF_UL_LCH]; // -1 sets to infinity
|
||||||
|
uint32_t BSD[mac_io::NOF_UL_LCH];
|
||||||
|
uint32_t priority[mac_io::NOF_UL_LCH];
|
||||||
|
uint32_t priority_sorted[mac_io::NOF_UL_LCH];
|
||||||
|
uint32_t lchid_sorted[mac_io::NOF_UL_LCH];
|
||||||
|
uint32_t nof_tx_pkts[mac_io::NOF_UL_LCH];
|
||||||
|
|
||||||
|
// Mutex for priority setting from outside MAC
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
log *log_h;
|
||||||
|
mac_io *mac_io_h;
|
||||||
|
uint32_t tti;
|
||||||
|
uint16_t pending_crnti_ce;
|
||||||
|
|
||||||
|
/* Msg3 Buffer */
|
||||||
|
static const uint32_t MSG3_BUFF_SZ = 128;
|
||||||
|
qbuff msg3_buff;
|
||||||
|
|
||||||
|
/* PDU Buffer */
|
||||||
|
static const uint32_t PDU_BUFF_SZ = 16*1024;
|
||||||
|
qbuff pdu_buff;
|
||||||
|
mac_pdu pdu_msg;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
#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
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "srsapps/ue/mac/proc.h"
|
||||||
|
|
||||||
|
#ifndef PROCBSR_H
|
||||||
|
#define PROCBSR_H
|
||||||
|
|
||||||
|
/* Buffer status report procedure */
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
class bsr_proc : public proc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void step(uint32_t tti) {
|
||||||
|
if (is_running()) {
|
||||||
|
fprintf(stderr, "BSR procedure not implemented\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
#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
|
@ -0,0 +1,133 @@
|
|||||||
|
|
||||||
|
#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/mac_pdu.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(20) {};
|
||||||
|
bool init(mac_params *params_db, phy *phy_h, log *log_h, 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_contention_resolution();
|
||||||
|
bool is_error();
|
||||||
|
bool in_progress();
|
||||||
|
void pdcch_to_crnti(bool is_ul_grant);
|
||||||
|
void timer_expired(uint32_t timer_id);
|
||||||
|
private:
|
||||||
|
|
||||||
|
void process_timeadv_cmd(uint32_t tti, uint32_t ta_cmd);
|
||||||
|
void step_initialization();
|
||||||
|
void step_resource_selection();
|
||||||
|
void step_preamble_transmission();
|
||||||
|
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];
|
||||||
|
mac_rar_pdu rar_pdu;
|
||||||
|
|
||||||
|
// 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 maxharq_msg3tx;
|
||||||
|
uint32_t contentionResolutionTimer;
|
||||||
|
uint32_t maskIndex;
|
||||||
|
int preambleIndex;
|
||||||
|
|
||||||
|
// Internal variables
|
||||||
|
uint32_t tti;
|
||||||
|
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;
|
||||||
|
uint8_t payload[256]; // 56 bits is often enough
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IDLE = 0,
|
||||||
|
INITIALIZATION, // Section 5.1.1
|
||||||
|
RESOURCE_SELECTION, // Section 5.1.2
|
||||||
|
PREAMBLE_TRANSMISSION, // Section 5.1.3
|
||||||
|
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 *phy_h;
|
||||||
|
log *log_h;
|
||||||
|
mac_params *params_db;
|
||||||
|
timers *timers_db;
|
||||||
|
mux *mux_unit;
|
||||||
|
demux *demux_unit;
|
||||||
|
|
||||||
|
uint64_t received_contention_id;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "srsapps/ue/mac/proc.h"
|
||||||
|
|
||||||
|
#ifndef PROCSR_H
|
||||||
|
#define PROCSR_H
|
||||||
|
|
||||||
|
/* Scheduling Request procedure */
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
class sr_proc : public proc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void step(uint32_t tti) {
|
||||||
|
if (is_running()) {
|
||||||
|
fprintf(stderr, "SR procedure not implemented\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
#include "srsapps/ue/mac/mac_params.h"
|
||||||
|
#include "srsapps/ue/mac/mux.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 {
|
||||||
|
|
||||||
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
class ul_harq_entity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
const static uint32_t NOF_HARQ_PROC = 8;
|
||||||
|
static uint32_t pidof(uint32_t tti);
|
||||||
|
|
||||||
|
ul_harq_entity();
|
||||||
|
~ul_harq_entity();
|
||||||
|
|
||||||
|
bool init(srslte_cell_t cell, uint32_t max_payload_len, log *log_h, timers* timers_, mux *mux_unit);
|
||||||
|
void set_maxHARQ_Tx(uint32_t maxHARQ_Tx, uint32_t maxHARQ_Msg3Tx);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void reset_ndi();
|
||||||
|
bool is_sps(uint32_t pid);
|
||||||
|
void run_tti(uint32_t tti, ul_sched_grant *grant, phy *phy_);
|
||||||
|
void run_tti(uint32_t tti, phy *phy_);
|
||||||
|
bool is_last_retx_msg3();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class ul_harq_process {
|
||||||
|
public:
|
||||||
|
ul_harq_process();
|
||||||
|
bool init(srslte_cell_t cell, uint32_t max_payload_len, ul_harq_entity *parent);
|
||||||
|
void reset();
|
||||||
|
void reset_ndi();
|
||||||
|
void set_maxHARQ_Tx(uint32_t maxHARQ_Tx_, uint32_t maxHARQ_Msg3Tx_);
|
||||||
|
|
||||||
|
void generate_retx(ul_buffer *ul);
|
||||||
|
void generate_retx(ul_sched_grant *ul_grant, ul_buffer *ul);
|
||||||
|
void generate_new_tx(uint8_t *payload, bool is_msg3, ul_sched_grant* grant, ul_buffer *ul);
|
||||||
|
|
||||||
|
bool has_grant();
|
||||||
|
ul_sched_grant *get_grant();
|
||||||
|
void set_harq_feedback(bool ack);
|
||||||
|
bool get_ndi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t current_tx_nb;
|
||||||
|
uint32_t current_irv;
|
||||||
|
bool harq_feedback;
|
||||||
|
bool ndi;
|
||||||
|
srslte::log *log_h;
|
||||||
|
ul_harq_entity *harq_entity;
|
||||||
|
ul_sched_grant cur_grant;
|
||||||
|
uint8_t *payload;
|
||||||
|
uint32_t max_payload_len;
|
||||||
|
bool is_grant_configured;
|
||||||
|
srslte_softbuffer_tx_t softbuffer;
|
||||||
|
uint32_t maxHARQ_Tx, maxHARQ_Msg3Tx;
|
||||||
|
bool is_msg3;
|
||||||
|
|
||||||
|
void generate_tx(ul_buffer* ul);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool last_retx_is_msg3;
|
||||||
|
timers *timers_db;
|
||||||
|
mux *mux_unit;
|
||||||
|
ul_harq_process *proc;
|
||||||
|
srslte::log *log_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#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, sched_grant *grant) {}
|
||||||
|
ul_sched_grant *get_pending_grant(uint32_t tti) { return NULL; }
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
contention_resolution_id = 0;
|
||||||
|
pending_temp_rnti = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void demux::init(phy* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_)
|
||||||
|
{
|
||||||
|
phy_h = phy_h_;
|
||||||
|
log_h = log_h_;
|
||||||
|
mac_io_h = mac_io_h_;
|
||||||
|
timers_db = timers_db_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool demux::is_temp_crnti_pending()
|
||||||
|
{
|
||||||
|
return pending_temp_rnti;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t demux::get_contention_resolution_id()
|
||||||
|
{
|
||||||
|
uint64_t x = contention_resolution_id;
|
||||||
|
contention_resolution_id = 0;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
|
||||||
|
* the MAC in transparent mode
|
||||||
|
*/
|
||||||
|
void demux::push_pdu_bcch(uint32_t tti_, uint8_t *mac_pdu, uint32_t nof_bits)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
mac_io_h->get(mac_io::MAC_LCH_BCCH_DL)->send(mac_pdu, nof_bits);
|
||||||
|
Debug("Pushed BCCH MAC PDU in transparent mode\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
void demux::push_pdu_temp_crnti(uint32_t tti_, uint8_t *mac_pdu, uint32_t nof_bits)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
if (!pending_temp_rnti) {
|
||||||
|
// Unpack DLSCH MAC PDU
|
||||||
|
pending_mac_msg.init(nof_bits);
|
||||||
|
pending_mac_msg.parse_packet(mac_pdu);
|
||||||
|
|
||||||
|
// Look for Contention Resolution UE ID
|
||||||
|
contention_resolution_id = 0;
|
||||||
|
while(pending_mac_msg.read_next()) {
|
||||||
|
if (pending_mac_msg.get()->ce_type() == mac_pdu::mac_subh::CON_RES_ID) {
|
||||||
|
contention_resolution_id = pending_mac_msg.get()->get_con_res_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending_temp_rnti = true;
|
||||||
|
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
|
||||||
|
} else {
|
||||||
|
Warning("Error pushing PDU with Temporal C-RNTI: Another PDU is still in pending\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demultiplexing of logical channels and dissassemble of MAC CE */
|
||||||
|
void demux::push_pdu(uint32_t tti_, uint8_t *mac_pdu, uint32_t nof_bits)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
// Unpack DLSCH MAC PDU
|
||||||
|
mac_msg.init(nof_bits);
|
||||||
|
mac_msg.parse_packet(mac_pdu);
|
||||||
|
process_pdu(&mac_msg);
|
||||||
|
Debug("Normal MAC PDU processed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void demux::demultiplex_pending_pdu(uint32_t tti_)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
if (pending_temp_rnti) {
|
||||||
|
process_pdu(&pending_mac_msg);
|
||||||
|
Debug("Temporal C-RNTI MAC PDU processed\n");
|
||||||
|
pending_temp_rnti = false;
|
||||||
|
pending_mac_msg.reset();
|
||||||
|
} else {
|
||||||
|
Error("Error demultiplex pending PDU: No pending PDU\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void demux::process_pdu(mac_pdu *pdu)
|
||||||
|
{
|
||||||
|
while(pdu->read_next()) {
|
||||||
|
if (pdu->get()->is_sdu()) {
|
||||||
|
// Route logical channel
|
||||||
|
if (pdu->get()->get_sdu_lcid() <= mac_io::MAC_LCH_DTCH2_DL) {
|
||||||
|
qbuff *dest_lch = mac_io_h->get(pdu->get()->get_sdu_lcid());
|
||||||
|
if (dest_lch) {
|
||||||
|
dest_lch->send(pdu->get()->get_sdu_ptr(), pdu->get()->get_sdu_nbytes()*8);
|
||||||
|
Debug("Sent MAC SDU len=%d bytes to lchid=%d\n",
|
||||||
|
pdu->get()->get_sdu_nbytes(), pdu->get()->get_sdu_lcid());
|
||||||
|
} else {
|
||||||
|
Error("Getting destination channel LCID=%d\n", pdu->get()->get_sdu_lcid());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Warning("Received SDU for unsupported LCID=%d\n", pdu->get()->get_sdu_lcid());
|
||||||
|
}
|
||||||
|
// Process MAC Control Element
|
||||||
|
} else {
|
||||||
|
if (!process_ce(pdu->get())) {
|
||||||
|
Warning("Received Subheader with invalid or unkonwn LCID\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool demux::process_ce(mac_pdu::mac_subh *subh) {
|
||||||
|
switch(subh->ce_type()) {
|
||||||
|
case mac_pdu::mac_subh::CON_RES_ID:
|
||||||
|
contention_resolution_id = subh->get_c_rnti();
|
||||||
|
Debug("Saved Contention Resolution ID=%d\n", contention_resolution_id);
|
||||||
|
break;
|
||||||
|
case mac_pdu::mac_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;
|
||||||
|
default:
|
||||||
|
Error("MAC CE not supported\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,194 @@
|
|||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/ue/phy/dl_sched_grant.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()
|
||||||
|
{
|
||||||
|
proc = new dl_harq_process[NOF_HARQ_PROC+1]; // BCCH process is separate
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
|
||||||
|
proc[i].pid = i;
|
||||||
|
}
|
||||||
|
pending_ack_pid = -1;
|
||||||
|
}
|
||||||
|
dl_harq_entity::~dl_harq_entity()
|
||||||
|
{
|
||||||
|
delete proc;
|
||||||
|
}
|
||||||
|
bool dl_harq_entity::init(srslte_cell_t cell, uint32_t max_payload_len, log* log_h_, timers* timers_, demux *demux_unit_)
|
||||||
|
{
|
||||||
|
timers_db = timers_;
|
||||||
|
demux_unit = demux_unit_;
|
||||||
|
log_h = log_h_;
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
|
||||||
|
if (!proc[i].init(cell, max_payload_len, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
bool dl_harq_entity::is_sps(uint32_t pid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void dl_harq_entity::set_harq_info(uint32_t tti, uint32_t pid, dl_sched_grant* grant)
|
||||||
|
{
|
||||||
|
proc[pid%(NOF_HARQ_PROC+1)].set_harq_info(tti, grant);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::receive_data(uint32_t tti, uint32_t pid, dl_buffer* dl_buffer, phy* phy_h)
|
||||||
|
{
|
||||||
|
proc[pid%(NOF_HARQ_PROC+1)].receive_data(tti, dl_buffer, phy_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::reset()
|
||||||
|
{
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
|
||||||
|
proc[i].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dl_harq_entity::is_ack_pending_resolution()
|
||||||
|
{
|
||||||
|
return pending_ack_pid >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::send_pending_ack_contention_resolution()
|
||||||
|
{
|
||||||
|
if (is_ack_pending_resolution()) {
|
||||||
|
proc[pending_ack_pid].send_pending_ack_contention_resolution();
|
||||||
|
pending_ack_pid = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
*
|
||||||
|
* HARQ PROCESS
|
||||||
|
*
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
dl_harq_entity::dl_harq_process::dl_harq_process() : cur_grant(0),pending_ack_grant(0) {
|
||||||
|
is_first_tx = true;
|
||||||
|
is_first_decoded = true;
|
||||||
|
bzero(&cur_grant, sizeof(srslte::ue::dl_sched_grant));
|
||||||
|
payload = NULL;
|
||||||
|
max_payload_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::dl_harq_process::reset() {
|
||||||
|
is_first_tx = true;
|
||||||
|
is_first_decoded = true;
|
||||||
|
bzero(&cur_grant, sizeof(srslte::ue::dl_sched_grant));
|
||||||
|
srslte_softbuffer_rx_reset(&softbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::dl_harq_process::send_pending_ack_contention_resolution()
|
||||||
|
{
|
||||||
|
if (pending_ul_buffer) {
|
||||||
|
pending_ul_buffer->generate_ack(pending_ack, &pending_ack_grant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dl_harq_entity::dl_harq_process::receive_data(uint32_t tti, srslte::ue::dl_buffer *dl_buffer, phy *phy_h)
|
||||||
|
{
|
||||||
|
bool ack = false;
|
||||||
|
pending_ul_buffer = NULL;
|
||||||
|
|
||||||
|
if (payload) {
|
||||||
|
if (cur_grant.get_tbs() <= max_payload_len) {
|
||||||
|
Info("Decoding PDSCH data TBS=%d, RV=%d\n", cur_grant.get_tbs(), cur_grant.get_rv());
|
||||||
|
if (dl_buffer->decode_data(&cur_grant, &softbuffer, payload)) {
|
||||||
|
Info("Decoded OK\n");
|
||||||
|
// RX OK
|
||||||
|
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.get_tbs()/8);
|
||||||
|
if (pid == HARQ_BCCH_PID) {
|
||||||
|
harq_entity->demux_unit->push_pdu_bcch(tti, payload, cur_grant.get_tbs());
|
||||||
|
is_first_tx = true;
|
||||||
|
} else {
|
||||||
|
if (is_first_decoded) {
|
||||||
|
if (cur_grant.is_temp_rnti()) {
|
||||||
|
harq_entity->demux_unit->push_pdu_temp_crnti(tti, payload, cur_grant.get_tbs());
|
||||||
|
} else {
|
||||||
|
harq_entity->demux_unit->push_pdu(tti, payload, cur_grant.get_tbs());
|
||||||
|
}
|
||||||
|
is_first_decoded = false;
|
||||||
|
}
|
||||||
|
ack = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Warning("Decoded Error\n");
|
||||||
|
// RX NOK
|
||||||
|
ack = false;
|
||||||
|
}
|
||||||
|
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) {
|
||||||
|
// Do not generate ACK
|
||||||
|
Debug("Not generating ACK\n");
|
||||||
|
} else {
|
||||||
|
if (cur_grant.is_temp_rnti()) {
|
||||||
|
// Postpone ACK after contention resolution is resolved
|
||||||
|
pending_ack = ack;
|
||||||
|
pending_ul_buffer = phy_h->get_ul_buffer(tti+4);
|
||||||
|
harq_entity->pending_ack_pid = pid;
|
||||||
|
memcpy(&pending_ack_grant, &cur_grant, sizeof(dl_sched_grant));
|
||||||
|
} else {
|
||||||
|
Debug("Generating ACK\n");
|
||||||
|
// Generate ACK
|
||||||
|
srslte::ue::ul_buffer *ul_buffer = phy_h->get_ul_buffer(tti+4);
|
||||||
|
ul_buffer->generate_ack(ack, &cur_grant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error with DL grant. TBS (%d) exceeds payload buffer length (%d)\n", cur_grant.get_tbs(), max_payload_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Implement 5.3.2.2
|
||||||
|
void dl_harq_entity::dl_harq_process::set_harq_info(uint32_t tti, srslte::ue::dl_sched_grant* new_grant) {
|
||||||
|
bool is_new_transmission = false;
|
||||||
|
if (new_grant->get_ndi() && !cur_grant.get_ndi() || is_first_tx) {
|
||||||
|
is_new_transmission = true;
|
||||||
|
is_first_decoded = true;
|
||||||
|
is_first_tx = false;
|
||||||
|
Debug("Set HARQ Info for new transmission\n");
|
||||||
|
} else {
|
||||||
|
is_new_transmission = false;
|
||||||
|
Debug("Set HARQ Info for retransmission\n");
|
||||||
|
}
|
||||||
|
if (is_new_transmission || cur_grant.get_tbs() != new_grant->get_tbs()) {
|
||||||
|
Debug("Reset softbuffer RX\n");
|
||||||
|
srslte_softbuffer_rx_reset(&softbuffer);
|
||||||
|
}
|
||||||
|
if (new_grant->get_tbs() <= max_payload_len) {
|
||||||
|
memcpy(&cur_grant, new_grant, sizeof(srslte::ue::dl_sched_grant));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error with DL grant. TBS (%d) exceeds payload buffer length (%d)\n", new_grant->get_tbs(), max_payload_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool dl_harq_entity::dl_harq_process::init(srslte_cell_t cell, uint32_t max_payload_len_, dl_harq_entity *parent) {
|
||||||
|
max_payload_len = max_payload_len_;
|
||||||
|
if (srslte_softbuffer_rx_init(&softbuffer, cell)) {
|
||||||
|
fprintf(stderr, "Error initiating soft buffer\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
harq_entity = parent;
|
||||||
|
log_h = harq_entity->log_h;
|
||||||
|
payload = (uint8_t*) srslte_vec_malloc(sizeof(uint8_t) * max_payload_len);
|
||||||
|
return payload?true:false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
#include "srsapps/ue/mac/dl_sps.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
dl_sched_grant* dl_sps::get_pending_grant(uint32_t tti)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void dl_sps::reset(uint32_t tti, dl_sched_grant* grant)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void dl_sps::clear()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,460 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 <unistd.h>
|
||||||
|
|
||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
#include "srsapps/ue/mac/mac.h"
|
||||||
|
#include "srsapps/ue/mac/mac_params.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
bool mac::init(phy *phy_h_, tti_sync* ttisync_, log* log_h_)
|
||||||
|
{
|
||||||
|
started = false;
|
||||||
|
ttisync = ttisync_;
|
||||||
|
phy_h = phy_h_;
|
||||||
|
log_h = log_h_;
|
||||||
|
tti = 0;
|
||||||
|
is_synchronized = false;
|
||||||
|
|
||||||
|
mux_unit.init(log_h, &mac_io_lch);
|
||||||
|
demux_unit.init(phy_h, log_h, &mac_io_lch, &timers_db);
|
||||||
|
ra_procedure.init(¶ms_db, phy_h, log_h, &timers_db, &mux_unit, &demux_unit);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (!pthread_create(&mac_thread, NULL, mac_thread_fnc, this)) {
|
||||||
|
started = true;
|
||||||
|
} else {
|
||||||
|
perror("pthread_create");
|
||||||
|
}
|
||||||
|
return started;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac::stop()
|
||||||
|
{
|
||||||
|
started = false;
|
||||||
|
|
||||||
|
pthread_join(mac_thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mac::get_tti()
|
||||||
|
{
|
||||||
|
if (is_synchronized) {
|
||||||
|
return (int) tti;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
params_db.set_param(mac_params::RNTI_TEMP, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mac::mac_thread_fnc(void *arg) {
|
||||||
|
srslte::ue::mac* mac = static_cast<srslte::ue::mac*>(arg);
|
||||||
|
mac->main_radio_loop();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac::main_radio_loop() {
|
||||||
|
setup_timers();
|
||||||
|
while(1) {
|
||||||
|
if (!is_synchronized) {
|
||||||
|
srslte_cell_t cell;
|
||||||
|
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
||||||
|
|
||||||
|
if (phy_h->decode_mib_best(&cell, bch_payload)) {
|
||||||
|
|
||||||
|
// Print MIB
|
||||||
|
srslte_cell_fprint(stdout, &cell, phy_h->get_current_tti()/10);
|
||||||
|
|
||||||
|
// Init HARQ for this cell
|
||||||
|
Info("Init UL/DL HARQ\n");
|
||||||
|
ul_harq.init(cell, 8*1024, log_h, &timers_db, &mux_unit);
|
||||||
|
dl_harq.init(cell, 8*1024, log_h, &timers_db, &demux_unit);
|
||||||
|
|
||||||
|
// Set the current PHY cell to the detected cell
|
||||||
|
Info("Setting up PHY for cell_id=%d\n", cell.id);
|
||||||
|
if (phy_h->set_cell(cell)) {
|
||||||
|
Info("Starting RX streaming\n");
|
||||||
|
if (phy_h->start_rxtx()) {
|
||||||
|
tti = ttisync->wait();
|
||||||
|
Info("Receiver synchronized\n");
|
||||||
|
|
||||||
|
// Send MIB to RRC
|
||||||
|
mac_io_lch.get(mac_io::MAC_LCH_BCCH_DL)->send(bch_payload, SRSLTE_BCH_PAYLOAD_LEN);
|
||||||
|
|
||||||
|
is_synchronized = true;
|
||||||
|
} else {
|
||||||
|
Error("Starting PHY receiver\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Setting PHY cell\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Warning("Cell not found\n");
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
if (is_synchronized) {
|
||||||
|
/* Warning: Here order of invocation of procedures is important!! */
|
||||||
|
|
||||||
|
tti = ttisync->wait();
|
||||||
|
|
||||||
|
// Step all procedures
|
||||||
|
ra_procedure.step(tti);
|
||||||
|
sr_procedure.step(tti);
|
||||||
|
bsr_procedure.step(tti);
|
||||||
|
phr_procedure.step(tti);
|
||||||
|
|
||||||
|
// Receive PCH, if requested
|
||||||
|
receive_pch(tti);
|
||||||
|
|
||||||
|
// Process DL grants always
|
||||||
|
process_dl_grants(tti);
|
||||||
|
|
||||||
|
// Send pending HARQ ACK, if any, and contention resolution is resolved
|
||||||
|
if (dl_harq.is_ack_pending_resolution()) {
|
||||||
|
if (ra_procedure.is_successful()) {
|
||||||
|
Info("Sending pending ACK for contention resolution\n");
|
||||||
|
dl_harq.send_pending_ack_contention_resolution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process UL grants if RA procedure is done or in contention resolution
|
||||||
|
if (ra_procedure.is_successful() || ra_procedure.is_contention_resolution()) {
|
||||||
|
Info("Processing UL grants\n");
|
||||||
|
process_ul_grants(tti);
|
||||||
|
}
|
||||||
|
timers_db.step_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac::setup_timers()
|
||||||
|
{
|
||||||
|
if (params_db.get_param(mac_params::TIMER_TIMEALIGN) > 0) {
|
||||||
|
timers_db.get(TIME_ALIGNMENT)->set(this, params_db.get_param(mac_params::TIMER_TIMEALIGN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static sched_grant::rnti_type_t rnti_type(int rnti_param_id) {
|
||||||
|
switch(rnti_param_id) {
|
||||||
|
case mac_params::RNTI_C:
|
||||||
|
return sched_grant::RNTI_TYPE_CRNTI;
|
||||||
|
case mac_params::RNTI_TEMP:
|
||||||
|
return sched_grant::RNTI_TYPE_TEMP;
|
||||||
|
case mac_params::RNTI_SPS:
|
||||||
|
return sched_grant::RNTI_TYPE_SPS;
|
||||||
|
case mac_params::RNTI_RA:
|
||||||
|
return sched_grant::RNTI_TYPE_RA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mac::get_harq_sps_pid(uint32_t tti) {
|
||||||
|
uint32_t nof_proc = ((uint32_t) params_db.get_param(mac_params::SPS_DL_NOF_PROC));
|
||||||
|
return tti/params_db.get_param(mac_params::SPS_DL_SCHED_INTERVAL)%nof_proc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
dl_sps_assig.clear();
|
||||||
|
ul_sps_assig.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive PCH when requested as defined in Section 5.5
|
||||||
|
void mac::receive_pch(uint32_t tti) {
|
||||||
|
if (params_db.get_param(mac_params::PCCH_RECEIVE)) {
|
||||||
|
dl_buffer *dl_buffer = phy_h->get_dl_buffer(tti);
|
||||||
|
dl_sched_grant pch_grant(sched_grant::RNTI_TYPE_PRNTI, SRSLTE_PRNTI);
|
||||||
|
if (dl_buffer->get_dl_grant(&pch_grant)) {
|
||||||
|
qbuff *pcch_buff = mac_io_lch.get(mac_io::MAC_LCH_PCCH_DL);
|
||||||
|
uint8_t *ptr = (uint8_t*) pcch_buff->request();
|
||||||
|
if (ptr && pch_grant.get_tbs() <= mac_io_lch.DEFAULT_MSG_SZ) {
|
||||||
|
if (dl_buffer->decode_data(&pch_grant, ptr)) {
|
||||||
|
pcch_buff->release();
|
||||||
|
} else {
|
||||||
|
Warning("Error decoding PCH\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Error getting pointer from PCCH buffer\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Debug("No P-RNTI grant found while looking for PCH messages\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function controls DL Grant Assignment as specified in Section 5.3.1 in 36.321
|
||||||
|
* and issues commands to DL harq operation
|
||||||
|
*/
|
||||||
|
void mac::process_dl_grants(uint32_t tti) {
|
||||||
|
// Get DL buffer for this TTI
|
||||||
|
dl_buffer *dl_buffer = phy_h->get_dl_buffer(tti);
|
||||||
|
|
||||||
|
// 5.3.1 DL Assignment reception
|
||||||
|
for (int i = mac_params::RNTI_C;i<=mac_params::RNTI_RA;i++) {
|
||||||
|
// Check C-RNTI, SPS-RNTI and Temporal RNTI
|
||||||
|
if (params_db.get_param(i) != 0) {
|
||||||
|
Info("Searching DL grants for RNTI: %d\n", params_db.get_param(i));
|
||||||
|
dl_sched_grant ue_grant(rnti_type(i), params_db.get_param(i));
|
||||||
|
if (dl_buffer->get_dl_grant(&ue_grant)) {
|
||||||
|
// If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it
|
||||||
|
if (ra_procedure.is_contention_resolution() && i == mac_params::RNTI_C) {
|
||||||
|
ra_procedure.pdcch_to_crnti(false);
|
||||||
|
}
|
||||||
|
if (i != mac_params::RNTI_SPS) {
|
||||||
|
uint32_t harq_pid = ue_grant.get_harq_process();
|
||||||
|
if (i == mac_params::RNTI_TEMP) {
|
||||||
|
ue_grant.set_ndi(is_first_temporal);
|
||||||
|
is_first_temporal = false;
|
||||||
|
}
|
||||||
|
if (i == mac_params::RNTI_C && dl_harq.is_sps(harq_pid)) {
|
||||||
|
ue_grant.set_ndi(true);
|
||||||
|
}
|
||||||
|
dl_harq.set_harq_info(tti, harq_pid, &ue_grant);
|
||||||
|
dl_harq.receive_data(tti, harq_pid, dl_buffer, phy_h);
|
||||||
|
} else {
|
||||||
|
uint32_t harq_pid = get_harq_sps_pid(tti);
|
||||||
|
if (ue_grant.get_ndi()) {
|
||||||
|
ue_grant.set_ndi(false);
|
||||||
|
dl_harq.set_harq_info(tti, harq_pid, &ue_grant);
|
||||||
|
dl_harq.receive_data(tti, harq_pid, dl_buffer, phy_h);
|
||||||
|
} else {
|
||||||
|
if (ue_grant.is_sps_release()) {
|
||||||
|
dl_sps_assig.clear();
|
||||||
|
if (timers_db.get(TIME_ALIGNMENT)->is_running()) {
|
||||||
|
//phy_h->send_sps_ack();
|
||||||
|
Warning("PHY Send SPS ACK not implemented\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dl_sps_assig.reset(tti, &ue_grant);
|
||||||
|
ue_grant.set_ndi(true);
|
||||||
|
dl_harq.set_harq_info(tti, harq_pid, &ue_grant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Process configured DL assingments (SPS) */
|
||||||
|
dl_sched_grant *sps_grant = dl_sps_assig.get_pending_grant(tti);
|
||||||
|
if (sps_grant != NULL) {
|
||||||
|
Info("Processing SPS grant\n");
|
||||||
|
uint32_t harq_pid = get_harq_sps_pid(tti);
|
||||||
|
sps_grant->set_ndi(true);
|
||||||
|
dl_harq.set_harq_info(tti, harq_pid, sps_grant);
|
||||||
|
dl_harq.receive_data(tti, harq_pid, dl_buffer, phy_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process SI-RNTI */
|
||||||
|
uint32_t si_window_start = params_db.get_param(mac_params::BCCH_SI_WINDOW_ST);
|
||||||
|
uint32_t si_window_length = params_db.get_param(mac_params::BCCH_SI_WINDOW_LEN);
|
||||||
|
|
||||||
|
if (tti >= si_window_start && tti < (si_window_start + si_window_length)) {
|
||||||
|
// Exclude subf 5 and sfn%2==0 unless it's a SIB1 message (window_length=1) (This is defined in 36.331 Sec 5.2.3)
|
||||||
|
if (!(phy_h->tti_to_subf(si_window_length) != 1 &&
|
||||||
|
phy_h->tti_to_subf(si_window_start) == 5 && (phy_h->tti_to_SFN(tti)%2) == 0))
|
||||||
|
{
|
||||||
|
Info("Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
|
||||||
|
dl_sched_grant si_grant(sched_grant::RNTI_TYPE_SIRNTI, SRSLTE_SIRNTI);
|
||||||
|
if (dl_buffer->get_dl_grant(&si_grant)) {
|
||||||
|
uint32_t k;
|
||||||
|
if (phy_h->tti_to_subf(si_window_start) == 5) { // This is SIB1, k is different
|
||||||
|
k = (phy_h->tti_to_SFN(tti)/2)%4;
|
||||||
|
} else {
|
||||||
|
k = phy_h->tti_to_subf(tti)%4;
|
||||||
|
}
|
||||||
|
si_grant.set_rv(((uint32_t) ceilf((float)1.5*k))%4);
|
||||||
|
Info("DL grant found, sending to HARQ with RV: %d\n", si_grant.get_rv());
|
||||||
|
dl_harq.set_harq_info(tti, dl_harq_entity::HARQ_BCCH_PID, &si_grant);
|
||||||
|
dl_harq.receive_data(tti, dl_harq_entity::HARQ_BCCH_PID, dl_buffer, phy_h);
|
||||||
|
params_db.set_param(mac_params::BCCH_SI_WINDOW_ST, 0);
|
||||||
|
params_db.set_param(mac_params::BCCH_SI_WINDOW_LEN, 0);
|
||||||
|
} else {
|
||||||
|
Warning("DL grant not found\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UL Grant reception and processin as defined in Section 5.4.1 in 36.321 */
|
||||||
|
void mac::process_ul_grants(uint32_t tti) {
|
||||||
|
// Get DL buffer for this TTI to look for DCI grants
|
||||||
|
dl_buffer *dl_buffer = phy_h->get_dl_buffer(tti);
|
||||||
|
|
||||||
|
//if (timers_db.get(TIME_ALIGNMENT)->is_running()) {
|
||||||
|
if (1) {
|
||||||
|
for (int i = mac_params::RNTI_C;i<=mac_params::RNTI_TEMP;i++) {
|
||||||
|
// Check C-RNTI, SPS-RNTI and Temporal C-RNTI
|
||||||
|
if (params_db.get_param(i) != 0) {
|
||||||
|
ul_sched_grant ul_grant(rnti_type(i), params_db.get_param(i));
|
||||||
|
if (dl_buffer->get_ul_grant(&ul_grant)) {
|
||||||
|
if (ra_procedure.is_contention_resolution() && i == mac_params::RNTI_C) {
|
||||||
|
ra_procedure.pdcch_to_crnti(true);
|
||||||
|
}
|
||||||
|
if (i == mac_params::RNTI_C || i == mac_params::RNTI_TEMP || ra_procedure.is_running()) {
|
||||||
|
if (i == mac_params::RNTI_C && ul_harq.is_sps(tti))
|
||||||
|
ul_grant.set_ndi(true);
|
||||||
|
ul_harq.run_tti(tti, &ul_grant, phy_h);
|
||||||
|
if (i == mac_params::RNTI_TEMP) {
|
||||||
|
// Discard already processed RAR grant
|
||||||
|
dl_buffer->discard_pending_rar_grant();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (i == mac_params::RNTI_SPS) {
|
||||||
|
if (ul_grant.get_ndi()) {
|
||||||
|
ul_grant.set_ndi(false);
|
||||||
|
ul_harq.run_tti(tti, &ul_grant, phy_h);
|
||||||
|
} else {
|
||||||
|
if (ul_grant.is_sps_release()) {
|
||||||
|
ul_sps_assig.clear();
|
||||||
|
} else {
|
||||||
|
ul_sps_assig.reset(tti, &ul_grant);
|
||||||
|
ul_grant.set_ndi(true);
|
||||||
|
ul_harq.run_tti(tti, &ul_grant, phy_h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Process configured UL assingments (SPS) */
|
||||||
|
ul_sched_grant *sps_grant = ul_sps_assig.get_pending_grant(tti);
|
||||||
|
if (sps_grant != NULL) {
|
||||||
|
sps_grant->set_ndi(true);
|
||||||
|
ul_harq.run_tti(tti, sps_grant, phy_h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul_harq.run_tti(tti, phy_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mac::recv_bcch_sdu(uint8_t* sdu_payload, uint32_t buffer_len_nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_BCCH_DL)->recv(sdu_payload, buffer_len_nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mac::recv_ccch_sdu(uint8_t* sdu_payload, uint32_t buffer_len_nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_CCCH_DL)->recv(sdu_payload, buffer_len_nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mac::recv_dtch0_sdu(uint8_t* sdu_payload, uint32_t buffer_len_nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_DTCH0_DL)->recv(sdu_payload, buffer_len_nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mac::recv_dcch0_sdu(uint8_t* sdu_payload, uint32_t buffer_len_nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_DTCH0_DL)->recv(sdu_payload, buffer_len_nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mac::send_ccch_sdu(uint8_t* sdu_payload, uint32_t nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_CCCH_UL)->send(sdu_payload, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mac::send_dtch0_sdu(uint8_t* sdu_payload, uint32_t nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_DTCH0_UL)->send(sdu_payload, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mac::send_dcch0_sdu(uint8_t* sdu_payload, uint32_t nbytes)
|
||||||
|
{
|
||||||
|
return mac_io_lch.get(mac_io::MAC_LCH_DCCH0_UL)->send(sdu_payload, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac::set_param(mac_params::mac_param_t param, int64_t value)
|
||||||
|
{
|
||||||
|
params_db.set_param((uint32_t) param, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac::set_dcch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD)
|
||||||
|
{
|
||||||
|
mux_unit.set_priority(mac_io::MAC_LCH_DCCH0_UL - mac_io::MAC_LCH_CCCH_UL, priority, PBR_x_tti, BSD);
|
||||||
|
}
|
||||||
|
void mac::set_dtch0_priority(uint32_t priority, int PBR_x_tti, uint32_t BSD)
|
||||||
|
{
|
||||||
|
mux_unit.set_priority(mac_io::MAC_LCH_DTCH0_UL - mac_io::MAC_LCH_CCCH_UL, priority, PBR_x_tti, BSD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
#include "srsapps/ue/mac/mac_pdu.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
mac_pdu::mac_subh* mac_pdu::get()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_pdu::init(uint32_t pdu_len)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
mac_pdu::mac_pdu(uint32_t max_subheaders)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
mac_pdu::mac_subh::cetype mac_pdu::mac_subh::ce_type()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint16_t mac_pdu::mac_subh::get_c_rnti()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint64_t mac_pdu::mac_subh::get_con_res_id()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint8_t mac_pdu::mac_subh::get_phd()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint32_t mac_pdu::mac_subh::get_sdu_lcid()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint32_t mac_pdu::mac_subh::get_sdu_nbytes()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint8_t* mac_pdu::mac_subh::get_sdu_ptr()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint8_t mac_pdu::mac_subh::get_ta_cmd()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::is_sdu()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::set_c_rnti(uint16_t crnti)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::set_con_res_id(uint64_t con_res_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::set_phd(uint8_t phd)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::set_sdu(uint8_t* ptr, uint32_t nof_bytes)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::mac_subh::set_ta_cmd(uint8_t ta_cmd)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_pdu::parse_packet(uint8_t* ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::read_next()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_pdu::reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::write_next()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_pdu::write_packet(uint8_t* ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mac_rar_pdu::mac_rar* mac_rar_pdu::get()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint8_t mac_rar_pdu::get_backoff()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::init(uint32_t pdu_len)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_rar_pdu::is_backoff()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint32_t mac_rar_pdu::mac_rar::get_rapid()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::mac_rar::get_sched_grant(uint8_t grant[])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint32_t mac_rar_pdu::mac_rar::get_ta_cmd()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
uint16_t mac_rar_pdu::mac_rar::get_temp_crnti()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::mac_rar::set_rapid(uint32_t rapid)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::mac_rar::set_sched_grant(uint8_t grant[])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::mac_rar::set_ta_cmd(uint32_t ta)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::mac_rar::set_temp_crnti(uint16_t temp_rnti)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
mac_rar_pdu::mac_rar_pdu(uint32_t max_rars)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::parse_packet(uint8_t* ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_rar_pdu::read_next()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void mac_rar_pdu::set_backoff(uint8_t bi)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_rar_pdu::write_next()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mac_rar_pdu::write_packet(uint8_t* ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef kk
|
||||||
|
bool demux::lcid_is_lch(uint32_t lcid) {
|
||||||
|
if (lcid <= LIBLTE_MAC_DLSCH_DCCH_LCID_END) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
#include "srsapps/ue/mac/mux.h"
|
||||||
|
#include "srsapps/ue/mac/mac.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
#define IO_IDX(lch) (lch + mac_io::MAC_LCH_CCCH_UL)
|
||||||
|
#define UL_IDX(lch) (lch - mac_io::MAC_LCH_CCCH_UL)
|
||||||
|
|
||||||
|
mux::mux() : pdu_msg(20)
|
||||||
|
{
|
||||||
|
msg3_buff.init(1, MSG3_BUFF_SZ);
|
||||||
|
pdu_buff.init(1, PDU_BUFF_SZ);
|
||||||
|
bzero(nof_tx_pkts, sizeof(uint32_t) * mac_io::NOF_UL_LCH);
|
||||||
|
pthread_mutex_init(&mutex, NULL);
|
||||||
|
|
||||||
|
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
|
||||||
|
priority[i] = 1;
|
||||||
|
priority_sorted[i] = 1;
|
||||||
|
PBR[i] = -1; // -1 is infinite
|
||||||
|
BSD[i] = 10;
|
||||||
|
lchid_sorted[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux::init(log *log_h_, mac_io *mac_io_h_)
|
||||||
|
{
|
||||||
|
log_h = log_h_;
|
||||||
|
mac_io_h = mac_io_h_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux::reset()
|
||||||
|
{
|
||||||
|
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
|
||||||
|
Bj[i] = 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 < mac_io::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 < mac_io::NOF_UL_LCH) {
|
||||||
|
new_index++;
|
||||||
|
}
|
||||||
|
int old_index = 0;
|
||||||
|
while(lch_id != lchid_sorted[old_index] && new_index < mac_io::NOF_UL_LCH) {
|
||||||
|
old_index++;
|
||||||
|
}
|
||||||
|
if (new_index == mac_io::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux::pdu_release()
|
||||||
|
{
|
||||||
|
pdu_buff.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mux::pdu_move_to_msg3(uint32_t tti_, uint32_t pdu_sz)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
if (pdu_buff.isempty()) {
|
||||||
|
if (assemble_pdu(pdu_sz)) {
|
||||||
|
if (pdu_buff.pending_data() < MSG3_BUFF_SZ) {
|
||||||
|
pdu_buff.move_to(&msg3_buff);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
pdu_buff.release();
|
||||||
|
Error("Assembled PDU size exceeds Msg3 buffer size\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Assembling PDU\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Generating PDU: PDU pending in buffer for transmission\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplexing and logical channel priorization as defined in Section 5.4.3
|
||||||
|
uint8_t* mux::pdu_pop(uint32_t tti_, uint32_t pdu_sz)
|
||||||
|
{
|
||||||
|
tti = tti_;
|
||||||
|
if (pdu_buff.isempty()) {
|
||||||
|
if (assemble_pdu(pdu_sz)) {
|
||||||
|
return (uint8_t*) pdu_buff.pop();
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Generating PDU: PDU pending in buffer for transmission\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux::append_crnti_ce_next_tx(uint16_t crnti) {
|
||||||
|
pending_crnti_ce = crnti;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mux::assemble_pdu(uint32_t pdu_sz) {
|
||||||
|
|
||||||
|
uint8_t *buff = (uint8_t*) pdu_buff.request();
|
||||||
|
if (!buff) {
|
||||||
|
Error("Assembling PDU: Buffer is not available\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure pdu_sz is byte-aligned
|
||||||
|
pdu_sz = 8*(pdu_sz/8);
|
||||||
|
|
||||||
|
// Acquire mutex. Cannot change priorities, PBR or BSD after assemble finishes
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
|
||||||
|
// Update Bj
|
||||||
|
for (int i=0;i=mac_io::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
|
||||||
|
|
||||||
|
uint32_t sdu_sz = 0;
|
||||||
|
|
||||||
|
pdu_msg.init(pdu_sz);
|
||||||
|
|
||||||
|
// MAC control element for C-RNTI or data from UL-CCCH
|
||||||
|
if (!allocate_sdu(UL_IDX(mac_io::MAC_LCH_CCCH_UL), &pdu_msg)) {
|
||||||
|
if (pending_crnti_ce) {
|
||||||
|
if (pdu_msg.write_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;
|
||||||
|
|
||||||
|
// MAC control element for BSR, with exception of BSR included for padding;
|
||||||
|
// TODO
|
||||||
|
// MAC control element for PHR
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// data from any Logical Channel, except data from UL-CCCH;
|
||||||
|
// first only those with positive Bj
|
||||||
|
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
|
||||||
|
bool res = true;
|
||||||
|
while ((Bj[i] > 0 || PBR[i] < 0) && res) {
|
||||||
|
res = allocate_sdu(lchid_sorted[i], &pdu_msg, &sdu_sz);
|
||||||
|
if (res && PBR[i] >= 0) {
|
||||||
|
Bj[i] -= sdu_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If resources remain, allocate regardless of their Bj value
|
||||||
|
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
|
||||||
|
while (allocate_sdu(lchid_sorted[i], &pdu_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAC control element for BSR included for padding.
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
|
/* Release SDUs */
|
||||||
|
for (int i=0;i<mac_io::NOF_UL_LCH;i++) {
|
||||||
|
while(nof_tx_pkts[i] > 0) {
|
||||||
|
mac_io_h->get(IO_IDX(i))->release();
|
||||||
|
nof_tx_pkts[i]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate MAC PDU and save to buffer */
|
||||||
|
if (pdu_msg.write_packet(buff)) {
|
||||||
|
pdu_buff.push(pdu_sz);
|
||||||
|
} else {
|
||||||
|
Error("Writing PDU message to packet\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mux::allocate_sdu(uint32_t lcid, mac_pdu *pdu)
|
||||||
|
{
|
||||||
|
return allocate_sdu(lcid, pdu, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mux::allocate_sdu(uint32_t lcid, mac_pdu *pdu, uint32_t *sdu_sz)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Get n-th pending SDU pointer and length
|
||||||
|
uint32_t buff_len;
|
||||||
|
uint8_t *buff_ptr = (uint8_t*) mac_io_h->get(lcid)->pop(&buff_len, nof_tx_pkts[lcid]);
|
||||||
|
|
||||||
|
if (buff_ptr) { // there is pending SDU to allocate
|
||||||
|
if (pdu->write_next()) { // there is space for a new subheader
|
||||||
|
if (pdu->get()->set_sdu(buff_ptr, buff_len)) { // new SDU could be added
|
||||||
|
// Increase number of pop'ed packets from queue
|
||||||
|
nof_tx_pkts[lcid]++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mux::msg3_flush()
|
||||||
|
{
|
||||||
|
msg3_buff.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mux::msg3_isempty()
|
||||||
|
{
|
||||||
|
return msg3_buff.isempty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to the Msg3 buffer */
|
||||||
|
uint8_t* mux::msg3_pop(uint32_t tti, uint32_t TB_size)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
uint8_t *msg3 = (uint8_t*) msg3_buff.pop(&len);
|
||||||
|
if (len < TB_size) {
|
||||||
|
// Pad with zeros without exceeding maximum buffer size
|
||||||
|
if (TB_size <= MSG3_BUFF_SZ) {
|
||||||
|
bzero(&msg3[len], (TB_size-len)*sizeof(uint8_t));
|
||||||
|
} else {
|
||||||
|
Error("Requested TB size from Msg3 buffer exceeds buffer size (%d>%d)\n", TB_size, MSG3_BUFF_SZ);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux::msg3_release()
|
||||||
|
{
|
||||||
|
msg3_buff.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,442 @@
|
|||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "srsapps/ue/mac/mac_params.h"
|
||||||
|
#include "srsapps/ue/mac/mac_io.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(mac_params* params_db_, phy* phy_h_, srslte::log* log_h_, srslte::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_;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::reset() {
|
||||||
|
state = IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::read_params() {
|
||||||
|
|
||||||
|
// Read initialization parameters
|
||||||
|
configIndex = params_db->get_param(mac_params::RA_CONFIGINDEX);
|
||||||
|
preambleIndex = params_db->get_param(mac_params::RA_PREAMBLEINDEX);
|
||||||
|
maskIndex = params_db->get_param(mac_params::RA_MASKINDEX);
|
||||||
|
nof_preambles = params_db->get_param(mac_params::RA_NOFPREAMBLES);
|
||||||
|
if (!nof_preambles || nof_preambles > 64) {
|
||||||
|
nof_preambles = 64;
|
||||||
|
}
|
||||||
|
nof_groupA_preambles = params_db->get_param(mac_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_params::RA_MESSAGEPOWEROFFSETB);
|
||||||
|
messageSizeGroupA = params_db->get_param(mac_params::RA_MESSAGESIZEA);
|
||||||
|
Pcmax = params_db->get_param(mac_params::RA_PCMAX);
|
||||||
|
deltaPreambleMsg3 = params_db->get_param(mac_params::RA_DELTAPREAMBLEMSG3);
|
||||||
|
}
|
||||||
|
responseWindowSize = params_db->get_param(mac_params::RA_RESPONSEWINDOW);
|
||||||
|
powerRampingStep = params_db->get_param(mac_params::RA_POWERRAMPINGSTEP);
|
||||||
|
preambleTransMax = params_db->get_param(mac_params::RA_PREAMBLETRANSMAX);
|
||||||
|
iniReceivedTargetPower = params_db->get_param(mac_params::RA_INITRECEIVEDPOWER);
|
||||||
|
maxharq_msg3tx = params_db->get_param(mac_params::RA_MAXTXMSG3);
|
||||||
|
contentionResolutionTimer = params_db->get_param(mac_params::RA_CONTENTIONTIMER);
|
||||||
|
|
||||||
|
delta_preamble_db = delta_preamble_db_table[configIndex];
|
||||||
|
|
||||||
|
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_contention_resolution() {
|
||||||
|
return state == CONTENTION_RESOLUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ra_proc::is_error() {
|
||||||
|
return state == RA_PROBLEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t interval(uint32_t x1, uint32_t x2) {
|
||||||
|
if (x1 > x2) {
|
||||||
|
return x1-x2;
|
||||||
|
} else {
|
||||||
|
return 10240-x2+x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* state_str[10] = {"Idle",
|
||||||
|
"RA Initializat.: ",
|
||||||
|
"RA ResSelection: ",
|
||||||
|
"RA PreambleTx : ",
|
||||||
|
"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 tti, 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;
|
||||||
|
received_contention_id = 0;
|
||||||
|
transmitted_contention_id = 0;
|
||||||
|
preambleTransmissionCounter = 1;
|
||||||
|
first_rar_received = true;
|
||||||
|
mux_unit->msg3_flush();
|
||||||
|
backoff_param_ms = 0;
|
||||||
|
phy_h->init_prach();
|
||||||
|
state = RESOURCE_SELECTION;
|
||||||
|
rInfo("Done\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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->send_prach(sel_preamble, sel_maskIndex - 1, received_target_power_dbm);
|
||||||
|
rInfo("Selected received_target_power_dbm=%d dBm\n", received_target_power_dbm);
|
||||||
|
state = RESPONSE_RECEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step_response_reception() {
|
||||||
|
int ra_tti = phy_h->get_prach_transmitted_tti();
|
||||||
|
if (ra_tti > 0) {
|
||||||
|
|
||||||
|
ra_rnti = 1+ra_tti%10; // f_id=0 for FDD
|
||||||
|
dl_sched_grant rar_grant(ra_rnti);
|
||||||
|
uint32_t interval_ra = interval(tti, ra_tti);
|
||||||
|
|
||||||
|
// Try to decode RAR only within the RA response window
|
||||||
|
if (interval_ra >= 3 && interval_ra <= 3+responseWindowSize) {
|
||||||
|
|
||||||
|
// Get DL grant for RA-RNTI
|
||||||
|
dl_buffer *dl_buffer = phy_h->get_dl_buffer(tti);
|
||||||
|
if (dl_buffer->get_dl_grant(&rar_grant))
|
||||||
|
{
|
||||||
|
rInfo("DL grant found RA-RNTI=%d\n", ra_rnti);
|
||||||
|
|
||||||
|
if (rar_grant.get_tbs() > MAX_RAR_PDU_LEN) {
|
||||||
|
rError("RAR PDU exceeds local RAR PDU buffer (%d>%d)\n", rar_grant.get_tbs(), MAX_RAR_PDU_LEN);
|
||||||
|
state = RESPONSE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode packet
|
||||||
|
if (dl_buffer->decode_data(&rar_grant, rar_pdu_buffer)) {
|
||||||
|
rar_pdu.init(rar_grant.get_tbs());
|
||||||
|
|
||||||
|
// Set Backoff parameter
|
||||||
|
if (rar_pdu.is_backoff()) {
|
||||||
|
backoff_param_ms = backoff_table[rar_pdu.get_backoff()%16];
|
||||||
|
} else {
|
||||||
|
backoff_param_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(rar_pdu.read_next()) {
|
||||||
|
if (rar_pdu.get()->get_rapid() == sel_preamble) {
|
||||||
|
rInfo("Received RAPID=%d\n", sel_preamble);
|
||||||
|
|
||||||
|
process_timeadv_cmd(tti, rar_pdu.get()->get_ta_cmd());
|
||||||
|
|
||||||
|
// FIXME: Indicate received target power
|
||||||
|
//phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep);
|
||||||
|
|
||||||
|
// Indicate grant to PHY layer. RAR grants have 6 sf delay (4 is the default delay)
|
||||||
|
uint8_t grant[mac_rar_pdu::mac_rar::RAR_GRANT_LEN];
|
||||||
|
rar_pdu.get()->get_sched_grant(grant);
|
||||||
|
phy_h->get_dl_buffer(tti+2)->set_rar_grant(grant);
|
||||||
|
|
||||||
|
if (preambleIndex > 0) {
|
||||||
|
// Preamble selected by Network
|
||||||
|
state = COMPLETION;
|
||||||
|
} else {
|
||||||
|
// Preamble selected by UE MAC
|
||||||
|
params_db->set_param(mac_params::RNTI_TEMP, rar_pdu.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_params::RNTI_C);
|
||||||
|
|
||||||
|
// Save transmitted UE contention id, as defined by higher layers
|
||||||
|
transmitted_contention_id = params_db->get_param(mac_params::CONTENTION_ID);
|
||||||
|
params_db->set_param(mac_params::CONTENTION_ID, 0);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get TransportBlock size for the grant
|
||||||
|
ul_sched_grant msg3_grant(rar_pdu.get()->get_temp_crnti());
|
||||||
|
phy_h->get_dl_buffer(tti+2)->get_ul_grant(&msg3_grant);
|
||||||
|
|
||||||
|
// Move MAC PDU from Multiplexing and assembly unit to Msg3
|
||||||
|
mux_unit->pdu_move_to_msg3(tti, msg3_grant.get_tbs()); // 56 is the minimum grant provided
|
||||||
|
|
||||||
|
state = CONTENTION_RESOLUTION;
|
||||||
|
|
||||||
|
// Start contention resolution timer
|
||||||
|
timers_db->get(mac::CONTENTION_TIMER)->reset();
|
||||||
|
timers_db->get(mac::CONTENTION_TIMER)->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (interval_ra > 3+responseWindowSize && interval_ra < 10000) {
|
||||||
|
rInfo("Timeout while trying to receive RAR\n");
|
||||||
|
state = RESPONSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step_response_error() {
|
||||||
|
mux_unit->msg3_flush();
|
||||||
|
|
||||||
|
preambleTransmissionCounter++;
|
||||||
|
if (preambleTransmissionCounter == preambleTransMax + 1) {
|
||||||
|
rError("Maximum number of transmissions reached (%d)\n", preambleTransMax);
|
||||||
|
state = RA_PROBLEM;
|
||||||
|
} else {
|
||||||
|
backoff_interval_start = 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\n");
|
||||||
|
state = RESOURCE_SELECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step_backoff_wait() {
|
||||||
|
if (interval(tti, backoff_interval_start) >= backoff_inteval) {
|
||||||
|
state = RESOURCE_SELECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step_contention_resolution() {
|
||||||
|
// If Msg3 has been sent
|
||||||
|
if (mux_unit->msg3_isempty()) {
|
||||||
|
msg3_transmitted = true;
|
||||||
|
if (pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)
|
||||||
|
{
|
||||||
|
// 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_params::RNTI_TEMP, 0);
|
||||||
|
state = COMPLETION;
|
||||||
|
}
|
||||||
|
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
|
||||||
|
|
||||||
|
} else if (demux_unit->is_temp_crnti_pending())
|
||||||
|
{
|
||||||
|
// Random Access initiated by RRC by the transmission of CCCH SDU
|
||||||
|
received_contention_id = demux_unit->get_contention_resolution_id();
|
||||||
|
if (received_contention_id) {
|
||||||
|
// MAC PDU successfully decoded and contains MAC CE contention Id
|
||||||
|
if (transmitted_contention_id == received_contention_id) {
|
||||||
|
|
||||||
|
// UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3
|
||||||
|
timers_db->get(mac::CONTENTION_TIMER)->stop();
|
||||||
|
params_db->set_param(mac_params::RNTI_C, params_db->get_param(mac_params::RNTI_TEMP));
|
||||||
|
|
||||||
|
// finish the disassembly and demultiplexing of the MAC PDU
|
||||||
|
demux_unit->demultiplex_pending_pdu(tti);
|
||||||
|
state = COMPLETION;
|
||||||
|
} else {
|
||||||
|
// Discard MAC PDU
|
||||||
|
state = RESPONSE_ERROR;
|
||||||
|
}
|
||||||
|
params_db->set_param(mac_params::RNTI_TEMP, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step_completition() {
|
||||||
|
params_db->set_param(mac_params::RA_PREAMBLEINDEX, 0);
|
||||||
|
params_db->set_param(mac_params::RA_MASKINDEX, 0);
|
||||||
|
mux_unit->msg3_flush();
|
||||||
|
msg3_transmitted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::step(uint32_t tti_)
|
||||||
|
{
|
||||||
|
tti = 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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::start_pdcch_order()
|
||||||
|
{
|
||||||
|
if (state == IDLE || state == COMPLETION || state == RA_PROBLEM) {
|
||||||
|
start_mode = PDCCH_ORDER;
|
||||||
|
state = INITIALIZATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ra_proc::start_rlc_order()
|
||||||
|
{
|
||||||
|
if (state == IDLE || state == COMPLETION || state == RA_PROBLEM) {
|
||||||
|
start_mode = RLC_ORDER;
|
||||||
|
state = INITIALIZATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contention Resolution Timer is expired (Section 5.1.5)
|
||||||
|
void ra_proc::timer_expired(uint32_t timer_id)
|
||||||
|
{
|
||||||
|
params_db->set_param(mac_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,241 @@
|
|||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/common/log.h"
|
||||||
|
|
||||||
|
#include "srsapps/ue/mac/mac.h"
|
||||||
|
#include "srsapps/ue/mac/ul_harq.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
namespace ue {
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
*
|
||||||
|
* HARQ ENTITY
|
||||||
|
*
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
ul_harq_entity::ul_harq_entity() {
|
||||||
|
proc = new ul_harq_process[NOF_HARQ_PROC]; // BCCH process is separate
|
||||||
|
}
|
||||||
|
ul_harq_entity::~ul_harq_entity() {
|
||||||
|
delete proc;
|
||||||
|
}
|
||||||
|
bool ul_harq_entity::init(srslte_cell_t cell, uint32_t max_payload_len, log *log_h_, timers *timers_db_, mux *mux_unit_) {
|
||||||
|
log_h = log_h_;
|
||||||
|
mux_unit = mux_unit_;
|
||||||
|
timers_db = timers_db_;
|
||||||
|
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
|
||||||
|
if (!proc[i].init(cell, max_payload_len, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void ul_harq_entity::set_maxHARQ_Tx(uint32_t maxHARQ_Tx, uint32_t maxHARQ_Msg3Tx) {
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
|
||||||
|
proc[i].set_maxHARQ_Tx(maxHARQ_Tx, maxHARQ_Msg3Tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t ul_harq_entity::pidof(uint32_t tti) {
|
||||||
|
return tti%NOF_HARQ_PROC;
|
||||||
|
}
|
||||||
|
void ul_harq_entity::reset() {
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
|
||||||
|
proc[i].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ul_harq_entity::reset_ndi() {
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
|
||||||
|
proc[i].reset_ndi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool ul_harq_entity::is_sps(uint32_t pid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ul_harq_entity::run_tti(uint32_t tti, phy *phy_) {
|
||||||
|
run_tti(tti, NULL, phy_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Section 5.4.2.1
|
||||||
|
void ul_harq_entity::run_tti(uint32_t tti, ul_sched_grant *grant, phy *phy_h)
|
||||||
|
{
|
||||||
|
uint32_t pid = pidof(tti);
|
||||||
|
last_retx_is_msg3 = false;
|
||||||
|
|
||||||
|
if (grant) {
|
||||||
|
if ((grant->is_temp_rnti() && grant->get_ndi() != proc[pid].get_ndi()) ||
|
||||||
|
(grant->is_crnti() && !proc[pid].has_grant()) ||
|
||||||
|
grant->is_from_rar())
|
||||||
|
{
|
||||||
|
// New transmission
|
||||||
|
uint8_t* msg3_ptr = (uint8_t*) mux_unit->msg3_pop(tti, grant->get_tbs());
|
||||||
|
|
||||||
|
// Uplink grant in a RAR
|
||||||
|
if (msg3_ptr && grant->is_from_rar()) {
|
||||||
|
proc[pid].generate_new_tx(msg3_ptr, true, grant, phy_h->get_ul_buffer(tti+4));
|
||||||
|
mux_unit->msg3_release();
|
||||||
|
|
||||||
|
// Normal UL grant
|
||||||
|
} else {
|
||||||
|
// Request a MAC PDU from the Multiplexing & Assemble Unit
|
||||||
|
uint8_t* mac_pdu = mux_unit->pdu_pop(tti, grant->get_tbs());
|
||||||
|
if (mac_pdu) {
|
||||||
|
proc[pid].generate_new_tx(mac_pdu, false, grant, phy_h->get_ul_buffer(tti+4));
|
||||||
|
mux_unit->pdu_release();
|
||||||
|
} else {
|
||||||
|
Warning("Uplink grant with MAC PDU available in Multiplex Unit\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Adaptive Re-TX
|
||||||
|
proc[pid].generate_retx(grant, phy_h->get_ul_buffer(tti+4));
|
||||||
|
}
|
||||||
|
} else if (proc[pid].has_grant()) {
|
||||||
|
// Non-Adaptive Re-Tx
|
||||||
|
proc[pid].generate_retx(phy_h->get_ul_buffer(tti+4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive and route HARQ feedbacks
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
|
||||||
|
if (proc[pid].has_grant()) {
|
||||||
|
proc[pid].set_harq_feedback(phy_h->get_dl_buffer(tti)->decode_ack(proc[pid].get_grant()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ul_harq_entity::is_last_retx_msg3()
|
||||||
|
{
|
||||||
|
return last_retx_is_msg3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
*
|
||||||
|
* 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() : cur_grant(0) {
|
||||||
|
payload = NULL;
|
||||||
|
max_payload_len = 0;
|
||||||
|
current_tx_nb = 0;
|
||||||
|
current_irv = 0;
|
||||||
|
is_grant_configured = false;
|
||||||
|
bzero(&cur_grant, sizeof(ul_sched_grant));
|
||||||
|
}
|
||||||
|
void ul_harq_entity::ul_harq_process::reset() {
|
||||||
|
current_tx_nb = 0;
|
||||||
|
current_irv = 0;
|
||||||
|
is_grant_configured = false;
|
||||||
|
bzero(&cur_grant, sizeof(ul_sched_grant));
|
||||||
|
srslte_softbuffer_tx_reset(&softbuffer);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul_sched_grant* ul_harq_entity::ul_harq_process::get_grant()
|
||||||
|
{
|
||||||
|
return &cur_grant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ul_harq_entity::ul_harq_process::set_harq_feedback(bool ack) {
|
||||||
|
harq_feedback = ack;
|
||||||
|
}
|
||||||
|
void ul_harq_entity::ul_harq_process::set_maxHARQ_Tx(uint32_t maxHARQ_Tx_, uint32_t maxHARQ_Msg3Tx_) {
|
||||||
|
maxHARQ_Tx = maxHARQ_Tx_;
|
||||||
|
maxHARQ_Msg3Tx = maxHARQ_Msg3Tx_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ul_harq_entity::ul_harq_process::init(srslte_cell_t cell, uint32_t max_payload_len_, ul_harq_entity *parent) {
|
||||||
|
max_payload_len = max_payload_len_;
|
||||||
|
if (srslte_softbuffer_tx_init(&softbuffer, cell)) {
|
||||||
|
fprintf(stderr, "Error initiating soft buffer\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
harq_entity = parent;
|
||||||
|
log_h = harq_entity->log_h;
|
||||||
|
payload = (uint8_t*) srslte_vec_malloc(sizeof(uint8_t) * max_payload_len);
|
||||||
|
return payload?true:false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retransmission with or w/o grant (Section 5.4.2.2)
|
||||||
|
void ul_harq_entity::ul_harq_process::generate_retx(ul_sched_grant* grant, ul_buffer* ul)
|
||||||
|
{
|
||||||
|
current_tx_nb++;
|
||||||
|
|
||||||
|
if (grant) {
|
||||||
|
// HARQ entity requests an adaptive transmission
|
||||||
|
memcpy(&cur_grant, grant, sizeof(grant));
|
||||||
|
current_irv = irv_of_rv[grant->get_rv()%4];
|
||||||
|
harq_feedback = false;
|
||||||
|
generate_tx(ul);
|
||||||
|
} else {
|
||||||
|
// HARQ entity requests a non-adaptive transmission
|
||||||
|
if (!harq_feedback) {
|
||||||
|
generate_tx(ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(uint8_t *pdu_payload, bool is_msg3_, ul_sched_grant* ul_grant, ul_buffer* ul)
|
||||||
|
{
|
||||||
|
if (ul_grant && pdu_payload && ul_grant->get_tbs() < max_payload_len) {
|
||||||
|
current_tx_nb = 0;
|
||||||
|
current_irv = 0;
|
||||||
|
// Store MAC PDU in the HARQ buffer
|
||||||
|
srslte_bit_pack_vector(pdu_payload, payload, ul_grant->get_tbs());
|
||||||
|
// Store the uplink grant
|
||||||
|
memcpy(&cur_grant, ul_grant, sizeof(ul_grant));
|
||||||
|
harq_feedback = false;
|
||||||
|
generate_tx(ul);
|
||||||
|
is_grant_configured = true;
|
||||||
|
is_msg3 = is_msg3_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ul_harq_entity::ul_harq_process::generate_retx(ul_buffer* ul)
|
||||||
|
{
|
||||||
|
generate_retx(NULL, ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmission of pending frame (Section 5.4.2.2)
|
||||||
|
void ul_harq_entity::ul_harq_process::generate_tx(ul_buffer* ul)
|
||||||
|
{
|
||||||
|
cur_grant.set_rv(rv_of_irv[current_irv%4]);
|
||||||
|
ul->set_current_tx_nb(current_tx_nb);
|
||||||
|
ul->generate_data(&cur_grant, &softbuffer, payload);
|
||||||
|
current_irv = (current_irv+1)%4;
|
||||||
|
if (is_msg3) {
|
||||||
|
if (current_tx_nb == maxHARQ_Msg3Tx) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (current_tx_nb == maxHARQ_Tx) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,283 @@
|
|||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "liblte_rrc.h"
|
||||||
|
#include "srsapps/radio/radio_uhd.h"
|
||||||
|
#include "srsapps/ue/phy/phy.h"
|
||||||
|
#include "srsapps/common/tti_sync_cv.h"
|
||||||
|
#include "srsapps/common/log_stdout.h"
|
||||||
|
#include "srsapps/ue/mac/mac.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Program arguments processing
|
||||||
|
***********************************************************************/
|
||||||
|
typedef struct {
|
||||||
|
float uhd_rx_freq;
|
||||||
|
float uhd_tx_freq;
|
||||||
|
float uhd_rx_gain;
|
||||||
|
float uhd_tx_gain;
|
||||||
|
}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 = 60.0;
|
||||||
|
args->uhd_tx_gain = 60.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(prog_args_t *args, char *prog) {
|
||||||
|
printf("Usage: %s [gv] -f rx_frequency (in Hz) -F tx_frequency (in Hz)\n", prog);
|
||||||
|
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_rx_gain);
|
||||||
|
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_tx_gain);
|
||||||
|
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, "gGfFv")) != -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 'v':
|
||||||
|
srslte_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_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_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_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_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_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_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_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_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_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_params::RA_MAXTXMSG3,
|
||||||
|
sib2->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx);
|
||||||
|
|
||||||
|
printf("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%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]);
|
||||||
|
|
||||||
|
// PDSCH ConfigCommon
|
||||||
|
mac->set_param(srslte::ue::mac_params::PDSCH_RSPOWER,
|
||||||
|
sib2->rr_config_common_sib.pdsch_cnfg.rs_power);
|
||||||
|
mac->set_param(srslte::ue::mac_params::PDSCH_PB,
|
||||||
|
sib2->rr_config_common_sib.pdsch_cnfg.p_b);
|
||||||
|
|
||||||
|
// PUSCH ConfigCommon
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUSCH_EN_64QAM,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.enable_64_qam);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUSCH_HOPPING_OFFSET,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUSCH_HOPPING_N_SB,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.n_sb);
|
||||||
|
phy->set_param(srslte::ue::phy_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_params::PUSCH_RS_GROUP_HOPPING_EN,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled?1:0);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUSCH_RS_SEQUENCE_HOPPING_EN,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled?1:0);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUSCH_RS_CYCLIC_SHIFT,
|
||||||
|
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift);
|
||||||
|
phy->set_param(srslte::ue::phy_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",
|
||||||
|
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);
|
||||||
|
|
||||||
|
// PUCCH ConfigCommon
|
||||||
|
phy->set_param(srslte::ue::phy_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_params::PUCCH_CYCLIC_SHIFT,
|
||||||
|
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PUCCH_N_PUCCH_1,
|
||||||
|
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an);
|
||||||
|
phy->set_param(srslte::ue::phy_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_params::PRACH_ROOT_SEQ_IDX,
|
||||||
|
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index);
|
||||||
|
phy->set_param(srslte::ue::phy_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_params::PRACH_FREQ_OFFSET,
|
||||||
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset);
|
||||||
|
phy->set_param(srslte::ue::phy_params::PRACH_ZC_CONFIG,
|
||||||
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config);
|
||||||
|
phy->set_param(srslte::ue::phy_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
prog_args_t prog_args;
|
||||||
|
srslte::ue::tti_sync_cv ttisync(10240);
|
||||||
|
srslte::radio_uhd radio_uhd;
|
||||||
|
srslte::ue::phy phy;
|
||||||
|
srslte::ue::mac mac;
|
||||||
|
srslte::log_stdout log("MAC");
|
||||||
|
|
||||||
|
parse_args(&prog_args, argc, argv);
|
||||||
|
|
||||||
|
// Init Radio
|
||||||
|
radio_uhd.init();
|
||||||
|
|
||||||
|
// Init PHY
|
||||||
|
phy.init(&radio_uhd, &ttisync);
|
||||||
|
|
||||||
|
// Init MAC
|
||||||
|
mac.init(&phy, &ttisync, &log);
|
||||||
|
|
||||||
|
// Set RX freq and gain
|
||||||
|
radio_uhd.set_rx_freq(prog_args.uhd_rx_freq);
|
||||||
|
radio_uhd.set_rx_gain(prog_args.uhd_rx_gain);
|
||||||
|
radio_uhd.set_tx_freq(prog_args.uhd_tx_freq);
|
||||||
|
radio_uhd.set_tx_gain(prog_args.uhd_tx_gain);
|
||||||
|
|
||||||
|
LIBLTE_BIT_MSG_STRUCT bit_msg;
|
||||||
|
LIBLTE_RRC_MIB_STRUCT bch_msg;
|
||||||
|
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
|
||||||
|
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
|
||||||
|
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
|
||||||
|
|
||||||
|
uint32_t si_window_len, sib2_period;
|
||||||
|
int tti;
|
||||||
|
enum {START, SIB1, SIB2, CONNECT} state = START;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
switch(state) {
|
||||||
|
case START:
|
||||||
|
n = mac.recv_bcch_sdu(bit_msg.msg, LIBLTE_MAX_MSG_SIZE);
|
||||||
|
if (n > 0) {
|
||||||
|
bit_msg.N_bits = n;
|
||||||
|
liblte_rrc_unpack_bcch_bch_msg(&bit_msg, &bch_msg);
|
||||||
|
printf("MIB received %d bytes, BW=%s\n", n, liblte_rrc_dl_bandwidth_text[bch_msg.dl_bw]);
|
||||||
|
state = SIB1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIB1:
|
||||||
|
n = mac.recv_bcch_sdu(bit_msg.msg, LIBLTE_MAX_MSG_SIZE);
|
||||||
|
if (n > 0) {
|
||||||
|
bit_msg.N_bits = n;
|
||||||
|
liblte_rrc_unpack_bcch_dlsch_msg(&bit_msg, &dlsch_msg);
|
||||||
|
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",
|
||||||
|
n/8, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
|
||||||
|
printf("Payload: ");
|
||||||
|
srslte_vec_fprint_hex(stdout, bit_msg.msg, n);
|
||||||
|
state = SIB2;
|
||||||
|
} else {
|
||||||
|
tti = mac.get_tti();
|
||||||
|
mac.set_param(srslte::ue::mac_params::BCCH_SI_WINDOW_ST, sib_start_tti(tti, 2, 5));
|
||||||
|
mac.set_param(srslte::ue::mac_params::BCCH_SI_WINDOW_LEN, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIB2:
|
||||||
|
n = mac.recv_bcch_sdu(bit_msg.msg, LIBLTE_MAX_MSG_SIZE);
|
||||||
|
if (n > 0) {
|
||||||
|
// Process SIB2
|
||||||
|
bit_msg.N_bits = n;
|
||||||
|
liblte_rrc_unpack_bcch_dlsch_msg(&bit_msg, &dlsch_msg);
|
||||||
|
printf("SIB2 received %d bytes\n", n/8);
|
||||||
|
printf("Payload: ");
|
||||||
|
srslte_vec_fprint_hex(stdout, bit_msg.msg, n);
|
||||||
|
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
|
||||||
|
|
||||||
|
// 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_DATA;
|
||||||
|
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, &bit_msg);
|
||||||
|
|
||||||
|
mac.set_param(srslte::ue::mac_params::CONTENTION_ID, ul_ccch_msg.msg.rrc_con_req.ue_id.random);
|
||||||
|
|
||||||
|
// Send ConnectionRequest Packet
|
||||||
|
mac.send_ccch_sdu(bit_msg.msg, bit_msg.N_bits);
|
||||||
|
state = CONNECT;
|
||||||
|
} else {
|
||||||
|
tti = mac.get_tti();
|
||||||
|
mac.set_param(srslte::ue::mac_params::BCCH_SI_WINDOW_ST, sib_start_tti(tti, sib2_period, 0));
|
||||||
|
mac.set_param(srslte::ue::mac_params::BCCH_SI_WINDOW_LEN, si_window_len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONNECT:
|
||||||
|
// Waint for Connection Setup
|
||||||
|
n = mac.recv_ccch_sdu(bit_msg.msg, LIBLTE_MAX_MSG_SIZE);
|
||||||
|
if (n > 0) {
|
||||||
|
printf("ConnSetup received %d bytes\n", n/8);
|
||||||
|
bit_msg.N_bits = n;
|
||||||
|
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]);
|
||||||
|
if (dl_ccch_msg.msg_type == LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP) {
|
||||||
|
// Process ConnectionRequest
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(50000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 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 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/.
|
||||||
|
#
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "src/*.cc")
|
||||||
|
ADD_LIBRARY(srsapps_ue_phy SHARED ${SOURCES})
|
||||||
|
TARGET_LINK_LIBRARIES(srsapps_ue_phy srsapps_common)
|
||||||
|
INSTALL(TARGETS srsapps_ue_phy DESTINATION ${LIBRARY_DIR})
|
||||||
|
LIBLTE_SET_PIC(srsapps_ue_phy)
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES "include/srsapps/ue/phy/*.h")
|
||||||
|
ADD_CUSTOM_TARGET (add_ue_phy_headers SOURCES ${HEADERS_ALL})
|
||||||
|
|
||||||
|
ADD_SUBDIRECTORY(test)
|
||||||
|
|
Loading…
Reference in New Issue