Working on phy itf

This commit is contained in:
ismagom 2015-04-05 15:36:20 +02:00
parent 5588791695
commit f02ffe66f0
20 changed files with 1486 additions and 841 deletions

View File

@ -46,7 +46,4 @@ ADD_CUSTOM_TARGET (add_srslte_headers SOURCES ${HEADERS_ALL})
########################################################################
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(examples)
add_subdirectory(tutorial_examples)
add_subdirectory(itf)

View File

@ -0,0 +1,82 @@
/**
*
* \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/srslte.h"
#include "srslte/ue_itf/queue.h"
#include "srslte/ue_itf/sched_grant.h"
#include "srslte/ue_itf/params.h"
#ifndef UEDLBUFFER_H
#define UEDLBUFFER_H
namespace srslte {
namespace ue {
/* Class for the processing of Downlink buffers. The MAC obtains a buffer for a given TTI and then
* gets ul/dl scheduling grants and/or processes phich/pdsch channels
*/
class SRSLTE_API dl_buffer : public queue::element {
public:
typedef enum {
PDCCH_UL_SEARCH_CRNTI = 0,
PDCCH_UL_SEARCH_RA_PROC,
PDCCH_UL_SEARCH_SPS,
PDCCH_UL_SEARCH_TEMPORAL,
PDCCH_UL_SEARCH_TPC_PUSCH,
PDCCH_UL_SEARCH_TPC_PUCCH
} pdcch_ul_search_t;
typedef enum {
PDCCH_DL_SEARCH_CRNTI = 0,
PDCCH_DL_SEARCH_SIRNTI,
PDCCH_DL_SEARCH_PRNTI,
PDCCH_DL_SEARCH_RARNTI,
PDCCH_DL_SEARCH_TEMPORAL,
PDCCH_DL_SEARCH_SPS
} pdcch_dl_search_t;
bool init_cell(srslte_cell_t cell, params *params_db);
void free_cell();
bool recv_ue_sync(srslte_ue_sync_t *ue_sync, srslte_timestamp_t *rx_time);
bool get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, sched_grant *grant);
bool get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, sched_grant *grant);
bool decode_phich(srslte_phich_alloc_t assignment);
bool decode_pdsch(sched_grant pdsch_grant, uint8_t *payload); // returns true or false for CRC OK/KO
private:
params *params_db;
srslte_cell_t cell;
srslte_ue_dl_t ue_dl;
srslte_phich_t phich;
cf_t *signal_buffer;
uint32_t cfi;
bool sf_symbols_and_ce_done;
bool pdcch_llr_extracted;
uint32_t tti;
};
}
}
#endif

View File

@ -0,0 +1,81 @@
/**
*
* \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/srslte.h"
#ifndef UEH
#define UEH
namespace srslte {
namespace ue {
class SRSLTE_API params
{
public:
typedef enum {
DL_FREQ = 0,
UL_FREQ,
CELLSEARCH_TIMEOUT_PSS_NFRAMES,
CELLSEARCH_TIMEOUT_MIB_NFRAMES,
CELLSEARCH_FORCE_N_ID_2,
CELLSEARCH_CORRELATION_THRESHOLD, // integer that will be divided by 10
PUSCH_BETA,
PUSCH_RS_GROUP_HOPPING_EN,
PUSCH_RS_SEQUENCE_HOPPING_EN,
PUSCH_RS_CYCLIC_SHIFT,
PUSCH_RS_GROUP_ASSIGNMENT,
PUSCH_HOPPING_N_SB,
PUSCH_HOPPING_INTRA_SF,
PUSCH_HOPPING_OFFSET,
UCI_I_OFFSET_ACK,
UCI_I_OFFSET_RI,
UCI_I_OFFSET_CQI,
PRACH_CONFIG_INDEX,
PRACH_ROOT_SEQ_IDX,
PRACH_HIGH_SPEED_FLAG,
PRACH_ZC_CONFIG,
PRACH_FREQ_OFFSET,
NOF_PARAMS,
} param_t;
void set_param(param_t param, int64_t value);
int64_t get_param(param_t param);
private:
int64_t params_db[NOF_PARAMS];
};
}
}
#endif

View File

@ -0,0 +1,114 @@
/**
*
* \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/srslte.h"
#include "srslte/ue_itf/dl_buffer.h"
#include "srslte/ue_itf/ul_buffer.h"
#include "srslte/ue_itf/prach.h"
#include "srslte/ue_itf/params.h"
#include "srslte/ue_itf/sched_grant.h"
#include "srslte/ue_itf/queue.h"
#ifndef UEPHY_H
#define UEPHY_H
#define SYNC_MODE_CV 0
#define SYNC_MODE_CALLBACK 1
#define SYNC_MODE SYNC_MODE_CALLBACK
namespace srslte {
namespace ue {
typedef _Complex float cf_t;
class SRSLTE_API phy
{
public:
#if SYNC_MODE==SYNC_MODE_CALLBACK
typedef void (*ue_phy_callback_t) (void);
ue_phy_callback_t tti_clock_callback;
ue_phy_callback_t status_change;
phy(ue_phy_callback_t tti_clock_callback, ue_phy_callback_t status_change);
#else
phy();
#endif
~phy();
void measure(); // TBD
void dl_bch();
void start_rxtx();
void stop_rxtx();
void send_prach(uint32_t preamble_idx);
bool status_is_idle();
bool status_is_rxtx();
bool status_is_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]);
uint32_t get_tti();
#if SYNC_MODE==SYNC_MODE_CV
std::condition_variable tti_cv;
std::mutex tti_mutex;
#endif
ul_buffer* get_ul_buffer(uint32_t tti);
dl_buffer* get_dl_buffer(uint32_t tti);
void main_radio_loop();
private:
enum {
IDLE, MEASURE, RX_BCH, MIB_DECODED, RXTX
} phy_state;
srslte_cell_t cell;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
bool is_sfn_synched = false;
bool started = false;
uint32_t current_tti;
srslte_ue_sync_t ue_sync;
srslte_ue_mib_t ue_mib;
queue *ul_buffer_queue;
queue *dl_buffer_queue;
prach prach_buffer;
params params_db;
pthread_t radio_thread;
void *radio_handler;
static void *radio_thread_fnc(void *arg);
void run_rx_bch_state();
bool rx_bch();
int sync_sfn();
void run_rx_tx_state();
};
}
}
#endif

View File

@ -0,0 +1,56 @@
/**
*
* \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/srslte.h"
#include "srslte/ue_itf/queue.h"
#include "srslte/ue_itf/params.h"
#ifndef UEPRACH_H
#define UEPRACH_H
namespace srslte {
namespace ue {
class SRSLTE_API prach {
public:
bool init_cell(srslte_cell_t cell, params *params_db);
void free_cell();
bool ready_to_send(uint32_t preamble_idx);
bool is_ready_to_send(uint32_t current_tti);
bool send(void *radio_handler, srslte_timestamp_t rx_time);
private:
params *params_db;
int preamble_idx;
bool initiated = false;
uint32_t len;
cf_t *buffer[64];
srslte_prach_t prach;
};
}
}
#endif

View File

@ -25,11 +25,14 @@
*
*/
#include <stdint.h>
#ifndef QUEUE_H
#define QUEUE_H
namespace srslte {
namespace ue {
class queue
{
public:
@ -82,5 +85,5 @@ private:
};
}
}
#endif

