mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
485 lines
15 KiB
C++
485 lines
15 KiB
C++
/**
|
|
*
|
|
* \section COPYRIGHT
|
|
*
|
|
* Copyright 2013-2015 The srsLTE Developers. See the
|
|
* COPYRIGHT file at the top-level directory of this distribution.
|
|
*
|
|
* \section LICENSE
|
|
*
|
|
* This file is part of the srsLTE library.
|
|
*
|
|
* srsLTE is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* srsLTE is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* A copy of the GNU Affero General Public License can be found in
|
|
* the LICENSE file in the top-level directory of this distribution
|
|
* and at http://www.gnu.org/licenses/.
|
|
*
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "srslte/utils/debug.h"
|
|
#include "srsapps/ue/phy/phy.h"
|
|
#include "srsapps/common/log_stdout.h"
|
|
#include "srsapps/common/tti_sync_cv.h"
|
|
#include "srsapps/radio/radio_uhd.h"
|
|
|
|
/**********************************************************************
|
|
* Program arguments processing
|
|
***********************************************************************/
|
|
typedef struct {
|
|
float uhd_rx_freq;
|
|
float uhd_tx_freq;
|
|
float uhd_rx_gain;
|
|
float uhd_tx_gain;
|
|
bool continous;
|
|
}prog_args_t;
|
|
|
|
prog_args_t prog_args;
|
|
|
|
void args_default(prog_args_t *args) {
|
|
args->uhd_rx_freq = -1.0;
|
|
args->uhd_tx_freq = -1.0;
|
|
args->uhd_rx_gain = -1; // set to autogain
|
|
args->uhd_tx_gain = -1;
|
|
args->continous = false;
|
|
}
|
|
|
|
void usage(prog_args_t *args, char *prog) {
|
|
printf("Usage: %s [gGcv] -f rx_frequency -F tx_frequency (in Hz)\n", prog);
|
|
printf("\t-g UHD RX gain [Default AGC]\n");
|
|
printf("\t-G UHD TX gain [Default same as RX gain (AGC)]\n");
|
|
printf("\t-c Run continuously [Default only once]\n");
|
|
printf("\t-v [increase verbosity, default none]\n");
|
|
}
|
|
|
|
void parse_args(prog_args_t *args, int argc, char **argv) {
|
|
int opt;
|
|
args_default(args);
|
|
while ((opt = getopt(argc, argv, "gGfFcv")) != -1) {
|
|
switch (opt) {
|
|
case 'g':
|
|
args->uhd_rx_gain = atof(argv[optind]);
|
|
break;
|
|
case 'G':
|
|
args->uhd_tx_gain = atof(argv[optind]);
|
|
break;
|
|
case 'f':
|
|
args->uhd_rx_freq = atof(argv[optind]);
|
|
break;
|
|
case 'F':
|
|
args->uhd_tx_freq = atof(argv[optind]);
|
|
break;
|
|
case 'c':
|
|
args->continous = true;
|
|
break;
|
|
case 'v':
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
typedef enum{
|
|
rar_tpc_n6dB = 0,
|
|
rar_tpc_n4dB,
|
|
rar_tpc_n2dB,
|
|
rar_tpc_0dB,
|
|
rar_tpc_2dB,
|
|
rar_tpc_4dB,
|
|
rar_tpc_6dB,
|
|
rar_tpc_8dB,
|
|
rar_tpc_n_items,
|
|
}rar_tpc_command_t;
|
|
static const char tpc_command_text[rar_tpc_n_items][8] = {"-6dB", "-4dB", "-2dB", "0dB", "2dB", "4dB", "6dB", "8dB"};
|
|
typedef enum{
|
|
rar_header_type_bi = 0,
|
|
rar_header_type_rapid,
|
|
rar_header_type_n_items,
|
|
}rar_header_t;
|
|
static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"};
|
|
|
|
typedef struct {
|
|
rar_header_t hdr_type;
|
|
bool hopping_flag;
|
|
rar_tpc_command_t tpc_command;
|
|
bool ul_delay;
|
|
bool csi_req;
|
|
uint16_t rba;
|
|
uint16_t timing_adv_cmd;
|
|
uint16_t temp_c_rnti;
|
|
uint8_t mcs;
|
|
uint8_t RAPID;
|
|
uint8_t BI;
|
|
}rar_msg_t;
|
|
|
|
char *bool_to_string(bool x) {
|
|
if (x) {
|
|
return (char*) "Enabled";
|
|
} else {
|
|
return (char*) "Disabled";
|
|
}
|
|
}
|
|
|
|
void rar_msg_fprint(FILE *stream, rar_msg_t *msg)
|
|
{
|
|
fprintf(stream, "Header type: %s\n", rar_header_text[msg->hdr_type]);
|
|
fprintf(stream, "Hopping flag: %s\n", bool_to_string(msg->hopping_flag));
|
|
fprintf(stream, "TPC command: %s\n", tpc_command_text[msg->tpc_command]);
|
|
fprintf(stream, "UL delay: %s\n", bool_to_string(msg->ul_delay));
|
|
fprintf(stream, "CSI required: %s\n", bool_to_string(msg->csi_req));
|
|
fprintf(stream, "RBA: %d\n", msg->rba);
|
|
fprintf(stream, "TA: %d\n", msg->timing_adv_cmd);
|
|
fprintf(stream, "T-CRNTI: %d\n", msg->temp_c_rnti);
|
|
fprintf(stream, "MCS: %d\n", msg->mcs);
|
|
fprintf(stream, "RAPID: %d\n", msg->RAPID);
|
|
fprintf(stream, "BI: %d\n", msg->BI);
|
|
}
|
|
|
|
int rar_unpack(uint8_t *buffer, rar_msg_t *msg)
|
|
{
|
|
int ret = SRSLTE_ERROR;
|
|
uint8_t *ptr = buffer;
|
|
|
|
if(buffer != NULL &&
|
|
msg != NULL)
|
|
{
|
|
ptr++;
|
|
msg->hdr_type = (rar_header_t) *ptr++;
|
|
if(msg->hdr_type == rar_header_type_bi) {
|
|
ptr += 2;
|
|
msg->BI = srslte_bit_unpack(&ptr, 4);
|
|
ret = SRSLTE_SUCCESS;
|
|
} else if (msg->hdr_type == rar_header_type_rapid) {
|
|
msg->RAPID = srslte_bit_unpack(&ptr, 6);
|
|
ptr++;
|
|
|
|
msg->timing_adv_cmd = srslte_bit_unpack(&ptr, 11);
|
|
msg->hopping_flag = *ptr++;
|
|
msg->rba = srslte_bit_unpack(&ptr, 10);
|
|
msg->mcs = srslte_bit_unpack(&ptr, 4);
|
|
msg->tpc_command = (rar_tpc_command_t) srslte_bit_unpack(&ptr, 3);
|
|
msg->ul_delay = *ptr++;
|
|
msg->csi_req = *ptr++;
|
|
msg->temp_c_rnti = srslte_bit_unpack(&ptr, 16);
|
|
ret = SRSLTE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
|
|
|
|
srslte::ue::phy phy;
|
|
|
|
uint8_t payload[102400];
|
|
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
|
|
|
|
enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA;
|
|
|
|
uint32_t conreq_tti = 0;
|
|
uint32_t preamble_idx = 7;
|
|
rar_msg_t rar_msg;
|
|
uint32_t nof_rx_connsetup = 0, nof_rx_rar = 0, nof_tx_ra = 0;
|
|
|
|
uint32_t nof_rtx_connsetup = 0;
|
|
uint32_t rv_value[4] = {0, 2, 3, 1};
|
|
|
|
void config_phy() {
|
|
phy.set_param(srslte::ue::phy_params::PRACH_CONFIG_INDEX, 0);
|
|
phy.set_param(srslte::ue::phy_params::PRACH_FREQ_OFFSET, 0);
|
|
phy.set_param(srslte::ue::phy_params::PRACH_HIGH_SPEED_FLAG, 0);
|
|
phy.set_param(srslte::ue::phy_params::PRACH_ROOT_SEQ_IDX, 0);
|
|
phy.set_param(srslte::ue::phy_params::PRACH_ZC_CONFIG, 1);
|
|
|
|
phy.set_param(srslte::ue::phy_params::PUSCH_BETA, 10);
|
|
phy.set_param(srslte::ue::phy_params::DMRS_GROUP_HOPPING_EN, 0);
|
|
phy.set_param(srslte::ue::phy_params::DMRS_SEQUENCE_HOPPING_EN, 0);
|
|
phy.set_param(srslte::ue::phy_params::PUSCH_RS_CYCLIC_SHIFT, 0);
|
|
phy.set_param(srslte::ue::phy_params::PUSCH_RS_GROUP_ASSIGNMENT, 0);
|
|
phy.set_param(srslte::ue::phy_params::PUSCH_HOPPING_OFFSET, 0);
|
|
|
|
phy.set_param(srslte::ue::phy_params::PUCCH_BETA, 10);
|
|
phy.set_param(srslte::ue::phy_params::PUCCH_DELTA_SHIFT, 1);
|
|
phy.set_param(srslte::ue::phy_params::PUCCH_CYCLIC_SHIFT, 0);
|
|
phy.set_param(srslte::ue::phy_params::PUCCH_N_PUCCH_1, 0);
|
|
phy.set_param(srslte::ue::phy_params::PUCCH_N_RB_2, 2);
|
|
|
|
}
|
|
|
|
uint32_t interval(uint32_t x1, uint32_t x2) {
|
|
if (x1 > x2) {
|
|
return x1-x2;
|
|
} else {
|
|
return 10240-x2+x1;
|
|
}
|
|
}
|
|
|
|
srslte_softbuffer_rx_t softbuffer;
|
|
|
|
// This is the MAC implementation
|
|
void run_tti(uint32_t tti) {
|
|
INFO("MAC running tti: %d\n", tti);
|
|
|
|
// Get buffer
|
|
srslte::ue::dl_buffer *dl_buffer = phy.get_dl_buffer(tti);
|
|
|
|
if (state == RA) {
|
|
if (nof_tx_ra > 0 && !prog_args.continous) {
|
|
exit(0);
|
|
}
|
|
// Indicate PHY to transmit the PRACH when possible
|
|
if (phy.send_prach(preamble_idx)) {
|
|
nof_tx_ra++;
|
|
state = RAR;
|
|
} else {
|
|
fprintf(stderr, "Error sending PRACH\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
if (state == RAR) {
|
|
srslte::ue::dl_sched_grant rar_grant(2);
|
|
int ra_tti = phy.get_prach_transmitted_tti();
|
|
if (ra_tti > 0) {
|
|
INFO("PRACH was transmitted at %d\n", ra_tti);
|
|
// Assume the maximum RA-window
|
|
uint32_t interval_ra = interval(tti, ra_tti);
|
|
INFO("Interval=%u\n", interval_ra);
|
|
if (interval_ra >= 3 && interval_ra <= 13) {
|
|
// Get DL grant for RA-RNTI=2
|
|
if (dl_buffer->get_dl_grant(&rar_grant))
|
|
{
|
|
srslte_softbuffer_rx_reset(&softbuffer);
|
|
// Decode packet
|
|
if (dl_buffer->decode_data(&rar_grant, &softbuffer, payload)) {
|
|
rar_unpack(payload, &rar_msg);
|
|
if (rar_msg.RAPID == preamble_idx) {
|
|
|
|
INFO("Received RAR at TTI: %d\n", tti);
|
|
nof_rx_rar++;
|
|
|
|
if (SRSLTE_VERBOSE_ISINFO()) {
|
|
rar_msg_fprint(stdout, &rar_msg);
|
|
}
|
|
|
|
// Set time advance
|
|
phy.set_timeadv_rar(rar_msg.timing_adv_cmd);
|
|
|
|
// Generate Msg3 grant
|
|
srslte::ue::ul_sched_grant connreq_grant(rar_msg.temp_c_rnti);
|
|
srslte_dci_rar_grant_t rar_grant;
|
|
rar_grant.rba = rar_msg.rba;
|
|
rar_grant.trunc_mcs = rar_msg.mcs;
|
|
rar_grant.hopping_flag = rar_msg.hopping_flag;
|
|
phy.rar_ul_grant(&rar_grant, &connreq_grant);
|
|
|
|
// Pack Msg3 bits
|
|
srslte_bit_pack_vector((uint8_t*) conn_request_msg, payload, connreq_grant.get_tbs());
|
|
|
|
// Get UL buffer
|
|
srslte::ue::ul_buffer *ul_buffer = phy.get_ul_buffer(tti+6);
|
|
|
|
// Generate PUSCH
|
|
if (ul_buffer) {
|
|
connreq_grant.set_rv(0);
|
|
INFO("Generating PUSCH for TTI: %d\n", ul_buffer->tti);
|
|
ul_buffer->generate_data(&connreq_grant, payload);
|
|
|
|
// Save transmission time
|
|
conreq_tti = ul_buffer->tti;
|
|
state = CONNREQUEST;
|
|
} else {
|
|
fprintf(stderr, "Error getting UL buffer for TTI %d\n", tti);
|
|
state = RA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (interval_ra > 13 && interval_ra < 100) { // avoid wrapping
|
|
INFO("RAR not received at TTI=%d (interval_ra=%d)\n", tti, interval_ra);
|
|
state = RA;
|
|
}
|
|
}
|
|
}
|
|
if (state == CONNREQUEST) {
|
|
uint32_t interval_conreq = interval(tti, conreq_tti);
|
|
if (interval_conreq == 4) {
|
|
|
|
srslte::ue::ul_sched_grant connreq_grant(rar_msg.temp_c_rnti);
|
|
srslte_dci_rar_grant_t rar_grant;
|
|
rar_grant.rba = rar_msg.rba;
|
|
rar_grant.trunc_mcs = rar_msg.mcs;
|
|
rar_grant.hopping_flag = rar_msg.hopping_flag;
|
|
phy.rar_ul_grant(&rar_grant, &connreq_grant);
|
|
|
|
// Decode PHICH from Connection Request
|
|
if (!dl_buffer->decode_ack(&connreq_grant)) {
|
|
|
|
// Pack Msg3 bits
|
|
srslte_bit_pack_vector((uint8_t*) conn_request_msg, payload, connreq_grant.get_tbs());
|
|
|
|
// Get UL buffer
|
|
srslte::ue::ul_buffer *ul_buffer = phy.get_ul_buffer(tti+4);
|
|
|
|
// Generate PUSCH
|
|
if (ul_buffer) {
|
|
nof_rtx_connsetup++;
|
|
if (nof_rtx_connsetup >= 5) {
|
|
state = RA;
|
|
} else {
|
|
connreq_grant.set_current_tx_nb(nof_rtx_connsetup);
|
|
connreq_grant.set_rv(rv_value[nof_rtx_connsetup%4]);
|
|
INFO("Generating PUSCH for TTI: %d\n", ul_buffer->tti);
|
|
ul_buffer->generate_data(&connreq_grant, payload);
|
|
|
|
// Save transmission time
|
|
conreq_tti = ul_buffer->tti;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Error getting UL buffer for TTI %d\n", tti);
|
|
state = RA;
|
|
}
|
|
} else {
|
|
srslte_softbuffer_rx_reset(&softbuffer);
|
|
state = CONNSETUP;
|
|
}
|
|
}
|
|
}
|
|
if (state == CONNSETUP) {
|
|
srslte::ue::dl_sched_grant conn_setup_grant(rar_msg.temp_c_rnti);
|
|
bool connsetup_recv = false;
|
|
// Get DL grant for tmp_rnti
|
|
if (dl_buffer->get_dl_grant(&conn_setup_grant))
|
|
{
|
|
// Decode packet
|
|
if (dl_buffer->decode_data(&conn_setup_grant, &softbuffer, payload)) {
|
|
nof_rx_connsetup++;
|
|
state = RA;
|
|
nof_rtx_connsetup=0;
|
|
if (!prog_args.continous) {
|
|
printf("Connection Setup received (%d/%d)\n", nof_rx_connsetup, nof_tx_ra);
|
|
}
|
|
connsetup_recv = true;
|
|
} else {
|
|
INFO("Error decoding PDSCH for Connection Request at TTI=%d\n", tti);
|
|
}
|
|
|
|
// send ACK
|
|
INFO("Sending ack %d on TTI: %d\n", connsetup_recv, tti+4);
|
|
srslte::ue::ul_buffer *ul_buffer = phy.get_ul_buffer(tti+4);
|
|
ul_buffer->generate_ack(connsetup_recv, &conn_setup_grant);
|
|
if (!prog_args.continous) {
|
|
while(ul_buffer->uci_ready()) {
|
|
sleep(1);
|
|
}
|
|
}
|
|
state = RA;
|
|
|
|
} else {
|
|
INFO("DCI for Connection Request not found on PDCCH at TTI=%d\n", tti);
|
|
state = RA;
|
|
}
|
|
}
|
|
float gain = prog_args.uhd_rx_gain;
|
|
if (gain < 0) {
|
|
gain = phy.get_agc_gain();
|
|
}
|
|
if (srslte_verbose == SRSLTE_VERBOSE_NONE && prog_args.continous) {
|
|
printf("RECV RAR %2.1f \%% RECV ConnSetup %2.1f \%% (%5u/%5u) Gain: %.1f dB\r",
|
|
(float) 100*nof_rx_rar/nof_tx_ra,
|
|
(float) 100*nof_rx_connsetup/nof_tx_ra,
|
|
nof_rx_connsetup, nof_tx_ra, gain);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
srslte_cell_t cell;
|
|
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
|
srslte::ue::tti_sync_cv ttisync(10240);
|
|
srslte::radio_uhd radio_uhd;
|
|
srslte::log_stdout log("PHY");
|
|
|
|
parse_args(&prog_args, argc, argv);
|
|
|
|
// Init Radio and PHY
|
|
if (prog_args.uhd_rx_gain > 0 && prog_args.uhd_tx_gain > 0) {
|
|
radio_uhd.init();
|
|
radio_uhd.set_rx_gain(prog_args.uhd_rx_gain);
|
|
radio_uhd.set_tx_gain(prog_args.uhd_tx_gain);
|
|
phy.init(&radio_uhd, &ttisync, &log);
|
|
} else {
|
|
radio_uhd.init_agc();
|
|
radio_uhd.set_tx_rx_gain_offset(-10);
|
|
phy.init_agc(&radio_uhd, &ttisync, &log);
|
|
}
|
|
|
|
// Give it time to create thread
|
|
sleep(1);
|
|
|
|
// Setup PHY parameters
|
|
config_phy();
|
|
|
|
// Set RX freq
|
|
radio_uhd.set_rx_freq(prog_args.uhd_rx_freq);
|
|
radio_uhd.set_tx_freq(prog_args.uhd_tx_freq);
|
|
|
|
/* Instruct the PHY to decode BCH */
|
|
if (!phy.decode_mib_best(&cell, bch_payload)) {
|
|
exit(-1);
|
|
}
|
|
// Print MIB
|
|
srslte_cell_fprint(stdout, &cell, phy.get_current_tti()/10);
|
|
|
|
// Set the current PHY cell to the detected cell
|
|
if (!phy.set_cell(cell)) {
|
|
printf("Error setting cell\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if (!phy.init_prach()) {
|
|
printf("Error initiating PRACH\n");
|
|
exit(-1);
|
|
}
|
|
|
|
srslte_softbuffer_rx_init(&softbuffer, cell);
|
|
|
|
/* Instruct the PHY to start RX streaming and synchronize */
|
|
if (!phy.start_rxtx()) {
|
|
printf("Could not start RX\n");
|
|
exit(-1);
|
|
}
|
|
for (int i=0;i<100;i++) {
|
|
ttisync.wait();
|
|
}
|
|
/* go to idle and process each tti */
|
|
while(1) {
|
|
uint32_t tti = ttisync.wait();
|
|
run_tti(tti);
|
|
}
|
|
}
|
|
|
|
|
|
|