/** * * \section COPYRIGHT * * Copyright 2013-2015 Software Radio Systems Limited * * \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 #include #include #include "srslte/common/phy_common.h" #include "srslte/common/sequence.h" #ifdef FORCE_STANDARD_RATE static bool use_standard_rates = true; #else static bool use_standard_rates = false; #endif /* Returns true if the structure pointed by cell has valid parameters */ bool srslte_cellid_isvalid(uint32_t cell_id) { if (cell_id < 504) { return true; } else { return false; } } bool srslte_nofprb_isvalid(uint32_t nof_prb) { if (nof_prb >= 6 && nof_prb <= SRSLTE_MAX_PRB) { return true; } else { return false; } } bool srslte_cell_isvalid(srslte_cell_t *cell) { return srslte_cellid_isvalid(cell->id) && srslte_portid_isvalid(cell->nof_ports) && srslte_nofprb_isvalid(cell->nof_prb); } void srslte_cell_fprint(FILE *stream, srslte_cell_t *cell, uint32_t sfn) { fprintf(stream, " - Cell ID: %d\n", cell->id); fprintf(stream, " - Nof ports: %d\n", cell->nof_ports); fprintf(stream, " - CP: %s\n", srslte_cp_string(cell->cp)); fprintf(stream, " - PRB: %d\n", cell->nof_prb); fprintf(stream, " - PHICH Length: %s\n", cell->phich_length == SRSLTE_PHICH_EXT ? "Extended" : "Normal"); fprintf(stream, " - PHICH Resources: "); switch (cell->phich_resources) { case SRSLTE_PHICH_R_1_6: fprintf(stream, "1/6"); break; case SRSLTE_PHICH_R_1_2: fprintf(stream, "1/2"); break; case SRSLTE_PHICH_R_1: fprintf(stream, "1"); break; case SRSLTE_PHICH_R_2: fprintf(stream, "2"); break; } fprintf(stream, "\n"); fprintf(stream, " - SFN: %d\n", sfn); } bool srslte_sfidx_isvalid(uint32_t sf_idx) { if (sf_idx <= SRSLTE_NSUBFRAMES_X_FRAME) { return true; } else { return false; } } bool srslte_portid_isvalid(uint32_t port_id) { if (port_id <= SRSLTE_MAX_PORTS) { return true; } else { return false; } } bool srslte_N_id_2_isvalid(uint32_t N_id_2) { if (N_id_2 < 3) { return true; } else { return false; } } bool srslte_N_id_1_isvalid(uint32_t N_id_1) { if (N_id_1 < 169) { return true; } else { return false; } } char *srslte_mod_string(srslte_mod_t mod) { switch (mod) { case SRSLTE_MOD_BPSK: return "BPSK"; case SRSLTE_MOD_QPSK: return "QPSK"; case SRSLTE_MOD_16QAM: return "16QAM"; case SRSLTE_MOD_64QAM: return "64QAM"; default: return "N/A"; } } uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod) { switch (mod) { case SRSLTE_MOD_BPSK: return 1; case SRSLTE_MOD_QPSK: return 2; case SRSLTE_MOD_16QAM: return 4; case SRSLTE_MOD_64QAM: return 6; default: return 0; } } char *srslte_cp_string(srslte_cp_t cp) { if (cp == SRSLTE_CP_NORM) { return "Normal "; } else { return "Extended"; } } /* Returns the new time advance N_ta_new as specified in Section 4.2.3 of 36.213 */ uint32_t srslte_N_ta_new(uint32_t N_ta_old, uint32_t ta) { ta &= 63; int n_ta_new = N_ta_old + ((float) ta - 31) * 16; if (n_ta_new < 0) { return 0; } else { if (n_ta_new < 20512) { return (uint32_t) n_ta_new; } else { return 20512; } } } /* Returns the new time advance as indicated by the random access response * as specified in Section 4.2.3 of 36.213 */ uint32_t srslte_N_ta_new_rar(uint32_t ta) { if (ta > 1282) { ta = 1282; } return ta*16; } void srslte_use_standard_symbol_size(bool enabled) { use_standard_rates = enabled; } int srslte_sampling_freq_hz(uint32_t nof_prb) { int n = srslte_symbol_sz(nof_prb); if (n == -1) { return SRSLTE_ERROR; } else { return 15000 * n; } } int srslte_symbol_sz_power2(uint32_t nof_prb) { if (nof_prb<=6) { return 128; } else if (nof_prb<=15) { return 256; } else if (nof_prb<=25) { return 512; } else if (nof_prb<=50) { return 1024; } else if (nof_prb<=75) { return 1536; } else if (nof_prb<=100) { return 2048; } else { return -1; } } int srslte_symbol_sz(uint32_t nof_prb) { if (nof_prb<=0) { return SRSLTE_ERROR; } if (!use_standard_rates) { if (nof_prb<=6) { return 128; } else if (nof_prb<=15) { return 256; } else if (nof_prb<=25) { return 384; } else if (nof_prb<=50) { return 768; } else if (nof_prb<=75) { return 1024; } else if (nof_prb<=100) { return 1536; } else { return SRSLTE_ERROR; } } else { return srslte_symbol_sz_power2(nof_prb); } } int srslte_nof_prb(uint32_t symbol_sz) { if (!use_standard_rates) { switch(symbol_sz) { case 128: return 6; case 256: return 15; case 384: return 25; case 768: return 50; case 1024: return 75; case 1536: return 100; } } else { switch(symbol_sz) { case 128: return 6; case 256: return 15; case 512: return 25; case 1024: return 50; case 1536: return 75; case 2048: return 100; } } return SRSLTE_ERROR; } bool srslte_symbol_sz_isvalid(uint32_t symbol_sz) { if (!use_standard_rates) { if (symbol_sz == 128 || symbol_sz == 256 || symbol_sz == 384 || symbol_sz == 768 || symbol_sz == 1024 || symbol_sz == 1536) { return true; } else { return false; } } else { if (symbol_sz == 128 || symbol_sz == 256 || symbol_sz == 512 || symbol_sz == 1024 || symbol_sz == 1536 || symbol_sz == 2048) { return true; } else { return false; } } } uint32_t srslte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) { if (nof_ports == 1 && symbol_id==0) { return (cell_id+3) % 6; } else { return cell_id % 6; } } /** Computes sequence-group pattern f_gh according to 5.5.1.3 of 36.211 */ int srslte_group_hopping_f_gh(uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME], uint32_t cell_id) { srslte_sequence_t seq; bzero(&seq, sizeof(srslte_sequence_t)); if (srslte_sequence_LTE_pr(&seq, 160, cell_id / 30)) { return SRSLTE_ERROR; } for (uint32_t ns=0;ns= band->earfcn_offset) { return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); } else { return 0.0; } } int srslte_band_get_band(uint32_t earfcn) { uint32_t i = SRSLTE_NOF_LTE_BANDS-1; while(i > 0 && lte_bands[i].earfcn_offset>earfcn) { i--; } return lte_bands[i].band; } float srslte_band_fd(uint32_t earfcn) { uint32_t i = SRSLTE_NOF_LTE_BANDS-1; while(i > 0 && lte_bands[i].earfcn_offset>earfcn) { i--; } return get_fd(<e_bands[i], earfcn); } float srslte_band_fu(uint32_t earfcn) { uint32_t i = SRSLTE_NOF_LTE_BANDS-1; while(i > 0 && lte_bands[i].earfcn_offset>earfcn) { i--; } return get_fd(<e_bands[i], earfcn) - lte_bands[i].duplex_mhz; } int srslte_band_get_fd_band_all(uint32_t band, srslte_earfcn_t *earfcn, uint32_t max_elems) { return srslte_band_get_fd_band(band, earfcn, -1, -1, max_elems); } int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) { uint32_t i, j; uint32_t nof_earfcn; i=0; while(i < SRSLTE_NOF_LTE_BANDS && lte_bands[i].band != band) { i++; } if (i == SRSLTE_NOF_LTE_BANDS) { fprintf(stderr, "Error: Invalid band %d\n", band); return SRSLTE_ERROR; } if (end_earfcn == -1) { end_earfcn = lte_bands[i].earfcn_max; } else { if (end_earfcn > lte_bands[i].earfcn_max) { fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max); return SRSLTE_ERROR; } } if (start_earfcn == -1) { start_earfcn = lte_bands[i].earfcn_offset; } else { if (start_earfcn < lte_bands[i].earfcn_offset) { fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset); return SRSLTE_ERROR; } } nof_earfcn = end_earfcn - start_earfcn; if (nof_earfcn > max_elems) { nof_earfcn = max_elems; } for (j=0;j 0;i++) { if (lte_bands[i].area == region) { n = srslte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems); if (n != -1) { nof_fd += n; max_elems -= n; } else { return SRSLTE_ERROR; } } } return nof_fd; } /* Returns the interval tti1-tti2 mod 10240 */ uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2) { if (tti1 > tti2) { return tti1-tti2; } else { return 10240-tti2+tti1; } }