View File

@ -0,0 +1,66 @@
/**
*
* \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/srslte.h"
#include "queue.h"
#ifndef UESCHEDGRANT_H
#define UESCHEDGRANT_H
namespace srslte {
namespace ue {
/* Uplink/Downlink scheduling grant generated by a successfully decoded PDCCH */
class SRSLTE_API sched_grant {
public:
typedef enum {DOWNLINK=0, UPLINK=1} direction_t;
uint16_t get_rnti();
uint32_t get_rv();
void set_rv(uint32_t rv);
bool get_ndi();
uint32_t get_current_tti();
bool get_cqi_request();
int get_harq_process();
bool is_uplink();
bool is_downlink();
void* get_grant_ptr();
protected:
union {
srslte_ra_pusch_t ul_grant;
srslte_ra_pdsch_t dl_grant;
};
direction_t dir;
uint16_t rnti;
uint32_t current_tti;
};
}
}
#endif

View File

@ -0,0 +1,65 @@
/**
*
* \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/srslte.h"
#include "srslte/ue_itf/queue.h"
#include "srslte/ue_itf/sched_grant.h"
#include "srslte/ue_itf/params.h"
#ifndef UEULBUFFER_H
#define UEULBUFFER_H
namespace srslte {
namespace ue {
/* Uplink scheduling assignment. The MAC instructs the PHY to prepare an UL packet (PUSCH or PUCCH)
* for transmission. The MAC must call generate_pusch() to set the packet ready for transmission
*/
class SRSLTE_API ul_buffer : public queue::element {
public:
bool init_cell(srslte_cell_t cell, params *params_db);
void free_cell();
void set_tti(uint32_t tti);
void set_current_tx_nb(uint32_t current_tx_nb);
bool generate_pusch(sched_grant pusch_grant, uint8_t *payload, srslte_uci_data_t uci_data);
bool generate_pucch(srslte_uci_data_t uci_data);
bool send_packet(void *radio_handler, srslte_timestamp_t rx_time);
private:
params *params_db;
srslte_cell_t cell;
srslte_ue_ul_t ue_ul;
bool signal_generated;
cf_t* signal_buffer;
uint32_t tti;
uint32_t current_tx_nb;
};
}
}
#endif

View File

@ -1,577 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "ue_phy.h"
/*
* CLASS SCHED_GRANT
*
*/
/* Returns the RNTI associated with the UL/DL scheduling grant */
uint16_t srslte::ue_phy::sched_grant::get_rnti() {
return rnti;
}
uint32_t srslte::ue_phy::sched_grant::get_rv() {
if (dir == UPLINK) {
return ul_grant.rv_idx;
} else {
return dl_grant.rv_idx;
}
}
void srslte::ue_phy::sched_grant::set_rv(uint32_t rv) {
if (dir == UPLINK) {
ul_grant.rv_idx = rv;
} else {
dl_grant.rv_idx = rv;
}
}
bool srslte::ue_phy::sched_grant::get_ndi() {
if (dir == UPLINK) {
return ul_grant.ndi;
} else {
return dl_grant.ndi;
}
}
bool srslte::ue_phy::sched_grant::get_cqi_request() {
if (dir == UPLINK) {
return ul_grant.ndi;
} else {
return dl_grant.ndi;
}
}
uint32_t srslte::ue_phy::sched_grant::get_current_tti() {
return current_tti;
}
int srslte::ue_phy::sched_grant::get_harq_process() {
if (dir == UPLINK) {
return -1;
} else {
return dl_grant.harq_process;
}
}
bool srslte::ue_phy::sched_grant::is_uplink() {
return dir == UPLINK;
}
bool srslte::ue_phy::sched_grant::is_downlink() {
return dir == DOWNLINK;
}
void* srslte::ue_phy::sched_grant::get_grant_ptr() {
if (is_uplink()) {
return (void*) &ul_grant;
} else {
return (void*) &dl_grant;
}
}
/*
* CLASS UL_BUFFER
*
*/
bool srslte::ue_phy::ul_buffer::init_cell(srslte_cell_t cell_, int64_t *params_db_) {
cell = cell_;
params_db = params_db_;
signal_generated = false;
current_tx_nb = 0;
if (!srslte_ue_ul_init(&ue_ul, cell)) {
signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
return signal_buffer?true:false;
} else {
return false;
}
}
void srslte::ue_phy::ul_buffer::free_cell() {
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_ul_free(&ue_ul);
}
bool srslte::ue_phy::ul_buffer::generate_pusch(sched_grant pusch_grant,
uint8_t *payload,
srslte_uci_data_t uci_data)
{
if (pusch_grant.is_uplink()) {
fprintf(stderr, "Invalid scheduling grant. Grant is for Downlink\n");
return false;
}
srslte_refsignal_drms_pusch_cfg_t drms_cfg;
bzero(&drms_cfg, sizeof(srslte_refsignal_drms_pusch_cfg_t));
drms_cfg.beta_pusch = params_db[PARAM_PUSCH_BETA];
drms_cfg.group_hopping_en = params_db[PARAM_PUSCH_RS_GROUP_HOPPING_EN];
drms_cfg.sequence_hopping_en = params_db[PARAM_PUSCH_RS_SEQUENCE_HOPPING_EN];
drms_cfg.cyclic_shift = params_db[PARAM_PUSCH_RS_CYCLIC_SHIFT];
drms_cfg.delta_ss = params_db[PARAM_PUSCH_RS_GROUP_ASSIGNMENT];
srslte_pusch_hopping_cfg_t pusch_hopping;
pusch_hopping.n_sb = params_db[PARAM_PUSCH_HOPPING_N_SB];
pusch_hopping.hop_mode = params_db[PARAM_PUSCH_HOPPING_INTRA_SF] ?
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF :
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
pusch_hopping.hopping_offset = params_db[PARAM_PUSCH_HOPPING_OFFSET];
pusch_hopping.current_tx_nb = current_tx_nb;
srslte_ue_ul_set_pusch_cfg(&ue_ul, &drms_cfg, &pusch_hopping);
int n = srslte_ue_ul_pusch_uci_encode_rnti(&ue_ul, (srslte_ra_pusch_t*) pusch_grant.get_grant_ptr(),
payload, uci_data,
tti%10, pusch_grant.get_rnti(),
signal_buffer);
if (n < 0) {
fprintf(stderr, "Error encoding PUSCH\n");
return false;
}
signal_generated = true;
/* This is done by the transmission thread
srslte_vec_sc_prod_cfc(signal_buffer, beta_pusch, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
float time_adv_sec = TA_OFFSET + ((float) n_ta)*LTE_TS;
srslte_timestamp_t next_tx_time;
srslte_timestamp_copy(&next_tx_time, &last_rx_time);
srslte_timestamp_add(&next_tx_time, 0, 0.003 - time_adv_sec);
*/
// Send through radio
return true;
}
bool srslte::ue_phy::ul_buffer::generate_pucch(srslte_uci_data_t uci_data)
{
return false;
}
/*
* CLASS DL_BUFFER
*
*/
bool srslte::ue_phy::dl_buffer::init_cell(srslte_cell_t cell_, int64_t *params_db_)
{
params_db = params_db_;
cell = cell_;
sf_symbols_and_ce_done = false;
pdcch_llr_extracted = false;
tti = 0;
if (srslte_ue_dl_init(&ue_dl, cell)) {
signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
return signal_buffer?true:false;
} else {
return false;
}
}
void srslte::ue_phy::dl_buffer::free_cell()
{
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_dl_free(&ue_dl);
}
bool srslte::ue_phy::dl_buffer::get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
if (!pdcch_llr_extracted) {
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
return false;
}
pdcch_llr_extracted = true;
}
srslte_dci_msg_t dci_msg;
if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) {
return false;
}
if (srslte_dci_msg_to_ra_ul(&dci_msg, cell.nof_prb,
params_db[PARAM_PUSCH_HOPPING_OFFSET],
(srslte_ra_pusch_t*) grant->get_grant_ptr()))
{
return false;
}
return true;
}
bool srslte::ue_phy::dl_buffer::get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
if (!pdcch_llr_extracted) {
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
return false;
}
pdcch_llr_extracted = true;
}
srslte_dci_msg_t dci_msg;
if (srslte_ue_dl_find_dl_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) {
return false;
}
if (srslte_dci_msg_to_ra_dl(&dci_msg, rnti, cell, cfi,
(srslte_ra_pdsch_t*) grant->get_grant_ptr()))
{
return false;
}
return true;
}
bool srslte::ue_phy::dl_buffer::decode_phich(srslte_phich_alloc_t assignment)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
return false;
}
bool srslte::ue_phy::dl_buffer::decode_pdsch(sched_grant pdsch_grant, uint8_t *payload)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
srslte_ra_pdsch_t *ra_dl = (srslte_ra_pdsch_t*) pdsch_grant.get_grant_ptr();
if (srslte_harq_setup_dl(&ue_dl.harq_process[0], ra_dl->mcs,
pdsch_grant.get_rv(), tti%10, &ra_dl->prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
return SRSLTE_ERROR;
}
if (ue_dl.harq_process[0].mcs.mod > 0 && ue_dl.harq_process[0].mcs.tbs >= 0) {
int ret = srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.harq_process[0], ue_dl.sf_symbols,
ue_dl.ce, 0, pdsch_grant.get_rnti(), payload);
if (ret == SRSLTE_SUCCESS) {
return true;
}
}
return false;
}
/*
* CLASS UE_PHY
*
*/
#if SYNC_MODE==SYNC_MODE_CALLBACK
srslte::ue_phy::ue_phy(ue_phy_callback_t tti_clock_callback_, ue_phy_callback_t status_change_)
{
tti_clock_callback = tti_clock_callback_;
status_change = status_change_;
ul_buffer_queue = new queue(6, sizeof(ul_buffer));
dl_buffer_queue = new queue(6, sizeof(dl_buffer));
started = true;
pthread_create(&radio_thread, NULL, radio_thread_fnc, this);
}
#else
srslte::ue_phy::ue_phy()
{
}
#endif
srslte::ue_phy::~ue_phy()
{
started = false;
pthread_join(radio_thread, NULL);
delete ul_buffer_queue;
delete dl_buffer_queue;
if (prach_initiated) {
for (uint32_t i=0;i<64;i++) {
if (prach_buffer[i]) {
free(prach_buffer[i]);
}
}
srslte_prach_free(&prach);
}
}
bool srslte::ue_phy::init_prach()
{
if (srslte_prach_init(&prach, srslte_symbol_sz(cell.nof_prb),
srslte_prach_get_preamble_format(params_db[PARAMS_PRACH_CONFIG_INDEX]),
params_db[PARAMS_PRACH_ROOT_SEQ_IDX],
params_db[PARAMS_PRACH_HIGH_SPEED_FLAG]?true:false,
params_db[PARAMS_PRACH_ZC_CONFIG])) {
return false;
}
prach_len = prach.N_seq + prach.N_cp;
for (uint32_t i=0;i<64;i++) {
prach_buffer[i] = (cf_t*) srslte_vec_malloc(prach_len*sizeof(cf_t));
if(!prach_buffer[i]) {
return false;
}
if(srslte_prach_gen(&prach, i, params_db[PARAMS_PRACH_FREQ_OFFSET], prach_buffer[i])){
return false;
}
}
prach_initiated = true;
return true;
}
// FIXME: Add PRACH power control
void srslte::ue_phy::send_prach(uint32_t preamble_idx)
{
if (prach_initiated && phy_state == RXTX) {
prach_ready_to_send = true;
}
}
// Do fast measurement on RSSI and/or PSS autocorrelation energy or PSR
void srslte::ue_phy::measure()
{
if (phy_state == IDLE) {
// capture and do measurement
status_change();
}
}
void srslte::ue_phy::dl_bch()
{
if (phy_state == IDLE) {
phy_state = RX_BCH;
status_change();
}
}
void srslte::ue_phy::start_rxtx()
{
if (phy_state == MIB_DECODED) {
// Set sampling freq to MIB PRB
// start radio streaming
phy_state = RXTX;
status_change();
}
}
void srslte::ue_phy::stop_rxtx()
{
// stop radio
phy_state = IDLE;
status_change();
}
bool srslte::ue_phy::status_is_idle() {
return phy_state == IDLE;
}
bool srslte::ue_phy::status_is_rxtx() {
return phy_state == RXTX;
}
bool srslte::ue_phy::status_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN])
{
if (phy_state == MIB_DECODED) {
memcpy(payload, bch_payload, SRSLTE_BCH_PAYLOAD_LEN*sizeof(uint8_t));
}
}
static void* radio_thread_fnc(void *arg) {
srslte::ue_phy* ue_phy = (srslte::ue_phy*) arg;
ue_phy->main_radio_loop();
return NULL;
}
int radio_recv_wrapper_cs(void*,void*,uint32_t,srslte_timestamp_t*);
bool srslte::ue_phy::rx_bch()
{
srslte_ue_cellsearch_result_t found_cells[3];
srslte_ue_cellsearch_t cs;
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, radio_recv_wrapper_cs, radio_handler)) {
return false;
}
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, params_db[PARAM_CELLSEARCH_TIMEOUT_PSS_NFRAMES]);
srslte_ue_cellsearch_set_threshold(&cs, (float) params_db[PARAM_CELLSEARCH_CORRELATION_THRESHOLD]/10);
// set sampling freq 1.92 MHz
// set frequency, gain etc
// start radio streaming
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
int ret = SRSLTE_ERROR;
uint32_t force_N_id_2 = params_db[PARAM_CELLSEARCH_FORCE_N_ID_2];
if (force_N_id_2 >= 0 && force_N_id_2 < 3) {
ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
// Stop radio
srslte_ue_cellsearch_free(&cs);
if (ret < 0) {
fprintf(stderr, "Error searching cell");
return false;
} else if (ret == 0) {
fprintf(stderr, "Could not find any cell in this frequency");
return false;
}
// Save result
cell.id = found_cells[max_peak_cell].cell_id;
cell.cp = found_cells[max_peak_cell].cp;
printf("Found CELL PHY_ID: %d, CP: %s PSR: %.1f AbsPower: %.1f dBm",
cell.id, srslte_cp_string(cell.cp),
found_cells[max_peak_cell].psr, 30+10*log10(found_cells[max_peak_cell].peak));
srslte_ue_mib_sync_t ue_mib;
if (srslte_ue_mib_sync_init(&ue_mib, cell.id, cell.cp, radio_recv_wrapper_cs, radio_handler)) {
return false;
}
uint32_t sfn, sfn_offset;
/* Find and decode MIB */
// Start RX stream again
ret = srslte_ue_mib_sync_decode(&ue_mib, params_db[PARAM_CELLSEARCH_TIMEOUT_MIB_NFRAMES],
bch_payload, &cell.nof_ports, &sfn_offset);
// Stop RX stream again
srslte_ue_mib_sync_free(&ue_mib);
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
current_tti = sfn*10+1;
printf("MIB decoded: %d ports, SFN: %d, TTI: %d", cell.nof_ports, sfn, current_tti);
return true;
} else {
printf("Error decoding MIB");
return false;
}
}
void srslte::ue_phy::run_rx_bch_state() {
if (rx_bch()) {
for(uint32_t i=0;i<6;i++) {
get_ul_buffer(i)->init_cell(cell, params_db);
get_dl_buffer(i)->init_cell(cell, params_db);
}
// init also ue_mib for sfn synch
phy_state = MIB_DECODED;
status_change();
} else {
phy_state = IDLE;
}
}
void srslte::ue_phy::run_rx_tx_state()
{
// if not synched -> go through mib
// else receive sync frame on dl_frame
// if have to send prach, send it
// if ul ready to send send
}
void srslte::ue_phy::main_radio_loop() {
while(started) {
switch(phy_state) {
case IDLE:
case MIB_DECODED:
break;
case RX_BCH:
run_rx_bch_state();
break;
case RXTX:
run_rx_tx_state();
break;
}
}
}
void srslte::ue_phy::set_param(param_t param, int64_t value)
{
params_db[param] = value;
}
srslte::ue_phy::ul_buffer* srslte::ue_phy::get_ul_buffer(uint32_t tti)
{
return (srslte::ue_phy::ul_buffer*) ul_buffer_queue->get(tti);
}
srslte::ue_phy::dl_buffer* srslte::ue_phy::get_dl_buffer(uint32_t tti)
{
return (srslte::ue_phy::dl_buffer*) dl_buffer_queue->get(tti);
}

View File

@ -1,233 +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/srslte.h"
#include "queue.h"
#ifndef UEPHY_H
#define UEPHY_H
#define SYNC_MODE_CV 0
#define SYNC_MODE_CALLBACK 1
#define SYNC_MODE SYNC_MODE_CALLBACK
namespace srslte {
typedef _Complex float cf_t;
class ue_phy
{
public:
typedef enum {DOWNLINK=0, UPLINK=1} direction_t;
typedef enum {
PDCCH_UL_SEARCH_CRNTI = 0,
PDCCH_UL_SEARCH_RA_PROC,
PDCCH_UL_SEARCH_SPS,
PDCCH_UL_SEARCH_TEMPORAL,
PDCCH_UL_SEARCH_TPC_PUSCH,
PDCCH_UL_SEARCH_TPC_PUCCH
} pdcch_ul_search_t;
typedef enum {
PDCCH_DL_SEARCH_CRNTI = 0,
PDCCH_DL_SEARCH_SIRNTI,
PDCCH_DL_SEARCH_PRNTI,
PDCCH_DL_SEARCH_RARNTI,
PDCCH_DL_SEARCH_TEMPORAL,
PDCCH_DL_SEARCH_SPS
} pdcch_dl_search_t;
/* Uplink/Downlink scheduling grant generated by a successfully decoded PDCCH */
class sched_grant {
public:
uint16_t get_rnti();
uint32_t get_rv();
void set_rv(uint32_t rv);
bool get_ndi();
uint32_t get_current_tti();
bool get_cqi_request();
int get_harq_process();
bool is_uplink();
bool is_downlink();
void* get_grant_ptr();
protected:
union {
srslte_ra_pusch_t ul_grant;
srslte_ra_pdsch_t dl_grant;
};
direction_t dir;
uint16_t rnti;
uint32_t current_tti;
};
/* Uplink scheduling assignment. The MAC instructs the PHY to prepare an UL packet (PUSCH or PUCCH)
* for transmission. The MAC must call generate_pusch() to set the packet ready for transmission
*/
class ul_buffer : public queue::element {
public:
bool init_cell(srslte_cell_t cell, int64_t *params_db);
void free_cell();
void set_tti(uint32_t tti);
void set_current_tx_nb(uint32_t current_tx_nb);
bool generate_pusch(sched_grant pusch_grant, uint8_t *payload, srslte_uci_data_t uci_data);
bool generate_pucch(srslte_uci_data_t uci_data);
private:
int64_t *params_db;
srslte_cell_t cell;
srslte_ue_ul_t ue_ul;
bool signal_generated;
cf_t* signal_buffer;
uint32_t tti;
uint32_t current_tx_nb;
};
/* Class for the processing of Downlink buffers. The MAC obtains a buffer for a given TTI and then
* gets ul/dl scheduling grants and/or processes phich/pdsch channels
*/
class dl_buffer : public queue::element {
public:
bool init_cell(srslte_cell_t cell, int64_t *params_db);
void free_cell();
bool get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant);
bool get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant);
bool decode_phich(srslte_phich_alloc_t assignment);
bool decode_pdsch(sched_grant pdsch_grant, uint8_t *payload); // returns true or false for CRC OK/KO
private:
int64_t *params_db;
srslte_cell_t cell;
srslte_ue_dl_t ue_dl;
srslte_phich_t phich;
cf_t *signal_buffer;
uint32_t cfi;
bool sf_symbols_and_ce_done;
bool pdcch_llr_extracted;
uint32_t tti;
};
#if SYNC_MODE==SYNC_MODE_CALLBACK
typedef void (*ue_phy_callback_t) (void);
ue_phy_callback_t tti_clock_callback;
ue_phy_callback_t status_change;
ue_phy(ue_phy_callback_t tti_clock_callback, ue_phy_callback_t status_change);
#else
ue_phy();
#endif
~ue_phy();
void measure(); // TBD
void dl_bch();
void start_rxtx();
void stop_rxtx();
bool init_prach();
void send_prach(uint32_t preamble_idx);
bool status_is_idle();
bool status_is_rxtx();
bool status_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]);
typedef enum {
PARAM_DL_FREQ = 0,
PARAM_UL_FREQ,
PARAM_CELLSEARCH_TIMEOUT_PSS_NFRAMES,
PARAM_CELLSEARCH_TIMEOUT_MIB_NFRAMES,
PARAM_CELLSEARCH_FORCE_N_ID_2,
PARAM_CELLSEARCH_CORRELATION_THRESHOLD, // integer that will be divided by 10
PARAM_PUSCH_BETA,
PARAM_PUSCH_RS_GROUP_HOPPING_EN,
PARAM_PUSCH_RS_SEQUENCE_HOPPING_EN,
PARAM_PUSCH_RS_CYCLIC_SHIFT,
PARAM_PUSCH_RS_GROUP_ASSIGNMENT,
PARAM_PUSCH_HOPPING_N_SB,
PARAM_PUSCH_HOPPING_INTRA_SF,
PARAM_PUSCH_HOPPING_OFFSET,
PARAMS_UCI_I_OFFSET_ACK,
PARAMS_UCI_I_OFFSET_RI,
PARAMS_UCI_I_OFFSET_CQI,
PARAMS_PRACH_CONFIG_INDEX,
PARAMS_PRACH_ROOT_SEQ_IDX,
PARAMS_PRACH_HIGH_SPEED_FLAG,
PARAMS_PRACH_ZC_CONFIG,
PARAMS_PRACH_FREQ_OFFSET,
PARAM_NOF_PARAMS,
} param_t;
void set_param(param_t param, int64_t value);
uint32_t get_tti();
#if SYNC_MODE==SYNC_MODE_CV
std::condition_variable tti_cv;
std::mutex tti_mutex;
#endif
ul_buffer* get_ul_buffer(uint32_t tti);
dl_buffer* get_dl_buffer(uint32_t tti);
void main_radio_loop();
private:
enum {
IDLE, MEASURE, RX_BCH, MIB_DECODED, RXTX
} phy_state;
int64_t *params_db;
srslte_cell_t cell;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
bool is_sfn_synched = false;
bool started = false;
uint32_t current_tti;
bool prach_initiated = false;
bool prach_ready_to_send = false;
uint32_t prach_len;
cf_t *prach_buffer[64];
srslte_prach_t prach;
queue *ul_buffer_queue;
queue *dl_buffer_queue;
pthread_t radio_thread;
void *radio_handler;
static void* radio_thread_fnc(void *arg);
void run_rx_bch_state();
bool rx_bch();
void run_rx_tx_state();
};
}
#endif

View File

@ -77,8 +77,20 @@ FOREACH (_file ${cmakefiles})
ENDIF ()
ENDFOREACH()
########################################################################
# Create C++ library
########################################################################
FILE(GLOB modules *)
SET(SOURCES_CPP_ALL "")
FOREACH (_module ${modules})
IF(IS_DIRECTORY ${_module})
FILE(GLOB_RECURSE tmp "${_module}/src/*.cc")
LIST(APPEND SOURCES_CPP_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_module})
ENDFOREACH()
ADD_LIBRARY(srslte++ SHARED ${SOURCES_CPP_ALL})
TARGET_LINK_LIBRARIES(srslte++ srslte m pthread ${FFTW3F_LIBRARIES})
INSTALL(TARGETS srslte++ DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(srslte++)

View File

@ -0,0 +1,171 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/ue_itf/sched_grant.h"
#include "srslte/ue_itf/dl_buffer.h"
#include "srslte/ue_itf/phy.h"
#include "srslte/ue_itf/params.h"
namespace srslte {
namespace ue {
bool dl_buffer::init_cell(srslte_cell_t cell_, params *params_db_)
{
params_db = params_db_;
cell = cell_;
sf_symbols_and_ce_done = false;
pdcch_llr_extracted = false;
tti = 0;
if (srslte_ue_dl_init(&ue_dl, cell)) {
signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
return signal_buffer?true:false;
} else {
return false;
}
}
void dl_buffer::free_cell()
{
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_dl_free(&ue_dl);
}
// FIXME: Avoid this memcpy modifying ue_sync to directly write into provided pointer
bool dl_buffer::recv_ue_sync(srslte_ue_sync_t *ue_sync, srslte_timestamp_t *rx_time)
{
cf_t *sf_buffer = NULL;
if (srslte_ue_sync_get_buffer(ue_sync, &sf_buffer)) {
return false;
}
memcpy(signal_buffer, sf_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_ue_sync_get_last_timestamp(ue_sync, rx_time);
}
bool dl_buffer::get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, sched_grant *grant)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
if (!pdcch_llr_extracted) {
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
return false;
}
pdcch_llr_extracted = true;
}
srslte_dci_msg_t dci_msg;
if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) {
return false;
}
if (srslte_dci_msg_to_ra_ul(&dci_msg, cell.nof_prb,
params_db->get_param(params::PUSCH_HOPPING_OFFSET),
(srslte_ra_pusch_t*) grant->get_grant_ptr()))
{
return false;
}
return true;
}
bool dl_buffer::get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, sched_grant *grant)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
if (!pdcch_llr_extracted) {
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
return false;
}
pdcch_llr_extracted = true;
}
srslte_dci_msg_t dci_msg;
if (srslte_ue_dl_find_dl_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) {
return false;
}
if (srslte_dci_msg_to_ra_dl(&dci_msg, rnti, cell, cfi,
(srslte_ra_pdsch_t*) grant->get_grant_ptr()))
{
return false;
}
return true;
}
bool dl_buffer::decode_phich(srslte_phich_alloc_t assignment)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
return false;
}
bool dl_buffer::decode_pdsch(sched_grant pdsch_grant, uint8_t *payload)
{
if (!sf_symbols_and_ce_done) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
return false;
}
sf_symbols_and_ce_done = true;
}
srslte_ra_pdsch_t *ra_dl = (srslte_ra_pdsch_t*) pdsch_grant.get_grant_ptr();
if (srslte_harq_setup_dl(&ue_dl.harq_process[0], ra_dl->mcs,
pdsch_grant.get_rv(), tti%10, &ra_dl->prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
return SRSLTE_ERROR;
}
if (ue_dl.harq_process[0].mcs.mod > 0 && ue_dl.harq_process[0].mcs.tbs >= 0) {
int ret = srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.harq_process[0], ue_dl.sf_symbols,
ue_dl.ce, 0, pdsch_grant.get_rnti(), payload);
if (ret == SRSLTE_SUCCESS) {
return true;
}
}
return false;
}
}
}

View File

@ -24,26 +24,24 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdlib.h>
#include "queue.h"
srslte::queue::queue(uint32_t nof_elements, uint32_t element_size)
{
buffer_of_elements = (queue::element**) malloc(sizeof(queue::element*) * nof_elements);
for (int i=0;i<nof_elements;i++) {
buffer_of_elements[i] = (queue::element*) malloc(element_size);
}
}
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
srslte::queue::~queue()
{
for (int i=0;i<nof_elements;i++) {
free(buffer_of_elements[i]);
#include "srslte/ue_itf/params.h"
namespace srslte {
namespace ue {
void params::set_param(param_t param, int64_t value)
{
params_db[param] = value;
}
free(buffer_of_elements);
}
srslte::queue::element* srslte::queue::get(uint32_t idx)
{
return (queue::element*) buffer_of_elements[idx%nof_elements];
int64_t params::get_param(param_t param)
{
return params_db[param];
}
}
}

View File

@ -0,0 +1,341 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/ue_itf/phy.h"
#include "srslte/ue_itf/prach.h"
#include "srslte/ue_itf/ul_buffer.h"
#include "srslte/ue_itf/dl_buffer.h"
namespace srslte {
namespace ue {
#if SYNC_MODE==SYNC_MODE_CALLBACK
phy::phy(ue_phy_callback_t tti_clock_callback_, ue_phy_callback_t status_change_)
{
tti_clock_callback = tti_clock_callback_;
status_change = status_change_;
ul_buffer_queue = new queue(6, sizeof(ul_buffer));
dl_buffer_queue = new queue(6, sizeof(dl_buffer));
started = true;
pthread_create(&radio_thread, NULL, radio_thread_fnc, this);
}
#else
phy()
{
}
#endif
phy::~phy()
{
started = false;
pthread_join(radio_thread, NULL);
for (int i=0;i<6;i++) {
((ul_buffer*) ul_buffer_queue->get(i))->free_cell();
((dl_buffer*) dl_buffer_queue->get(i))->free_cell();
}
delete ul_buffer_queue;
delete dl_buffer_queue;
prach_buffer.free_cell();
}
// FIXME: Add PRACH power control
void phy::send_prach(uint32_t preamble_idx)
{
if (phy_state == RXTX) {
prach_buffer.ready_to_send(preamble_idx);
}
}
// Do fast measurement on RSSI and/or PSS autocorrelation energy or PSR
void phy::measure()
{
if (phy_state == IDLE) {
// capture and do measurement
status_change();
}
}
void phy::dl_bch()
{
if (phy_state == IDLE) {
phy_state = RX_BCH;
status_change();
}
}
void phy::start_rxtx()
{
if (phy_state == MIB_DECODED) {
// Set sampling freq to MIB PRB
// start radio streaming
phy_state = RXTX;
status_change();
}
}
void phy::stop_rxtx()
{
// stop radio
phy_state = IDLE;
status_change();
}
bool phy::status_is_idle() {
return phy_state == IDLE;
}
bool phy::status_is_rxtx() {
return phy_state == RXTX;
}
bool phy::status_is_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN])
{
if (phy_state == MIB_DECODED) {
memcpy(payload, bch_payload, SRSLTE_BCH_PAYLOAD_LEN*sizeof(uint8_t));
}
}
void* phy::radio_thread_fnc(void *arg) {
phy* phy = static_cast<srslte::ue::phy*>(arg);
phy->main_radio_loop();
return NULL;
}
int radio_recv_wrapper_cs(void*,void*,uint32_t,srslte_timestamp_t*)
{
}
void phy::run_rx_bch_state() {
phy_state = IDLE;
if (rx_bch()) {
for(uint32_t i=0;i<6;i++) {
get_ul_buffer(i)->init_cell(cell, &params_db);
get_dl_buffer(i)->init_cell(cell, &params_db);
}
if (srslte_ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initiating UE mib\n");
} else {
if (srslte_ue_sync_init(&ue_sync, cell, radio_recv_wrapper_cs, radio_handler)) {
fprintf(stderr, "Error initiating ue_sync");
} else {
phy_state = MIB_DECODED;
}
}
}
status_change();
}
void phy::main_radio_loop() {
while(started) {
switch(phy_state) {
case IDLE:
case MIB_DECODED:
break;
case RX_BCH:
run_rx_bch_state();
break;
case RXTX:
run_rx_tx_state();
break;
}
}
}
ul_buffer* phy::get_ul_buffer(uint32_t tti)
{
return (ul_buffer*) ul_buffer_queue->get(tti);
}
dl_buffer* phy::get_dl_buffer(uint32_t tti)
{
return (dl_buffer*) dl_buffer_queue->get(tti);
}
bool phy::rx_bch()
{
srslte_ue_cellsearch_result_t found_cells[3];
srslte_ue_cellsearch_t cs;
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, radio_recv_wrapper_cs, radio_handler)) {
return false;
}
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, params_db.get_param(params::CELLSEARCH_TIMEOUT_PSS_NFRAMES));
srslte_ue_cellsearch_set_threshold(&cs, (float) params_db.get_param(params::CELLSEARCH_CORRELATION_THRESHOLD)/10);
// set sampling freq 1.92 MHz
// set frequency, gain etc
// start radio streaming
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
int ret = SRSLTE_ERROR;
uint32_t force_N_id_2 = params_db.get_param(params::CELLSEARCH_FORCE_N_ID_2);
if (force_N_id_2 >= 0 && force_N_id_2 < 3) {
ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
// Stop radio
srslte_ue_cellsearch_free(&cs);
if (ret < 0) {
fprintf(stderr, "Error searching cell");
return false;
} else if (ret == 0) {
fprintf(stderr, "Could not find any cell in this frequency");
return false;
}
// Save result
cell.id = found_cells[max_peak_cell].cell_id;
cell.cp = found_cells[max_peak_cell].cp;
printf("Found CELL PHY_ID: %d, CP: %s PSR: %.1f AbsPower: %.1f dBm",
cell.id, srslte_cp_string(cell.cp),
found_cells[max_peak_cell].psr, 30+10*log10(found_cells[max_peak_cell].peak));
srslte_ue_mib_sync_t ue_mib_sync;
if (srslte_ue_mib_sync_init(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, radio_handler)) {
return false;
}
uint32_t sfn, sfn_offset;
/* Find and decode MIB */
// Start RX stream again
ret = srslte_ue_mib_sync_decode(&ue_mib_sync, params_db.get_param(params::CELLSEARCH_TIMEOUT_MIB_NFRAMES),
bch_payload, &cell.nof_ports, &sfn_offset);
// Stop RX stream again
srslte_ue_mib_sync_free(&ue_mib_sync);
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
current_tti = sfn*10+1;
printf("MIB decoded: %d ports, SFN: %d, TTI: %d", cell.nof_ports, sfn, current_tti);
return true;
} else {
printf("Error decoding MIB");
return false;
}
}
int phy::sync_sfn(void) {
cf_t *sf_buffer = NULL;
int ret = SRSLTE_ERROR;
ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
uint32_t sfn_offset=0;
srslte_pbch_decode_reset(&ue_mib.pbch);
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
current_tti = sfn*10;
return 1;
}
}
}
return 0;
}
void phy::run_rx_tx_state()
{
int ret;
if (!is_sfn_synched) {
ret = sync_sfn();
switch(ret) {
default:
phy_state = IDLE;
break;
case 1:
is_sfn_synched = true;
break;
case 0:
break;
}
} else {
// Receive alligned buffer for the current tti
srslte_timestamp_t rx_time;
get_dl_buffer(current_tti)->recv_ue_sync(&ue_sync, &rx_time);
// send prach if we have to
if (prach_buffer.is_ready_to_send(current_tti)) {
prach_buffer.send(radio_handler, rx_time);
}
// send ul buffer if we have to
if (get_ul_buffer(current_tti)->is_ready_to_send()) {
get_ul_buffer(current_tti)->send_packet(radio_handler, rx_time);
}
}
current_tti++;
tti_clock_callback();
}
}
}

View File

@ -0,0 +1,114 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/ue_itf/prach.h"
#include "srslte/ue_itf/phy.h"
#include "srslte/ue_itf/params.h"
namespace srslte {
namespace ue {
void prach::free_cell()
{
if (initiated) {
for (uint32_t i=0;i<64;i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
srslte_prach_free(&prach);
}
}
bool prach::init_cell(srslte_cell_t cell, params *params_db_)
{
params_db = params_db_;
preamble_idx = -1;
if (srslte_prach_init(&prach, srslte_symbol_sz(cell.nof_prb),
srslte_prach_get_preamble_format(params_db->get_param(params::PRACH_CONFIG_INDEX)),
params_db->get_param(params::PRACH_ROOT_SEQ_IDX),
params_db->get_param(params::PRACH_HIGH_SPEED_FLAG)?true:false,
params_db->get_param(params::PRACH_ZC_CONFIG))) {
return false;
}
len = prach.N_seq + prach.N_cp;
for (uint32_t i=0;i<64;i++) {
buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t));
if(!buffer[i]) {
return false;
}
if(srslte_prach_gen(&prach, i, params_db->get_param(params::PRACH_FREQ_OFFSET), buffer[i])){
return false;
}
}
initiated = true;
return true;
}
bool prach::ready_to_send(uint32_t preamble_idx_)
{
if (initiated && preamble_idx_ < 64) {
preamble_idx = preamble_idx_;
return true;
} else {
return false;
}
}
bool prach::is_ready_to_send(uint32_t current_tti) {
if (preamble_idx >= 0 && preamble_idx < 64) {
uint32_t config_idx = (uint32_t) params_db->get_param(params::PRACH_CONFIG_INDEX);
srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx);
if (prach_sfn == SRSLTE_PRACH_SFN_EVEN && ((current_tti/10)%2)==0 ||
prach_sfn == SRSLTE_PRACH_SFN_ANY)
{
srslte_prach_sf_config_t sf_config;
srslte_prach_sf_config(config_idx, &sf_config);
for (int i=0;i<sf_config.nof_sf;i++) {
if ((current_tti%10) == sf_config.sf[i]) {
return true;
}
}
}
return false;
}
}
bool prach::send(void *radio_handler, srslte_timestamp_t rx_time)
{
// transmit
}
} // namespace ue
} // namespace srslte

View File

@ -0,0 +1,55 @@
/**
*
* \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 <stdlib.h>
#include "srslte/ue_itf/queue.h"
namespace srslte {
namespace ue {
queue::queue(uint32_t nof_elements, uint32_t element_size)
{
buffer_of_elements = (queue::element**) malloc(sizeof(queue::element*) * nof_elements);
for (int i=0;i<nof_elements;i++) {
buffer_of_elements[i] = (queue::element*) malloc(element_size);
}
}
queue::~queue()
{
for (int i=0;i<nof_elements;i++) {
free(buffer_of_elements[i]);
}
free(buffer_of_elements);
}
queue::element* queue::get(uint32_t idx)
{
return (queue::element*) buffer_of_elements[idx%nof_elements];
}
} // namespace ue
} // namespace srslte

View File

@ -0,0 +1,103 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/ue_itf/sched_grant.h"
namespace srslte {
namespace ue {
/* Returns the RNTI associated with the UL/DL scheduling grant */
uint16_t sched_grant::get_rnti() {
return rnti;
}
uint32_t sched_grant::get_rv() {
if (dir == UPLINK) {
return ul_grant.rv_idx;
} else {
return dl_grant.rv_idx;
}
}
void sched_grant::set_rv(uint32_t rv) {
if (dir == UPLINK) {
ul_grant.rv_idx = rv;
} else {
dl_grant.rv_idx = rv;
}
}
bool sched_grant::get_ndi() {
if (dir == UPLINK) {
return ul_grant.ndi;
} else {
return dl_grant.ndi;
}
}
bool sched_grant::get_cqi_request() {
if (dir == UPLINK) {
return ul_grant.ndi;
} else {
return dl_grant.ndi;
}
}
uint32_t sched_grant::get_current_tti() {
return current_tti;
}
int sched_grant::get_harq_process() {
if (dir == UPLINK) {
return -1;
} else {
return dl_grant.harq_process;
}
}
bool sched_grant::is_uplink() {
return dir == UPLINK;
}
bool sched_grant::is_downlink() {
return dir == DOWNLINK;
}
void* sched_grant::get_grant_ptr() {
if (is_uplink()) {
return (void*) &ul_grant;
} else {
return (void*) &dl_grant;
}
}
} // namespace ue
} // namespace srslte

View File

@ -0,0 +1,125 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/ue_itf/sched_grant.h"
#include "srslte/ue_itf/ul_buffer.h"
#include "srslte/ue_itf/phy.h"
#include "srslte/ue_itf/params.h"
namespace srslte {
namespace ue {
bool ul_buffer::init_cell(srslte_cell_t cell_, params *params_db) {
cell = cell_;
params_db = params_db;
signal_generated = false;
current_tx_nb = 0;
if (!srslte_ue_ul_init(&ue_ul, cell)) {
signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
return signal_buffer?true:false;
} else {
return false;
}
}
void ul_buffer::free_cell() {
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_ul_free(&ue_ul);
}
bool ul_buffer::generate_pusch(sched_grant pusch_grant,
uint8_t *payload,
srslte_uci_data_t uci_data)
{
if (pusch_grant.is_uplink()) {
fprintf(stderr, "Invalid scheduling grant. Grant is for Downlink\n");
return false;
}
srslte_refsignal_drms_pusch_cfg_t drms_cfg;
bzero(&drms_cfg, sizeof(srslte_refsignal_drms_pusch_cfg_t));
drms_cfg.beta_pusch = params_db->get_param(params::PUSCH_BETA);
drms_cfg.group_hopping_en = params_db->get_param(params::PUSCH_RS_GROUP_HOPPING_EN);
drms_cfg.sequence_hopping_en = params_db->get_param(params::PUSCH_RS_SEQUENCE_HOPPING_EN);
drms_cfg.cyclic_shift = params_db->get_param(params::PUSCH_RS_CYCLIC_SHIFT);
drms_cfg.delta_ss = params_db->get_param(params::PUSCH_RS_GROUP_ASSIGNMENT);
srslte_pusch_hopping_cfg_t pusch_hopping;
pusch_hopping.n_sb = params_db->get_param(params::PUSCH_HOPPING_N_SB);
pusch_hopping.hop_mode = params_db->get_param(params::PUSCH_HOPPING_INTRA_SF) ?
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF :
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
pusch_hopping.hopping_offset = params_db->get_param(params::PUSCH_HOPPING_OFFSET);
pusch_hopping.current_tx_nb = current_tx_nb;
srslte_ue_ul_set_pusch_cfg(&ue_ul, &drms_cfg, &pusch_hopping);
int n = srslte_ue_ul_pusch_uci_encode_rnti(&ue_ul, (srslte_ra_pusch_t*) pusch_grant.get_grant_ptr(),
payload, uci_data,
tti%10, pusch_grant.get_rnti(),
signal_buffer);
if (n < 0) {
fprintf(stderr, "Error encoding PUSCH\n");
return false;
}
signal_generated = true;
/* This is done by the transmission thread
srslte_vec_sc_prod_cfc(signal_buffer, beta_pusch, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
float time_adv_sec = TA_OFFSET + ((float) n_ta)*LTE_TS;
srslte_timestamp_t next_tx_time;
srslte_timestamp_copy(&next_tx_time, &last_rx_time);
srslte_timestamp_add(&next_tx_time, 0, 0.003 - time_adv_sec);
*/
// Send through radio
return true;
}
bool ul_buffer::generate_pucch(srslte_uci_data_t uci_data)
{
fprintf(stderr, "Not implemented\n");
return false;
}
bool ul_buffer::send_packet(void *radio_handler, srslte_timestamp_t rx_time)
{
// send packet through usrp
}
} // namespace ue
} // namespace srslte

View File

@ -20,7 +20,5 @@
#
ADD_LIBRARY(srslte++ SHARED ue_phy.cc)
TARGET_LINK_LIBRARIES(srslte++ srslte m ${FFTW3F_LIBRARIES})
INSTALL(TARGETS srslte++ DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(srslte++)
ADD_EXECUTABLE(ue_itf_test ue_itf_test.cc)
TARGET_LINK_LIBRARIES(ue_itf_test srslte++)

View File

@ -0,0 +1,74 @@
/**
*
* \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 <unistd.h>
#include "srslte/ue_itf/phy.h"
void tti_callback();
void status_change();
srslte::ue::phy phy = srslte::ue::phy(tti_callback, status_change);
void tti_callback() {
printf("called tti callback\n");
}
bool status_changed;
void status_change() {
printf("called status change\n");
status_changed=true;
}
int main(int argc, char *argv[])
{
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
sleep(1);
/* Instruct the PHY to decode BCH */
status_changed=false;
phy.dl_bch();
while(!status_changed);
if (!phy.status_is_bch_decoded(bch_payload)) {
printf("Could not decode BCH\n");
exit(-1);
}
srslte_vec_fprint_hex(stdout, bch_payload, SRSLTE_BCH_PAYLOAD_LEN);
/* Instruct the PHY to start RX streaming and synchronize */
status_changed=false;
phy.start_rxtx();
while(!status_changed);
if (!phy.status_is_rxtx()) {
printf("Could not start RX\n");
exit(-1);
}
/* go to idle and process each tti */
while(1) {
sleep(1);
}
}