Merge branch 'next'

master
Ismael Gomez 8 years ago
commit d4a05eefe4

@ -1,6 +1,11 @@
Change Log for Releases Change Log for Releases
============================== ==============================
## 001.004.000
* Fixed issue in rv for format1C causing incorrect SIB1 decoding in some networks
* Improved PDCCH decoding BER (fixed incorrect trellis initialization)
* Improved PUCCH RX performance
## 001.003.000 ## 001.003.000
* Bugfixes: * Bugfixes:

@ -100,8 +100,15 @@ if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE -g")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") find_package(SSE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")
if(HAVE_AVX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE")
elseif(HAVE_SSE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mfpmath=sse -msse4.1 -DLV_HAVE_SSE")
endif(HAVE_AVX)
else(${CMAKE_BUILD_TYPE} STREQUAL "Debug") else(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
find_package(SSE) find_package(SSE)
if(HAVE_AVX) if(HAVE_AVX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE")

@ -19,6 +19,6 @@
# #
SET(SRSLTE_VERSION_MAJOR 001) SET(SRSLTE_VERSION_MAJOR 001)
SET(SRSLTE_VERSION_MINOR 003) SET(SRSLTE_VERSION_MINOR 004)
SET(SRSLTE_VERSION_PATCH 000) SET(SRSLTE_VERSION_PATCH 000)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -1,13 +1,13 @@
%% PRACH Detection Conformance Test %% PRACH Detection Conformance Test
%clear %clear
d=50;%linspace(4,14,6); d=80;%linspace(4,14,6);
pDetection2 = zeros(2,length(d)); pDetection2 = zeros(2,length(d));
for dd=1:length(d) for dd=1:length(d)
detect_factor=d(dd); detect_factor=d(dd);
numSubframes = 1; % Number of subframes frames to simulate at each SNR numSubframes = 1; % Number of subframes frames to simulate at each SNR
SNRdB = 10;%linspace(-14,10,8); % SNR points to simulate SNRdB = 50;%linspace(-14,10,8); % SNR points to simulate
foffset = 0.0; % Frequency offset in Hertz foffset = 0.0; % Frequency offset in Hertz
delay=0; delay=0;
add_fading=false; add_fading=false;
@ -26,7 +26,7 @@ ue.NTxAnts = 1; % Number of transmission antennas
prach.Format = 0; % PRACH format: TS36.104, Table 8.4.2.1-1 prach.Format = 0; % PRACH format: TS36.104, Table 8.4.2.1-1
prach.HighSpeed = 0; % Normal mode: TS36.104, Table 8.4.2.1-1 prach.HighSpeed = 0; % Normal mode: TS36.104, Table 8.4.2.1-1
prach.FreqOffset = 4; % Default frequency location prach.FreqOffset = 2; % Default frequency location
info = ltePRACHInfo(ue, prach); % PRACH information info = ltePRACHInfo(ue, prach); % PRACH information
%% Propagation Channel Configuration %% Propagation Channel Configuration
@ -67,9 +67,10 @@ for nSNR = 1:length(SNRdB)
% Loop for each subframe % Loop for each subframe
for nsf = 1:numSubframes for nsf = 1:numSubframes
prach.SeqIdx = 0;%randi(838,1,1)-1; % Logical sequence index: TS36.141, Table A.6-1 prach.SeqIdx = 41;%randi(838,1,1)-1; % Logical sequence index: TS36.141, Table A.6-1
prach.CyclicShiftIdx = 11;%randi(16,1,1)-1; % Cyclic shift index: TS36.141, Table A.6-1 prach.CyclicShiftIdx = 11;%randi(16,1,1)-1; % Cyclic shift index: TS36.141, Table A.6-1
prach.PreambleIdx = 1;%randi(64,1,1)-1; % Preamble index: TS36.141, Table A.6-1 prach.PreambleIdx = 1;%randi(64,1,1)-1; % Preamble index: TS36.141, Table A.6-1
prach.TimingOffset = 0;
info = ltePRACHInfo(ue, prach); % PRACH information info = ltePRACHInfo(ue, prach); % PRACH information
% PRACH transmission % PRACH transmission
@ -99,7 +100,7 @@ for nSNR = 1:length(SNRdB)
rxwave = rxwave((fadinginfo.ChannelFilterDelay + 1):end, :); rxwave = rxwave((fadinginfo.ChannelFilterDelay + 1):end, :);
end end
rxwave=x; rxwave=lteFrequencyCorrect(ue, x, -20);
% rxwave=[zeros(delay,1); txwave(1:end-delay)]; % rxwave=[zeros(delay,1); txwave(1:end-delay)];
% Apply frequency offset % Apply frequency offset

@ -0,0 +1,133 @@
clear
ueConfig=struct('NCellID',1,'RNTI',11,'NULRB',25,'NSubframe',0,'CyclicPrefixUL','Normal','NTxAnts',1,'Hopping','Off');
pucchConfig=struct('NLayers',1,'OrthCover','Off','Shortened',0,'ResourceSize',2);
format_str={'1','1a'};
threshold=[0.5 0];
formats=[1];
pucchConfig.ResourceIdx= 0;
pucchConfig.DeltaShift = 1;
pucchConfig.CyclicShifts = 0;
ueConfig.NSubframe=0;
enable_fading=false;
SNR_values=-5;%linspace(-8,0,8);
Nreal=50;
% Setup Fading channel model
cfg.Seed = 8; % Random channel seed
cfg.NRxAnts = 1; % 1 receive antenna
cfg.DelayProfile = 'EVA'; % EVA delay spread
cfg.DopplerFreq = 5; % 120Hz Doppler frequency
cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation
cfg.InitTime = 0; % Initialize at time zero
cfg.NTerms = 16; % Oscillators used in fading model
cfg.ModelType = 'GMEDS'; % Rayleigh fading model type
cfg.InitPhase = 'Random'; % Random initial phases
cfg.NormalizePathGains = 'On'; % Normalize delay profile power
cfg.NormalizeTxAnts = 'On'; % Normalize for transmit antennas
% Setup matlab channel equalizer
cec.PilotAverage = 'UserDefined'; % Type of pilot averaging
cec.FreqWindow = 9; % Frequency window size
cec.TimeWindow = 9; % Time window size
cec.InterpType = 'linear'; % 2D interpolation type
cec.InterpWindow = 'Causal'; % Interpolation window type
cec.InterpWinSize = 1; % Interpolation window size
addpath('../../debug/srslte/lib/phch/test')
ber=zeros(length(formats),length(SNR_values));
ber2=zeros(length(formats),length(SNR_values));
for f=1:length(formats)
nb=formats(f);
for s=1:length(SNR_values)
SNRdB=SNR_values(s);
SNR = 10^(SNRdB/10); % Linear SNR
errors = 0;
errors2 = 0;
for n=1:Nreal
bits=randi(2,nb-1,1)-1;
[sym_mat, info]=ltePUCCH1(ueConfig,pucchConfig,bits);
idx=ltePUCCH1Indices(ueConfig,pucchConfig);
[dmrs_mat, info_dmrs]=ltePUCCH1DRS(ueConfig,pucchConfig);
idx_dmrs=ltePUCCH1DRSIndices(ueConfig,pucchConfig);
% Resource mapping
subframe_tx = lteULResourceGrid(ueConfig);
subframe_tx(idx)=sym_mat;
subframe_tx(idx_dmrs)=dmrs_mat;
[txWaveform, info] = lteSCFDMAModulate(ueConfig,subframe_tx);
cfg.SamplingRate = info.SamplingRate;
% Fading
if (enable_fading)
rxWaveform = lteFadingChannel(cfg,txWaveform);
else
rxWaveform = txWaveform;
end
% Noise Addition
N0 = 1/(sqrt(2.0*double(info.Nfft))*SNR);
noise = N0*complex(randn(size(rxWaveform)), randn(size(rxWaveform))); % Generate noise
rxWaveform = rxWaveform + noise;
% Demodulate
subframe_rx = lteSCFDMADemodulate(ueConfig, rxWaveform);
% Perform channel estimation
[hest, nest] = lteULChannelEstimatePUCCH1(ueConfig, pucchConfig, cec, subframe_rx);
% Equalize
pucchSymbols = lteEqualizeMMSE(subframe_rx(idx), hest(idx), nest);
% Decoding
bits_rx = ltePUCCH1Decode(ueConfig, pucchConfig, length(bits), pucchSymbols);
% Check errors
a=size(bits_rx);
if (a(2) ~= 1)
errors = errors + 1;
elseif (formats(f) == 2)
if (a(1) ~= 1)
errors = errors + 1;
elseif (bits_rx(1) ~= bits(1))
errors = errors + 1;
end
end
% Decoding srsLTE
[bits_rx,z,ce]= srslte_pucch(ueConfig, pucchConfig, length(bits), subframe_rx, threshold);
% Check errors
a=size(bits_rx);
if (a(2) ~= 1)
errors2 = errors2 + 1;
elseif (formats(f) == 2)
if (a(1) ~= 1)
errors2 = errors2 + 1;
elseif (bits_rx(1) ~= bits(1))
errors2 = errors2 + 1;
end
end
end
ber(f,s)=errors/Nreal;
ber2(f,s)=errors2/Nreal;
fprintf('Format %s, SNR=%.1f dB, errors=%d, errors2=%d\n', format_str{formats(f)},SNRdB,errors,errors2);
end
end
semilogy(SNR_values,ber,SNR_values,ber2)
xlabel('SNR (dB)')
ylabel('BER')
grid on
legend(format_str(formats))

@ -3,11 +3,11 @@ puschConfig=struct('NLayers',1,'OrthCover','Off','Shortened',0,'NBundled',0);
addpath('../../build//srslte/lib/phch/test') addpath('../../build//srslte/lib/phch/test')
cqilen=[0 4 20]; cqilen=0;%[0 4 20];
mods={'64QAM'}; mods={'64QAM'};
rvs=0; rvs=0;
betas=[0 5.0, 20.0]; betas=0;%[0 5.0, 20.0];
for p=1:ueConfig.NULRB for p=1
for i=0:26 for i=0:26
for m=1:length(mods) for m=1:length(mods)
for r=1:length(rvs) for r=1:length(rvs)

@ -307,8 +307,7 @@ int main(int argc, char **argv) {
case DECODE_SIB: case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */ /* We are looking for SI Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = srslte_ue_dl_decode_rnti_rv(&ue_dl, sf_buffer, data, srslte_ue_sync_get_sfidx(&ue_sync), SRSLTE_SIRNTI, n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1; return -1;
@ -357,7 +356,7 @@ int main(int argc, char **argv) {
printf("CFO: %+8.4f kHz, SFO: %+8.4f kHz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, " printf("CFO: %+8.4f kHz, SFO: %+8.4f kHz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r", "RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r",
srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync),
10*log10(rssi*1000) - rx_gain_offset, 10*log10(rssi*1000) - rx_gain_offset,
10*log10(rssi_utra*1000)- rx_gain_offset, 10*log10(rssi_utra*1000)- rx_gain_offset,
10*log10(rsrp*1000) - rx_gain_offset, 10*log10(rsrp*1000) - rx_gain_offset,

@ -426,6 +426,7 @@ int main(int argc, char **argv) {
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) { if (!prog_args.disable_plots) {
init_plots(cell); init_plots(cell);
sleep(1);
} }
#endif #endif
@ -494,7 +495,7 @@ int main(int argc, char **argv) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
/* We are looking for SIB1 Blocks, search only in appropiate places */ /* We are looking for SIB1 Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%8)==0)) { if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
decode_pdsch = false; decode_pdsch = false;
@ -502,28 +503,15 @@ int main(int argc, char **argv) {
} }
if (decode_pdsch) { if (decode_pdsch) {
INFO("Attempting DL decode SFN=%d\n", sfn); INFO("Attempting DL decode SFN=%d\n", sfn);
if (prog_args.rnti != SRSLTE_SIRNTI) { n = srslte_ue_dl_decode(&ue_dl,
n = srslte_ue_dl_decode(&ue_dl, &sf_buffer[prog_args.time_offset], data, srslte_ue_sync_get_sfidx(&ue_sync)); &sf_buffer[prog_args.time_offset],
} else { data,
// RV for SIB1 is predefined sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
uint32_t k = (sfn/2)%4;
uint32_t rv = ((uint32_t) ceilf((float)1.5*k))%4;
n = srslte_ue_dl_decode_rnti_rv(&ue_dl, &sf_buffer[prog_args.time_offset], data,
srslte_ue_sync_get_sfidx(&ue_sync),
SRSLTE_SIRNTI, rv);
/*
if (n>0) {
printf("Saving signal...\n");
srslte_ue_dl_save_signal(&ue_dl, &ue_dl.softbuffer, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), rv, prog_args.rnti);
exit(-1);
}
*/
}
if (n < 0) { if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
} else if (n > 0) { } else if (n > 0) {
/* Send data if socket active */ /* Send data if socket active */
if (prog_args.net_port > 0) { if (prog_args.net_port > 0) {
srslte_netsink_write(&net_sink, data, 1+(n-1)/8); srslte_netsink_write(&net_sink, data, 1+(n-1)/8);

@ -57,6 +57,7 @@ typedef struct {
cf_t *pilot_estimates; cf_t *pilot_estimates;
cf_t *pilot_recv_signal; cf_t *pilot_recv_signal;
cf_t *pilot_known_signal;
cf_t *tmp_noise; cf_t *tmp_noise;
#ifdef FREQ_SEL_SNR #ifdef FREQ_SEL_SNR
@ -99,6 +100,13 @@ SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q,
uint32_t cyclic_shift_for_dmrs, uint32_t cyclic_shift_for_dmrs,
uint32_t n_prb[2]); uint32_t n_prb[2]);
SRSLTE_API int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q,
cf_t *input,
cf_t *ce,
srslte_pucch_format_t format,
uint32_t n_pucch,
uint32_t sf_idx);
SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q); SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q);
SRSLTE_API float srslte_chest_ul_get_snr(srslte_chest_ul_t *q); SRSLTE_API float srslte_chest_ul_get_snr(srslte_chest_ul_t *q);

@ -46,6 +46,7 @@
#define SRSLTE_REFSIGNAL_UL_L(ns_idx, cp) ((ns_idx+1)*SRSLTE_CP_NSYMB(cp)-4) #define SRSLTE_REFSIGNAL_UL_L(ns_idx, cp) ((ns_idx+1)*SRSLTE_CP_NSYMB(cp)-4)
/* PUSCH DMRS common configuration (received in SIB2) */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint32_t cyclic_shift; uint32_t cyclic_shift;
uint32_t delta_ss; uint32_t delta_ss;
@ -53,15 +54,19 @@ typedef struct SRSLTE_API {
bool sequence_hopping_en; bool sequence_hopping_en;
}srslte_refsignal_dmrs_pusch_cfg_t; }srslte_refsignal_dmrs_pusch_cfg_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
// Common Configuration
uint32_t subframe_config; uint32_t subframe_config;
uint32_t I_srs;
uint32_t bw_cfg; uint32_t bw_cfg;
// Dedicated configuration
uint32_t B;
uint32_t b_hop;
uint32_t n_srs; uint32_t n_srs;
uint32_t I_srs;
uint32_t k_tc; uint32_t k_tc;
uint32_t n_rrc; uint32_t n_rrc;
uint32_t B;
uint32_t b_hop;
bool configured; bool configured;
}srslte_refsignal_srs_cfg_t; }srslte_refsignal_srs_cfg_t;
@ -101,6 +106,13 @@ SRSLTE_API void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q,
SRSLTE_API void srslte_refsignal_r_uv_arg_1prb(float *arg, SRSLTE_API void srslte_refsignal_r_uv_arg_1prb(float *arg,
uint32_t u); uint32_t u);
SRSLTE_API uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format,
srslte_cp_t cp);
SRSLTE_API uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m,
srslte_pucch_format_t format,
srslte_cp_t cp);
SRSLTE_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, SRSLTE_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q,
srslte_refsignal_dmrs_pusch_cfg_t *cfg, srslte_refsignal_dmrs_pusch_cfg_t *cfg,
uint32_t nof_prb); uint32_t nof_prb);
@ -150,6 +162,12 @@ SRSLTE_API int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q,
cf_t *r_pucch, cf_t *r_pucch,
cf_t *output); cf_t *output);
SRSLTE_API int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t* q,
srslte_pucch_format_t format,
uint32_t n_pucch,
cf_t *input,
cf_t *r_pucch);
SRSLTE_API int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q, SRSLTE_API int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q,
srslte_refsignal_srs_pregen_t *pregen); srslte_refsignal_srs_pregen_t *pregen);

@ -92,7 +92,7 @@ typedef struct SRSLTE_API {
} srslte_enb_dl_t; } srslte_enb_dl_t;
typedef struct { typedef struct {
uint32_t rnti_idx; int rnti_idx;
srslte_ra_dl_dci_t grant; srslte_ra_dl_dci_t grant;
srslte_dci_location_t location; srslte_dci_location_t location;
srslte_softbuffer_tx_t *softbuffer; srslte_softbuffer_tx_t *softbuffer;
@ -101,7 +101,7 @@ typedef struct {
typedef struct { typedef struct {
uint8_t ack; uint8_t ack;
uint32_t rnti_idx; int rnti_idx;
} srslte_enb_dl_phich_t; } srslte_enb_dl_phich_t;
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */

@ -73,11 +73,20 @@ typedef struct SRSLTE_API {
srslte_prach_t prach; srslte_prach_t prach;
srslte_pusch_cfg_t pusch_cfg; srslte_pusch_cfg_t pusch_cfg;
srslte_pusch_hopping_cfg_t hopping_cfg;
// Configuration for each user
bool *uci_cfg_en;
bool *srs_cfg_en;
srslte_uci_cfg_t *uci_cfg;
srslte_refsignal_srs_cfg_t *srs_cfg;
srslte_pucch_sched_t *pucch_sched;
} srslte_enb_ul_t; } srslte_enb_ul_t;
typedef struct { typedef struct {
uint32_t rnti_idx; int rnti_idx;
srslte_ra_ul_dci_t grant; srslte_ra_ul_dci_t grant;
srslte_dci_location_t location; srslte_dci_location_t location;
uint32_t rv_idx; uint32_t rv_idx;
@ -85,6 +94,7 @@ typedef struct {
bool needs_pdcch; bool needs_pdcch;
uint8_t *data; uint8_t *data;
srslte_softbuffer_rx_t *softbuffer; srslte_softbuffer_rx_t *softbuffer;
} srslte_enb_ul_pusch_t; } srslte_enb_ul_pusch_t;
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */
@ -92,6 +102,7 @@ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q,
srslte_cell_t cell, srslte_cell_t cell,
srslte_prach_cfg_t* prach_cfg, srslte_prach_cfg_t* prach_cfg,
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
srslte_pusch_hopping_cfg_t *hopping_cfg,
srslte_pucch_cfg_t *pucch_cfg, srslte_pucch_cfg_t *pucch_cfg,
uint32_t nof_rntis); uint32_t nof_rntis);
@ -101,12 +112,24 @@ SRSLTE_API int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q,
uint32_t idx, uint32_t idx,
uint16_t rnti); uint16_t rnti);
SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx,
srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg);
SRSLTE_API int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, SRSLTE_API int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q,
uint32_t idx); uint32_t idx);
SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q, SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q,
cf_t *signal_buffer); cf_t *signal_buffer);
SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q,
uint32_t rnti_idx,
uint32_t pdcch_n_cce,
uint32_t sf_rx,
srslte_uci_data_t *uci_data);
SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q,
srslte_ra_ul_grant_t *grant, srslte_ra_ul_grant_t *grant,
srslte_softbuffer_rx_t *softbuffer, srslte_softbuffer_rx_t *softbuffer,
@ -123,7 +146,7 @@ SRSLTE_API int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q,
cf_t *signal, cf_t *signal,
uint32_t *indices, uint32_t *indices,
float *offsets, float *offsets,
float *peak2avg); float *peak2avg);
#endif #endif

@ -90,6 +90,9 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q,
SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q);
SRSLTE_API void srslte_pdcch_set_cfi(srslte_pdcch_t *q,
uint32_t cfi);
/* Encoding function */ /* Encoding function */
SRSLTE_API int srslte_pdcch_encode(srslte_pdcch_t *q, SRSLTE_API int srslte_pdcch_encode(srslte_pdcch_t *q,
srslte_dci_msg_t *msg, srslte_dci_msg_t *msg,

@ -110,7 +110,8 @@ typedef enum SRSLTE_API {
typedef struct { typedef struct {
uint32_t config_idx; uint32_t config_idx;
uint32_t root_seq_idx; uint32_t root_seq_idx;
uint32_t zero_corr_zone; uint32_t zero_corr_zone;
uint32_t freq_offset;
bool hs_flag; bool hs_flag;
} srslte_prach_cfg_t; } srslte_prach_cfg_t;
@ -155,7 +156,7 @@ SRSLTE_API int srslte_prach_detect_offset(srslte_prach_t *p,
uint32_t sig_len, uint32_t sig_len,
uint32_t *indices, uint32_t *indices,
float *t_offsets, float *t_offsets,
float *peak_to_avg, float *peak_to_avg,
uint32_t *ind_len); uint32_t *ind_len);
SRSLTE_API void srslte_prach_set_detect_factor(srslte_prach_t *p, SRSLTE_API void srslte_prach_set_detect_factor(srslte_prach_t *p,

@ -40,10 +40,11 @@
#include "srslte/common/sequence.h" #include "srslte/common/sequence.h"
#include "srslte/modem/mod.h" #include "srslte/modem/mod.h"
#include "srslte/phch/cqi.h" #include "srslte/phch/cqi.h"
#include "srslte/phch/uci.h"
#define SRSLTE_PUCCH_N_SEQ 12 #define SRSLTE_PUCCH_N_SEQ 12
#define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS #define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS
#define SRSLTE_PUCCH_MAX_SYMBOLS 120 #define SRSLTE_PUCCH_MAX_SYMBOLS 120
typedef enum SRSLTE_API { typedef enum SRSLTE_API {
SRSLTE_PUCCH_FORMAT_1 = 0, SRSLTE_PUCCH_FORMAT_1 = 0,
@ -51,7 +52,8 @@ typedef enum SRSLTE_API {
SRSLTE_PUCCH_FORMAT_1B, SRSLTE_PUCCH_FORMAT_1B,
SRSLTE_PUCCH_FORMAT_2, SRSLTE_PUCCH_FORMAT_2,
SRSLTE_PUCCH_FORMAT_2A, SRSLTE_PUCCH_FORMAT_2A,
SRSLTE_PUCCH_FORMAT_2B SRSLTE_PUCCH_FORMAT_2B,
SRSLTE_PUCCH_FORMAT_ERROR,
} srslte_pucch_format_t; } srslte_pucch_format_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
@ -64,15 +66,19 @@ typedef struct SRSLTE_API {
}srslte_pucch_sched_t; }srslte_pucch_sched_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
// Common configuration
uint32_t delta_pucch_shift; uint32_t delta_pucch_shift;
uint32_t n_rb_2; uint32_t n_rb_2;
uint32_t N_cs; uint32_t N_cs;
uint32_t n1_pucch_an;
// SRS configuration
bool srs_configured; bool srs_configured;
uint32_t srs_cs_subf_cfg; uint32_t srs_cs_subf_cfg;
bool srs_simul_ack; bool srs_simul_ack;
} srslte_pucch_cfg_t; } srslte_pucch_cfg_t;
/* PUSCH object */ /* PUCCH object */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cell_t cell; srslte_cell_t cell;
srslte_pucch_cfg_t pucch_cfg; srslte_pucch_cfg_t pucch_cfg;
@ -84,10 +90,19 @@ typedef struct SRSLTE_API {
uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB];
uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME]; uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME];
float tmp_arg[SRSLTE_PUCCH_N_SEQ]; float tmp_arg[SRSLTE_PUCCH_N_SEQ];
cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS];
cf_t *z;
cf_t *z_tmp;
cf_t *ce;
bool rnti_is_set; bool rnti_is_set;
bool shortened; bool shortened;
bool group_hopping_en; bool group_hopping_en;
float threshold_format1;
float threshold_format1a;
float last_corr;
}srslte_pucch_t; }srslte_pucch_t;
@ -100,6 +115,10 @@ SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q,
srslte_pucch_cfg_t* cfg, srslte_pucch_cfg_t* cfg,
bool group_hopping_en); bool group_hopping_en);
SRSLTE_API void srslte_pucch_set_threshold(srslte_pucch_t *q,
float format1,
float format1a);
SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q, SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q,
uint16_t c_rnti); uint16_t c_rnti);
@ -107,6 +126,8 @@ SRSLTE_API uint32_t srslte_pucch_nof_symbols(srslte_pucch_cfg_t *cfg,
srslte_pucch_format_t format, srslte_pucch_format_t format,
bool shortened); bool shortened);
SRSLTE_API float srslte_pucch_get_last_corr(srslte_pucch_t* q);
SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q, SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q,
srslte_pucch_format_t format, srslte_pucch_format_t format,
uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format
@ -114,6 +135,15 @@ SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint8_t bits[SRSLTE_PUCCH_MAX_BITS],
cf_t *sf_symbols); cf_t *sf_symbols);
SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q,
srslte_pucch_format_t format,
uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format
uint32_t sf_idx,
cf_t *sf_symbols,
cf_t *ce,
float noise_estimate,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS]);
SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB],
srslte_pucch_cfg_t *cfg, srslte_pucch_cfg_t *cfg,
uint32_t n_pucch, uint32_t n_pucch,
@ -135,6 +165,21 @@ SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg,
uint32_t n_pucch, uint32_t n_pucch,
srslte_cp_t cp); srslte_cp_t cp);
SRSLTE_API srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data,
srslte_cp_t cp);
SRSLTE_API uint32_t srslte_pucch_get_npucch(uint32_t n_cce,
srslte_pucch_format_t format,
bool has_scheduling_request,
srslte_pucch_sched_t *pucch_sched);
SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg,
srslte_pucch_format_t format,
uint32_t n_pucch,
uint32_t nof_prb,
srslte_cp_t cp,
uint32_t ns);
SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell, SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell,
uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]); uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]);

@ -76,6 +76,7 @@ typedef struct SRSLTE_API {
uint32_t max_offset; uint32_t max_offset;
bool enable_cfo_corr; bool enable_cfo_corr;
float mean_cfo; float mean_cfo;
float mean_cfo2;
int cfo_i; int cfo_i;
bool find_cfo_i; bool find_cfo_i;
bool find_cfo_i_initiated; bool find_cfo_i_initiated;
@ -83,6 +84,7 @@ typedef struct SRSLTE_API {
uint32_t nof_symbols; uint32_t nof_symbols;
uint32_t cp_len; uint32_t cp_len;
srslte_cfo_t cfocorr; srslte_cfo_t cfocorr;
srslte_cfo_t cfocorr2;
sss_alg_t sss_alg; sss_alg_t sss_alg;
bool detect_cp; bool detect_cp;
bool sss_en; bool sss_en;
@ -93,6 +95,7 @@ typedef struct SRSLTE_API {
float m1_value; float m1_value;
float M_norm_avg; float M_norm_avg;
float M_ext_avg; float M_ext_avg;
cf_t *temp;
}srslte_sync_t; }srslte_sync_t;

@ -60,6 +60,18 @@
#include "srslte/config.h" #include "srslte/config.h"
#define MAX_CANDIDATES_UE 16 // From 36.213 Table 9.1.1-1
#define MAX_CANDIDATES_COM 6 // From 36.213 Table 9.1.1-1
#define MAX_CANDIDATES (MAX_CANDIDATES_UE + MAX_CANDIDATES_COM)
typedef struct {
srslte_dci_format_t format;
srslte_dci_location_t loc[MAX_CANDIDATES];
uint32_t nof_locations;
} dci_blind_search_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_pcfich_t pcfich; srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch;
@ -85,7 +97,10 @@ typedef struct SRSLTE_API {
uint64_t nof_detected; uint64_t nof_detected;
uint16_t current_rnti; uint16_t current_rnti;
dci_blind_search_t current_ss_ue[3][10];
dci_blind_search_t current_ss_common[3];
srslte_dci_location_t last_location; srslte_dci_location_t last_location;
srslte_dci_location_t last_location_ul;
srslte_dci_msg_t pending_ul_dci_msg; srslte_dci_msg_t pending_ul_dci_msg;
uint16_t pending_ul_dci_rnti; uint16_t pending_ul_dci_rnti;
@ -141,21 +156,14 @@ SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q,
cf_t *input, cf_t *input,
uint8_t *data, uint8_t *data,
uint32_t sf_idx); uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
cf_t *input, cf_t *input,
uint8_t *data, uint8_t *data,
uint32_t sf_idx, uint32_t tti,
uint16_t rnti); uint16_t rnti);
SRSLTE_API int srslte_ue_dl_decode_rnti_rv(srslte_ue_dl_t * q,
cf_t *input,
uint8_t * data,
uint32_t sf_idx,
uint16_t rnti,
uint32_t rvidx);
SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t n_prb_lowest, uint32_t n_prb_lowest,

@ -84,6 +84,12 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
goto clean_exit; goto clean_exit;
} }
q->pilot_known_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1));
if (!q->pilot_known_signal) {
perror("malloc");
goto clean_exit;
}
if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, NOF_REFS_SYM)) { if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, NOF_REFS_SYM)) {
fprintf(stderr, "Error initializing vector interpolator\n"); fprintf(stderr, "Error initializing vector interpolator\n");
goto clean_exit; goto clean_exit;
@ -122,6 +128,9 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q)
if (q->pilot_recv_signal) { if (q->pilot_recv_signal) {
free(q->pilot_recv_signal); free(q->pilot_recv_signal);
} }
if (q->pilot_known_signal) {
free(q->pilot_known_signal);
}
bzero(q, sizeof(srslte_chest_ul_t)); bzero(q, sizeof(srslte_chest_ul_t));
} }
@ -252,6 +261,63 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
return 0; return 0;
} }
int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx)
{
if (!q->dmrs_signal_configured) {
fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n");
return SRSLTE_ERROR;
}
int n_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp);
if (!n_rs) {
fprintf(stderr, "Error computing N_rs\n");
return SRSLTE_ERROR;
}
int nrefs_sf = SRSLTE_NRE*n_rs*2;
/* Get references from the input signal */
srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, format, n_pucch, input, q->pilot_recv_signal);
/* Generate known pilots */
uint8_t pucch2_bits[2] = {0, 0};
srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal),
/* Use the known DMRS signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf);
if (ce != NULL) {
/* FIXME: Currently averaging entire slot, performance good enough? */
for (int ns=0;ns<2;ns++) {
// Average all slot
for (int i=1;i<n_rs;i++) {
srslte_vec_sum_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_estimates[(i+ns*n_rs)*SRSLTE_NRE],
&q->pilot_estimates[ns*n_rs*SRSLTE_NRE],
SRSLTE_NRE);
}
srslte_vec_sc_prod_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], (float) 1.0/n_rs,
&q->pilot_estimates[ns*n_rs*SRSLTE_NRE],
SRSLTE_NRE);
// Average in freq domain
srslte_chest_average_pilots(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE],
q->smooth_filter, SRSLTE_NRE, 1, q->smooth_filter_len);
// Determine n_prb
uint32_t n_prb = srslte_pucch_n_prb(&q->dmrs_signal.pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns);
// copy estimates to slot
for (int i=0;i<SRSLTE_CP_NSYMB(q->cell.cp);i++) {
memcpy(&ce[SRSLTE_RE_IDX(q->cell.nof_prb, i+ns*SRSLTE_CP_NSYMB(q->cell.cp), n_prb*SRSLTE_NRE)],
&q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], sizeof(cf_t)*SRSLTE_NRE);
}
}
}
return 0;
}
float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q) { float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q) {
return q->noise_estimate; return q->noise_estimate;
} }

@ -452,7 +452,7 @@ int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t *q, uint32_t nof_prb,
} }
/* Number of PUCCH demodulation reference symbols per slot N_rs_pucch tABLE 5.5.2.2.1-1 36.211 */ /* Number of PUCCH demodulation reference symbols per slot N_rs_pucch tABLE 5.5.2.2.1-1 36.211 */
static uint32_t get_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) { uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) {
switch (format) { switch (format) {
case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1:
case SRSLTE_PUCCH_FORMAT_1A: case SRSLTE_PUCCH_FORMAT_1A:
@ -471,12 +471,15 @@ static uint32_t get_N_rs(srslte_pucch_format_t format, srslte_cp_t cp) {
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
return 2; return 2;
default:
fprintf(stderr, "Unsupported format %d\n", format);
return 0;
} }
return 0; return 0;
} }
/* Table 5.5.2.2.2-1: Demodulation reference signal location for different PUCCH formats. 36.211 */ /* Table 5.5.2.2.2-1: Demodulation reference signal location for different PUCCH formats. 36.211 */
static uint32_t get_pucch_dmrs_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) {
switch (format) { switch (format) {
case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1:
case SRSLTE_PUCCH_FORMAT_1A: case SRSLTE_PUCCH_FORMAT_1A:
@ -523,7 +526,7 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma
if (q && r_pucch) { if (q && r_pucch) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
uint32_t N_rs=get_N_rs(format, q->cell.cp); uint32_t N_rs=srslte_refsignal_dmrs_N_rs(format, q->cell.cp);
cf_t z_m_1 = 1.0; cf_t z_m_1 = 1.0;
if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) {
@ -543,7 +546,7 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma
for (uint32_t m=0;m<N_rs;m++) { for (uint32_t m=0;m<N_rs;m++) {
uint32_t n_oc=0; uint32_t n_oc=0;
uint32_t l = get_pucch_dmrs_symbol(m, format, q->cell.cp); uint32_t l = srslte_refsignal_dmrs_pucch_symbol(m, format, q->cell.cp);
// Add cyclic prefix alpha // Add cyclic prefix alpha
float alpha = 0.0; float alpha = 0.0;
if (format < SRSLTE_PUCCH_FORMAT_2) { if (format < SRSLTE_PUCCH_FORMAT_2) {
@ -575,18 +578,17 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
w=w_arg_pucch_format2_cpnorm; w=w_arg_pucch_format2_cpnorm;
break; break;
default:
fprintf(stderr, "Unsupported format %d\n", format);
return SRSLTE_ERROR;
} }
cf_t z_m = 1.0; cf_t z_m = 1.0;
if (m == 1) { if (m == 1) {
z_m = z_m_1; z_m = z_m_1;
} }
if (w) { for (uint32_t n=0;n<SRSLTE_NRE;n++) {
for (uint32_t n=0;n<SRSLTE_NRE;n++) { r_pucch[(ns%2)*SRSLTE_NRE*N_rs+m*SRSLTE_NRE+n] = z_m*cexpf(I*(w[m]+q->tmp_arg[n]+alpha*n));
r_pucch[(ns%2)*SRSLTE_NRE*N_rs+m*SRSLTE_NRE+n] = z_m*cexpf(I*(w[m]+q->tmp_arg[n]+alpha*n)); }
}
} else {
return SRSLTE_ERROR;
}
} }
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
@ -594,36 +596,48 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma
return ret; return ret;
} }
/* Maps PUCCH DMRS to the physical resources as defined in 5.5.2.2.2 in 36.211 */ int srslte_refsignal_dmrs_pucch_cp(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid)
int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *r_pucch, cf_t *output)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q && output && r_pucch) { if (q && source && dest) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB;
// Determine m uint32_t N_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp);
uint32_t m = srslte_pucch_m(&q->pucch_cfg, format, n_pucch, q->cell.cp);
uint32_t N_rs = get_N_rs(format, q->cell.cp);
for (uint32_t ns=0;ns<2;ns++) { for (uint32_t ns=0;ns<2;ns++) {
// Determine n_prb
uint32_t n_prb = m/2; // Determine n_prb
if ((m+ns)%2) { uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns);
n_prb = q->cell.nof_prb-1-m/2;
}
for (uint32_t i=0;i<N_rs;i++) { for (uint32_t i=0;i<N_rs;i++) {
uint32_t l = get_pucch_dmrs_symbol(i, format, q->cell.cp); uint32_t l = srslte_refsignal_dmrs_pucch_symbol(i, format, q->cell.cp);
memcpy(&output[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], if (!source_is_grid) {
&r_pucch[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)],
SRSLTE_NRE*sizeof(cf_t)); &source[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE],
SRSLTE_NRE*sizeof(cf_t));
} else {
memcpy(&dest[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE],
&source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)],
SRSLTE_NRE*sizeof(cf_t));
}
} }
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
return ret; return ret;
}
/* Maps PUCCH DMRS to the physical resources as defined in 5.5.2.2.2 in 36.211 */
int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *r_pucch, cf_t *output)
{
return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, r_pucch, output, false);
}
/* Gets PUCCH DMRS from the physical resources as defined in 5.5.2.2.2 in 36.211 */
int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *r_pucch)
{
return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, input, r_pucch, true);
} }

@ -37,7 +37,7 @@
#define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define SRSLTE_ENB_RF_AMP 0.8 #define SRSLTE_ENB_RF_AMP 0.5
int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell, uint32_t nof_rnti) int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell, uint32_t nof_rnti)
{ {

@ -42,6 +42,7 @@
int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell,
srslte_prach_cfg_t *prach_cfg, srslte_prach_cfg_t *prach_cfg,
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
srslte_pusch_hopping_cfg_t *hopping_cfg,
srslte_pucch_cfg_t *pucch_cfg, srslte_pucch_cfg_t *pucch_cfg,
uint32_t nof_rnti) uint32_t nof_rnti)
{ {
@ -57,11 +58,22 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell,
q->cell = cell; q->cell = cell;
q->nof_rnti = nof_rnti; q->nof_rnti = nof_rnti;
if (hopping_cfg) {
memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t));
}
q->uci_cfg_en = calloc(sizeof(bool), nof_rnti);
q->srs_cfg_en = calloc(sizeof(bool), nof_rnti);
q->uci_cfg = calloc(sizeof(srslte_uci_cfg_t), nof_rnti);
q->srs_cfg = calloc(sizeof(srslte_refsignal_srs_cfg_t), nof_rnti);
q->pucch_sched = calloc(sizeof(srslte_pucch_sched_t), nof_rnti);
if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n"); fprintf(stderr, "Error initiating FFT\n");
goto clean_exit; goto clean_exit;
} }
srslte_ofdm_set_normalize(&q->fft, true); srslte_ofdm_set_normalize(&q->fft, false);
srslte_ofdm_set_freq_shift(&q->fft, -0.5); srslte_ofdm_set_freq_shift(&q->fft, -0.5);
if (srslte_pucch_init(&q->pucch, q->cell)) { if (srslte_pucch_init(&q->pucch, q->cell)) {
@ -86,11 +98,16 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell,
srslte_prach_set_detect_factor(&q->prach, 60); srslte_prach_set_detect_factor(&q->prach, 60);
srslte_pucch_set_threshold(&q->pucch, 0.5, 0.5);
if (srslte_chest_ul_init(&q->chest, cell)) { if (srslte_chest_ul_init(&q->chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n"); fprintf(stderr, "Error initiating channel estimator\n");
goto clean_exit; goto clean_exit;
} }
// Configure common PUCCH configuration
srslte_pucch_set_cfg(&q->pucch, pucch_cfg, pusch_cfg->group_hopping_en);
// SRS is a dedicated configuration // SRS is a dedicated configuration
srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL); srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL);
@ -123,6 +140,23 @@ clean_exit:
void srslte_enb_ul_free(srslte_enb_ul_t *q) void srslte_enb_ul_free(srslte_enb_ul_t *q)
{ {
if (q) { if (q) {
if (q->uci_cfg) {
free(q->uci_cfg);
}
if (q->uci_cfg_en) {
free(q->uci_cfg_en);
}
if (q->srs_cfg) {
free(q->srs_cfg);
}
if (q->srs_cfg_en) {
free(q->srs_cfg_en);
}
if (q->pucch_sched) {
free(q->pucch_sched);
}
srslte_prach_free(&q->prach); srslte_prach_free(&q->prach);
srslte_ofdm_rx_free(&q->fft); srslte_ofdm_rx_free(&q->fft);
srslte_pucch_free(&q->pucch); srslte_pucch_free(&q->pucch);
@ -143,6 +177,34 @@ int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q, uint32_t idx, uint16_t rnti)
return srslte_pusch_set_rnti_multi(&q->pusch, idx, rnti); return srslte_pusch_set_rnti_multi(&q->pusch, idx, rnti);
} }
int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx,
srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg)
{
if (idx < q->nof_rnti) {
if (uci_cfg) {
memcpy(&q->uci_cfg[idx], uci_cfg, sizeof(srslte_uci_cfg_t));
q->uci_cfg_en[idx] = true;
} else {
q->uci_cfg_en[idx] = false;
}
if (pucch_sched) {
memcpy(&q->pucch_sched[idx], pucch_sched, sizeof(srslte_pucch_sched_t));
}
if (srs_cfg) {
memcpy(&q->srs_cfg[idx], srs_cfg, sizeof(srslte_refsignal_srs_cfg_t));
q->srs_cfg_en[idx] = true;
} else {
q->srs_cfg_en[idx] = false;
}
return SRSLTE_SUCCESS;
} else {
fprintf(stderr, "Error configuring UE: Invalid idx=%d, max users=%d\n", idx, q->nof_rnti);
return SRSLTE_ERROR;
}
}
int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint32_t idx) int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint32_t idx)
{ {
return srslte_pusch_set_rnti_multi(&q->pusch, idx, 0); return srslte_pusch_set_rnti_multi(&q->pusch, idx, 0);
@ -153,12 +215,79 @@ void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer)
srslte_ofdm_rx_sf(&q->fft, signal_buffer, q->sf_symbols); srslte_ofdm_rx_sf(&q->fft, signal_buffer, q->sf_symbols);
} }
int get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx,
uint32_t pdcch_n_cce, uint32_t sf_rx,
srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
{
float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest);
srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp);
uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->pucch_sched[rnti_idx]);
if (srslte_chest_ul_estimate_pucch(&q->chest, q->sf_symbols, q->ce, format, n_pucch, sf_rx)) {
fprintf(stderr,"Error estimating PUCCH DMRS\n");
return SRSLTE_ERROR;
}
int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, q->sf_symbols, q->ce, noise_power, bits);
if (ret_val < 0) {
fprintf(stderr,"Error decoding PUCCH\n");
return SRSLTE_ERROR;
}
return ret_val;
}
int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx,
uint32_t pdcch_n_cce, uint32_t sf_rx,
srslte_uci_data_t *uci_data)
{
uint8_t bits[SRSLTE_PUCCH_MAX_BITS];
if (rnti_idx < q->nof_rnti) {
int ret_val = get_pucch(q, rnti_idx, pdcch_n_cce, sf_rx, uci_data, bits);
// If we are looking for SR and ACK at the same time and ret=0, means there is no SR.
// try again to decode ACK only
if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) {
uci_data->scheduling_request = false;
ret_val = get_pucch(q, rnti_idx, pdcch_n_cce, sf_rx, uci_data, bits);
}
// update schedulign request
if (uci_data->scheduling_request) {
uci_data->scheduling_request = (ret_val==1);
}
// Save ACK bits
if (uci_data->uci_ack_len > 0) {
if (ret_val > 0) {
uci_data->uci_ack = bits[0];
} else {
uci_data->uci_ack = 0;
}
}
return SRSLTE_SUCCESS;
} else {
fprintf(stderr, "Invalid rnti_idx=%d\n", rnti_idx);
return SRSLTE_ERROR;
}
}
int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer,
uint32_t rnti_idx, uint32_t rv_idx, uint32_t current_tx_nb, uint32_t rnti_idx, uint32_t rv_idx, uint32_t current_tx_nb,
uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti)
{ {
if (srslte_pusch_cfg(&q->pusch, &q->pusch_cfg, grant, NULL, NULL, NULL, tti, rv_idx, current_tx_nb)) { if (srslte_pusch_cfg(&q->pusch,
&q->pusch_cfg,
grant,
q->uci_cfg_en[rnti_idx]?&q->uci_cfg[rnti_idx]:NULL,
&q->hopping_cfg,
q->srs_cfg_en[rnti_idx]?&q->srs_cfg[rnti_idx]:NULL,
tti, rv_idx, current_tx_nb)) {
fprintf(stderr, "Error configuring PDSCH\n"); fprintf(stderr, "Error configuring PDSCH\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -33,15 +33,28 @@ struct v37 {
decision_t *dp; /* Pointer to current decision */ decision_t *dp; /* Pointer to current decision */
metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */ metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */
decision_t *decisions; /* Beginning of decisions for block */ decision_t *decisions; /* Beginning of decisions for block */
uint32_t len;
}; };
void clear_v37(struct v37 *vp) {
bzero(vp->decisions, sizeof(decision_t)*vp->len);
vp->dp = NULL;
bzero(&vp->metrics1, sizeof(metric_t));
bzero(&vp->metrics2, sizeof(metric_t));
vp->old_metrics = NULL;
vp->new_metrics = NULL;
}
/* Initialize Viterbi decoder for start of new frame */ /* Initialize Viterbi decoder for start of new frame */
int init_viterbi37_port(void *p, int starting_state) { int init_viterbi37_port(void *p, int starting_state) {
struct v37 *vp = p; struct v37 *vp = p;
uint32_t i; uint32_t i;
if (p == NULL) if (p == NULL)
return -1; return -1;
clear_v37(vp);
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
vp->metrics1.w[i] = 63; vp->metrics1.w[i] = 63;
@ -81,6 +94,8 @@ void *create_viterbi37_port(int polys[3], uint32_t len) {
free(vp); free(vp);
return NULL ; return NULL ;
} }
vp->len = len+6;
return vp; return vp;
} }

@ -42,6 +42,7 @@ struct v37 {
decision_t *dp; /* Pointer to current decision */ decision_t *dp; /* Pointer to current decision */
metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */ metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */
decision_t *decisions; /* Beginning of decisions for block */ decision_t *decisions; /* Beginning of decisions for block */
uint32_t len;
}; };
void set_viterbi37_polynomial_sse(int polys[3]) { void set_viterbi37_polynomial_sse(int polys[3]) {
@ -54,15 +55,26 @@ void set_viterbi37_polynomial_sse(int polys[3]) {
} }
} }
void clear_v37_sse(struct v37 *vp) {
bzero(vp->decisions, sizeof(decision_t)*vp->len);
vp->dp = NULL;
bzero(&vp->metrics1, sizeof(metric_t));
bzero(&vp->metrics2, sizeof(metric_t));
vp->old_metrics = NULL;
vp->new_metrics = NULL;
}
/* Initialize Viterbi decoder for start of new frame */ /* Initialize Viterbi decoder for start of new frame */
int init_viterbi37_sse(void *p, int starting_state) { int init_viterbi37_sse(void *p, int starting_state) {
struct v37 *vp = p; struct v37 *vp = p;
uint32_t i; uint32_t i;
for(i=0;i<64;i++) for(i=0;i<64;i++)
vp->metrics1.c[i] = 63; vp->metrics1.c[i] = 63;
clear_v37_sse(vp);
vp->old_metrics = &vp->metrics1; vp->old_metrics = &vp->metrics1;
vp->new_metrics = &vp->metrics2; vp->new_metrics = &vp->metrics2;
vp->dp = vp->decisions; vp->dp = vp->decisions;
@ -89,6 +101,7 @@ void *create_viterbi37_sse(int polys[3], uint32_t len) {
return NULL; return NULL;
} }
vp->decisions = (decision_t *)p; vp->decisions = (decision_t *)p;
vp->len = len+6;
return vp; return vp;
} }

@ -648,6 +648,8 @@ int dci_format1As_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
data->dci_is_1a = true;
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment *y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
@ -719,7 +721,7 @@ int dci_format1As_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
*y++ = 0; *y++ = 0;
} }
msg->nof_bits = (y - msg->data); msg->nof_bits = (y - msg->data);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -752,13 +754,13 @@ int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32
while(i<nof_bits && y[1+i] == 1) while(i<nof_bits && y[1+i] == 1)
i++; i++;
if (i == nof_bits) { if (i == nof_bits) {
printf("Warning check me: could this be a RA PDCCH order??\n"); //printf("Warning check me: could this be a RA PDCCH order??\n");
i=1+10+nof_bits; i=1+10+nof_bits;
while(i<msg->nof_bits-1 && y[i] == 0) { while(i<msg->nof_bits-1 && y[i] == 0) {
i++; i++;
} }
if (i == msg->nof_bits-1) { if (i == msg->nof_bits-1) {
printf("Received a Format1A RA PDCCH order. Not implemented!\n"); //printf("Received a Format1A RA PDCCH order. Not implemented!\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
@ -878,6 +880,8 @@ int dci_format1Cs_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
"Format 1C accepts distributed type2 resource allocation only\n"); "Format 1C accepts distributed type2 resource allocation only\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
data->dci_is_1c = true;
if (nof_prb >= 50) { if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap; *y++ = data->type2_alloc.n_gap;

@ -52,6 +52,9 @@ static void set_cfi(srslte_pdcch_t *q, uint32_t cfi) {
} }
} }
void srslte_pdcch_set_cfi(srslte_pdcch_t *q, uint32_t cfi) {
set_cfi(q, cfi);
}
/** Initializes the PDCCH transmitter and receiver */ /** Initializes the PDCCH transmitter and receiver */
int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
@ -187,7 +190,7 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t
int l; // this must be int because of the for(;;--) loop int l; // this must be int because of the for(;;--) loop
uint32_t i, k, L, m; uint32_t i, k, L, m;
uint32_t Yk, ncce; uint32_t Yk, ncce;
const int M[4] = { 6, 6, 2, 2 }; const int S[4] = { 6, 12, 8, 16 };
// Compute Yk for this subframe // Compute Yk for this subframe
Yk = rnti; Yk = rnti;
@ -200,7 +203,7 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t
for (l = 3; l >= 0; l--) { for (l = 3; l >= 0; l--) {
L = (1 << l); L = (1 << l);
// For all possible ncce offset // For all possible ncce offset
for (i = 0; i < M[l]; i++) { for (i = 0; i < SRSLTE_MIN(nof_cce / L, S[l]/PDCCH_FORMAT_NOF_CCE(l)); i++) {
if (nof_cce > L) { if (nof_cce > L) {
ncce = L * ((Yk + i) % (nof_cce / L)); ncce = L * ((Yk + i) % (nof_cce / L));
if (k < max_candidates && ncce + L <= nof_cce) if (k < max_candidates && ncce + L <= nof_cce)
@ -217,7 +220,8 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t
} }
} }
DEBUG("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", k, rnti); DEBUG("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x, nsubframe=%d, nof_cce=%d\n",
k, rnti, nsubframe, nof_cce);
return k; return k;
} }
@ -240,22 +244,17 @@ uint32_t srslte_pdcch_common_locations(srslte_pdcch_t *q, srslte_dci_location_t
uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates) uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates)
{ {
uint32_t i, l, L, k; uint32_t i, l, L, k;
const int M[4] = { 0, 0, 4, 2 };
k = 0; k = 0;
for (l = 3; l > 1; l--) { for (l = 3; l > 1; l--) {
L = (1 << l); L = (1 << l);
for (i = 0; i < M[l]; i++) { for (i = 0; i < SRSLTE_MIN(nof_cce, 16) / (L); i++) {
if (nof_cce > L) { if (k < max_candidates) {
uint32_t ncce = L * (i % (nof_cce / L)); c[k].L = l;
if (k < max_candidates && ncce + L <= nof_cce) c[k].ncce = (L) * (i % (nof_cce / (L)));
{ DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n",
c[k].L = l; k, c[k].ncce, c[k].L);
c[k].ncce = ncce; k++;
DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n",
k, c[k].ncce, c[k].L);
k++;
}
} }
} }
} }

@ -562,7 +562,6 @@ int srslte_pdsch_encode_seq(srslte_pdsch_t *q,
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
data != NULL &&
cfg != NULL) cfg != NULL)
{ {

@ -600,10 +600,8 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
for (int j=0;j<n_wins;j++) { for (int j=0;j<n_wins;j++) {
if(p->peak_values[j] > p->detect_factor*corr_ave) if(p->peak_values[j] > p->detect_factor*corr_ave)
{ {
printf("ncs=%d, nzc=%d, nwins=%d, Nroot=%d, i=%d, j=%d, start=%d, peak_value=%f, peak_offset=%d, tseq=%f\n", //printf("saving prach correlation\n");
p->N_cs, p->N_zc, n_wins, p->N_roots, i, j, (p->N_zc-(j*p->N_cs))%p->N_zc, p->peak_values[j], //memcpy(save_corr, p->corr, p->N_zc*sizeof(float));
p->peak_offsets[j], p->T_seq*1e6);
memcpy(save_corr, p->corr, p->N_zc*sizeof(float));
if (indices) { if (indices) {
indices[*n_indices] = (i*n_wins)+j; indices[*n_indices] = (i*n_wins)+j;
} }

@ -38,6 +38,7 @@
#include "srslte/phch/pucch.h" #include "srslte/phch/pucch.h"
#include "srslte/common/sequence.h" #include "srslte/common/sequence.h"
#include "srslte/common/phy_common.h" #include "srslte/common/phy_common.h"
#include "srslte/mimo/precoding.h"
#include "srslte/scrambling/scrambling.h" #include "srslte/scrambling/scrambling.h"
#include "srslte/utils/debug.h" #include "srslte/utils/debug.h"
#include "srslte/utils/vector.h" #include "srslte/utils/vector.h"
@ -98,8 +99,10 @@ uint32_t get_N_sf(srslte_pucch_format_t format, uint32_t slot_idx, bool shortene
} }
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
return 5; return 5;
default:
return 0;
} }
return 0; return 0;
} }
@ -127,6 +130,8 @@ uint32_t srslte_pucch_nbits_format(srslte_pucch_format_t format) {
return 21; return 21;
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
return 22; return 22;
default:
return 0;
} }
return 0; return 0;
} }
@ -155,10 +160,82 @@ uint32_t get_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t
} }
} }
break; break;
default:
return 0;
} }
return 0; return 0;
} }
/* Choose PUCCH format based on pending transmission as described in 10.1 of 36.213 */
srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslte_cp_t cp)
{
srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR;
// No CQI data
if (uci_data->uci_cqi_len == 0) {
// 1-bit ACK + optional SR
if (uci_data->uci_ack_len == 1) {
format = SRSLTE_PUCCH_FORMAT_1A;
}
// 2-bit ACK + optional SR
else if (uci_data->uci_ack_len == 2) {
format = SRSLTE_PUCCH_FORMAT_1B;
}
// SR only
else if (uci_data->scheduling_request) {
format = SRSLTE_PUCCH_FORMAT_1;
}
}
// CQI data
else {
// CQI and no ack
if (uci_data->uci_ack_len == 0) {
format = SRSLTE_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (uci_data->uci_ack_len == 1 && SRSLTE_CP_ISNORM(cp)) {
format = SRSLTE_PUCCH_FORMAT_2A;
}
// CQI + 2-bit ACK
else if (uci_data->uci_ack_len == 2) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
// CQI + 2-bit ACK + cyclic prefix
else if (uci_data->uci_ack_len == 1 && SRSLTE_CP_ISEXT(cp)) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
}
return format;
}
/** Choose PUCCH resource as desribed in 10.1 of 36.213 */
uint32_t srslte_pucch_get_npucch(uint32_t n_cce, srslte_pucch_format_t format, bool has_scheduling_request, srslte_pucch_sched_t *pucch_sched)
{
uint32_t n_pucch = 0;
if (has_scheduling_request) {
n_pucch = pucch_sched->n_pucch_sr;
} else if (format < SRSLTE_PUCCH_FORMAT_2) {
if (pucch_sched->sps_enabled) {
n_pucch = pucch_sched->n_pucch_1[pucch_sched->tpc_for_pucch%4];
} else {
n_pucch = n_cce + pucch_sched->N_pucch_1;
}
} else {
n_pucch = pucch_sched->n_pucch_2;
}
return n_pucch;
}
uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch,
uint32_t nof_prb, srslte_cp_t cp, uint32_t ns)
{
uint32_t m = srslte_pucch_m(cfg, format, n_pucch, cp);
// Determine n_prb
uint32_t n_prb = m/2;
if ((m+ns)%2) {
n_prb = nof_prb-1-m/2;
}
return n_prb;
}
// Compute m according to Section 5.4.3 of 36.211 // Compute m according to Section 5.4.3 of 36.211
uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, srslte_cp_t cp) { uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, srslte_cp_t cp) {
@ -178,7 +255,10 @@ uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, u
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:
m = n_pucch/SRSLTE_NRE; m = n_pucch/SRSLTE_NRE;
break;
default:
m = 0;
break; break;
} }
return m; return m;
@ -250,6 +330,9 @@ float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLT
n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE; n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE;
} }
DEBUG("n_cs=%d, N_prime=%d, delta_pucch=%d, n_prime=%d, ns=%d, l=%d, ns_cs_cell=%d\n",
n_cs, N_prime, cfg->delta_pucch_shift, n_prime, ns, l, n_cs_cell[ns][l]);
return 2 * M_PI * (n_cs) / SRSLTE_NRE; return 2 * M_PI * (n_cs) / SRSLTE_NRE;
} }
@ -281,40 +364,55 @@ float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLT
} }
/* Map PUCCH symbols to physical resources according to 5.4.3 in 36.211 */ /* Map PUCCH symbols to physical resources according to 5.4.3 in 36.211 */
static int pucch_put(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *output) { static int pucch_cp(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid) {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q && output) { if (q && source && dest) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB;
// Determine m uint32_t n_re = 0;
uint32_t m = srslte_pucch_m(&q->pucch_cfg, format, n_pucch, q->cell.cp);
uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened);
for (uint32_t ns=0;ns<2;ns++) { for (uint32_t ns=0;ns<2;ns++) {
uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); uint32_t N_sf = get_N_sf(format, ns%2, q->shortened);
// Determine n_prb
uint32_t n_prb = m/2; // Determine n_prb
if ((m+ns)%2) { uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns);
n_prb = q->cell.nof_prb-1-m/2;
}
if (n_prb < q->cell.nof_prb) { if (n_prb < q->cell.nof_prb) {
for (uint32_t i=0;i<N_sf;i++) { for (uint32_t i=0;i<N_sf;i++) {
uint32_t l = get_pucch_symbol(i, format, q->cell.cp); uint32_t l = get_pucch_symbol(i, format, q->cell.cp);
memcpy(&output[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], if (!source_is_grid) {
&q->z[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)],
SRSLTE_NRE*sizeof(cf_t)); &source[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE],
SRSLTE_NRE*sizeof(cf_t));
} else {
memcpy(&dest[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE],
&source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)],
SRSLTE_NRE*sizeof(cf_t));
}
n_re += SRSLTE_NRE;
} }
} else { } else {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
ret = SRSLTE_SUCCESS; ret = n_re;
} }
return ret; return ret;
} }
static int pucch_put(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *z, cf_t *output) {
return pucch_cp(q, format, n_pucch, z, output, false);
}
static int pucch_get(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *z) {
return pucch_cp(q, format, n_pucch, input, z, true);
}
void srslte_pucch_set_threshold(srslte_pucch_t *q, float format1, float format1a) {
q->threshold_format1 = format1;
q->threshold_format1a = format1a;
}
/** Initializes the PDCCH transmitter and receiver */ /** Initializes the PDCCH transmitter and receiver */
int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) {
@ -340,6 +438,10 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) {
if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) { if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->z = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->z_tmp = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->ce = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -352,6 +454,16 @@ void srslte_pucch_free(srslte_pucch_t *q) {
srslte_sequence_free(&q->seq_f2[sf_idx]); srslte_sequence_free(&q->seq_f2[sf_idx]);
} }
} }
if (q->z) {
free(q->z);
}
if (q->z_tmp) {
free(q->z_tmp);
}
if (q->ce) {
free(q->ce);
}
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
bzero(q, sizeof(srslte_pucch_t)); bzero(q, sizeof(srslte_pucch_t));
} }
@ -470,9 +582,59 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t
// Declare this here, since we can not include refsignal_ul.h // Declare this here, since we can not include refsignal_ul.h
void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u);
static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format,
uint32_t n_pucch, uint32_t sf_idx,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS])
{
if (uci_mod_bits(q, format, bits, sf_idx)) {
fprintf(stderr, "Error encoding PUCCH bits\n");
return SRSLTE_ERROR;
}
uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened);
for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
uint32_t N_sf = get_N_sf(format, ns%2, q->shortened);
DEBUG("ns=%d, N_sf=%d\n", ns, N_sf);
// Get group hopping number u
uint32_t f_gh=0;
if (q->group_hopping_en) {
f_gh = q->f_gh[ns];
}
uint32_t u = (f_gh + (q->cell.id%30))%30;
srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u);
uint32_t N_sf_widx = N_sf==3?1:0;
for (uint32_t m=0;m<N_sf;m++) {
uint32_t l = get_pucch_symbol(m, format, q->cell.cp);
float alpha=0;
if (format >= SRSLTE_PUCCH_FORMAT_2) {
alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l);
for (uint32_t n=0;n<SRSLTE_PUCCH_N_SEQ;n++) {
z[(ns%2)*N_sf*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = q->d[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n));
}
} else {
uint32_t n_prime_ns=0;
uint32_t n_oc=0;
alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns);
float S_ns = 0;
if (n_prime_ns%2) {
S_ns = M_PI/2;
}
DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n",
__real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns, q->pucch_cfg.n_rb_2);
for (uint32_t n=0;n<SRSLTE_PUCCH_N_SEQ;n++) {
z[(ns%2)*N_sf_0*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] =
q->d[0]*cexpf(I*(w_n_oc[N_sf_widx][n_oc%3][m]+q->tmp_arg[n]+alpha*n+S_ns));
}
}
}
}
return SRSLTE_SUCCESS;
}
/* Encode, modulate and resource mapping of PUCCH bits according to Section 5.4.1 of 36.211 */ /* Encode, modulate and resource mapping of PUCCH bits according to Section 5.4.1 of 36.211 */
int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format,
uint32_t n_pucch, uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols) uint32_t n_pucch, uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS],
cf_t *sf_symbols)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
@ -496,49 +658,10 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format,
fprintf(stderr, "Error encoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n"); fprintf(stderr, "Error encoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (uci_mod_bits(q, format, bits, sf_idx)) { if (pucch_encode(q, format, n_pucch, sf_idx, bits, q->z)) {
fprintf(stderr, "Error encoding PUCCH bits\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); if (pucch_put(q, format, n_pucch, q->z, sf_symbols) < 0) {
for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
uint32_t N_sf = get_N_sf(format, ns%2, q->shortened);
DEBUG("ns=%d, N_sf=%d\n", ns, N_sf);
// Get group hopping number u
uint32_t f_gh=0;
if (q->group_hopping_en) {
f_gh = q->f_gh[ns];
}
uint32_t u = (f_gh + (q->cell.id%30))%30;
srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u);
uint32_t N_sf_widx = N_sf==3?1:0;
for (uint32_t m=0;m<N_sf;m++) {
uint32_t l = get_pucch_symbol(m, format, q->cell.cp);
float alpha=0;
if (format >= SRSLTE_PUCCH_FORMAT_2) {
alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l);
for (uint32_t n=0;n<SRSLTE_PUCCH_N_SEQ;n++) {
q->z[(ns%2)*N_sf*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] = q->d[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n));
}
} else {
uint32_t n_prime_ns=0;
uint32_t n_oc=0;
alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns);
float S_ns = 0;
if (n_prime_ns%2) {
S_ns = M_PI/2;
}
DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n",
__real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns, q->pucch_cfg.n_rb_2);
for (uint32_t n=0;n<SRSLTE_PUCCH_N_SEQ;n++) {
q->z[(ns%2)*N_sf_0*SRSLTE_PUCCH_N_SEQ+m*SRSLTE_PUCCH_N_SEQ+n] =
q->d[0]*cexpf(I*(w_n_oc[N_sf_widx][n_oc%3][m]+q->tmp_arg[n]+alpha*n+S_ns));
}
}
}
}
if (pucch_put(q, format, n_pucch, sf_symbols)) {
fprintf(stderr, "Error putting PUCCH symbols\n"); fprintf(stderr, "Error putting PUCCH symbols\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -548,4 +671,96 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format,
return ret; return ret;
} }
float srslte_pucch_get_last_corr(srslte_pucch_t* q)
{
return q->last_corr;
}
/* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */
int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
uint32_t n_pucch, uint32_t sf_idx, cf_t *sf_symbols, cf_t *ce, float noise_estimate,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
ce != NULL &&
sf_symbols != NULL)
{
ret = SRSLTE_ERROR;
// Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b
if (q->pucch_cfg.srs_configured && format < SRSLTE_PUCCH_FORMAT_2) {
q->shortened = false;
// If CQI is not transmitted, PUCCH will be normal unless ACK/NACK and SRS simultaneous transmission is enabled
if (q->pucch_cfg.srs_simul_ack) {
// If simultaneous ACK and SRS is enabled, PUCCH is shortened in cell-specific SRS subframes
if (srslte_refsignal_srs_send_cs(q->pucch_cfg.srs_cs_subf_cfg, sf_idx) == 1) {
q->shortened = true;
}
}
}
if (format >= SRSLTE_PUCCH_FORMAT_2 && !q->rnti_is_set) {
fprintf(stderr, "Error decoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n");
return SRSLTE_ERROR;
}
int nof_re = pucch_get(q, format, n_pucch, sf_symbols, q->z_tmp);
if (nof_re < 0) {
fprintf(stderr, "Error getting PUCCH symbols\n");
return SRSLTE_ERROR;
}
if (pucch_get(q, format, n_pucch, ce, q->ce) < 0) {
fprintf(stderr, "Error getting PUCCH symbols\n");
return SRSLTE_ERROR;
}
// Equalization
srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, noise_estimate);
// Perform ML-decoding
float corr=0, corr_max=-1e9;
int b_max = 0; // default bit value, eg. HI is NACK
switch(format) {
case SRSLTE_PUCCH_FORMAT_1:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp);
corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re;
if (corr >= q->threshold_format1) {
ret = 1;
} else {
ret = 0;
}
DEBUG("format1 corr=%f, nof_re=%d, th=%f\n", corr, nof_re, q->threshold_format1);
break;
case SRSLTE_PUCCH_FORMAT_1A:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0;
for (int b=0;b<2;b++) {
bits[0] = b;
pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp);
corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re;
if (corr > corr_max && corr >= q->threshold_format1a) {
corr_max = corr;
b_max = b;
}
if (corr_max > q->threshold_format1a) {
ret = 1;
}
DEBUG("format1a b=%d, corr=%f, nof_re=%d, th=%f\n", b, corr, nof_re, q->threshold_format1a);
}
bits[0] = b_max;
break;
default:
fprintf(stderr, "Error decoding PUCCH: Format %d not supported\n", format);
ret = SRSLTE_ERROR;
break;
}
q->last_corr = corr;
}
return ret;
}

@ -170,7 +170,8 @@ int srslte_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_
} }
srslte_mod_t last_mod[8]; srslte_mod_t last_mod[8];
uint32_t last_tbs_idx[8]; uint32_t last_ul_tbs_idx[8];
uint32_t last_dl_tbs[8];
static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t harq_pid) { static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t harq_pid) {
int tbs = -1; int tbs = -1;
@ -180,15 +181,15 @@ static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *gr
if (dci->mcs_idx < 11) { if (dci->mcs_idx < 11) {
grant->mcs.mod = SRSLTE_MOD_QPSK; grant->mcs.mod = SRSLTE_MOD_QPSK;
tbs = srslte_ra_tbs_from_idx(dci->mcs_idx, grant->L_prb); tbs = srslte_ra_tbs_from_idx(dci->mcs_idx, grant->L_prb);
last_tbs_idx[harq_pid%8] = dci->mcs_idx; last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx;
} else if (dci->mcs_idx < 21) { } else if (dci->mcs_idx < 21) {
grant->mcs.mod = SRSLTE_MOD_16QAM; grant->mcs.mod = SRSLTE_MOD_16QAM;
tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-1, grant->L_prb); tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-1, grant->L_prb);
last_tbs_idx[harq_pid%8] = dci->mcs_idx-1; last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx-1;
} else if (dci->mcs_idx < 29) { } else if (dci->mcs_idx < 29) {
grant->mcs.mod = SRSLTE_MOD_64QAM; grant->mcs.mod = SRSLTE_MOD_64QAM;
tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-2, grant->L_prb); tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-2, grant->L_prb);
last_tbs_idx[harq_pid%8] = dci->mcs_idx-2; last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx-2;
} else { } else {
fprintf(stderr, "Invalid MCS index %d\n", dci->mcs_idx); fprintf(stderr, "Invalid MCS index %d\n", dci->mcs_idx);
} }
@ -196,10 +197,10 @@ static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *gr
} else if (dci->mcs_idx == 29 && dci->cqi_request && grant->L_prb <= 4) { } else if (dci->mcs_idx == 29 && dci->cqi_request && grant->L_prb <= 4) {
// 8.6.1 and 8.6.2 36.213 second paragraph // 8.6.1 and 8.6.2 36.213 second paragraph
grant->mcs.mod = SRSLTE_MOD_QPSK; grant->mcs.mod = SRSLTE_MOD_QPSK;
tbs = srslte_ra_tbs_from_idx(last_tbs_idx[harq_pid%8], grant->L_prb); tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb);
} else if (dci->mcs_idx >= 29) { } else if (dci->mcs_idx >= 29) {
// Else use last TBS/Modulation and use mcs to obtain rv_idx // Else use last TBS/Modulation and use mcs to obtain rv_idx
tbs = srslte_ra_tbs_from_idx(last_tbs_idx[harq_pid%8], grant->L_prb); tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb);
grant->mcs.mod = last_mod[harq_pid%8]; grant->mcs.mod = last_mod[harq_pid%8];
dci->rv_idx = dci->mcs_idx - 28; dci->rv_idx = dci->mcs_idx - 28;
DEBUG("TTI=%d, harq_pid=%d, mcs_idx=%d, tbs=%d, mod=%d, rv=%d\n", DEBUG("TTI=%d, harq_pid=%d, mcs_idx=%d, tbs=%d, mod=%d, rv=%d\n",
@ -425,10 +426,15 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3; n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3;
i_tbs = dci->mcs_idx; i_tbs = dci->mcs_idx;
tbs = srslte_ra_tbs_from_idx(i_tbs, n_prb); tbs = srslte_ra_tbs_from_idx(i_tbs, n_prb);
} else { } else if (dci->dci_is_1c) {
if (dci->mcs_idx < 32) { if (dci->mcs_idx < 32) {
tbs = tbs_format1c_table[dci->mcs_idx]; tbs = tbs_format1c_table[dci->mcs_idx];
} } else {
fprintf(stderr, "Error decoding DCI: Invalid mcs_idx=%d in Format1C\n", dci->mcs_idx);
}
} else {
fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n");
return SRSLTE_ERROR;
} }
grant->mcs.mod = SRSLTE_MOD_QPSK; grant->mcs.mod = SRSLTE_MOD_QPSK;
grant->mcs.tbs = (uint32_t) tbs; grant->mcs.tbs = (uint32_t) tbs;
@ -436,6 +442,12 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
n_prb = grant->nof_prb; n_prb = grant->nof_prb;
grant->mcs.idx = dci->mcs_idx; grant->mcs.idx = dci->mcs_idx;
tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); tbs = dl_fill_ra_mcs(&grant->mcs, n_prb);
if (tbs) {
last_dl_tbs[dci->harq_process%8] = tbs;
} else {
// For mcs>=29, set last TBS received for this PID
grant->mcs.tbs = last_dl_tbs[dci->harq_process%8];
}
if (dci->nof_tb == 2) { if (dci->nof_tb == 2) {
grant->mcs2.idx = dci->mcs_idx_1; grant->mcs2.idx = dci->mcs_idx_1;
tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb); tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb);

@ -146,7 +146,7 @@ target_link_libraries(pucch_test srslte)
add_test(pucch_test pucch_test) add_test(pucch_test pucch_test)
BuildMex(MEXNAME pucch_encode SOURCES pucch_encode_test_mex.c LIBRARIES srslte_static srslte_mex) BuildMex(MEXNAME pucch_encode SOURCES pucch_encode_test_mex.c LIBRARIES srslte_static srslte_mex)
BuildMex(MEXNAME pucch SOURCES pucch_test_mex.c LIBRARIES srslte_static srslte_mex)

@ -34,8 +34,6 @@
char *input_file_name = NULL; char *input_file_name = NULL;
#define MAX_CANDIDATES 16
srslte_cell_t cell = { srslte_cell_t cell = {
6, // cell.cell.cell.nof_prb 6, // cell.cell.cell.nof_prb
1, // cell.cell.nof_ports 1, // cell.cell.nof_ports

@ -36,7 +36,6 @@
#define INPUT prhs[2] #define INPUT prhs[2]
#define NOF_INPUTS 3 #define NOF_INPUTS 3
#define MAX_CANDIDATES 16
srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also

@ -32,8 +32,6 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
#define MAX_CANDIDATES 16
char *input_file_name = NULL; char *input_file_name = NULL;
srslte_cell_t cell = { srslte_cell_t cell = {

@ -45,10 +45,10 @@ uint32_t root_seq_idx = 0;
uint32_t seq_idx = 0; uint32_t seq_idx = 0;
uint32_t frequency_offset = 0; uint32_t frequency_offset = 0;
uint32_t zero_corr_zone = 11; uint32_t zero_corr_zone = 11;
uint32_t timeadv = 0; float timeadv = 0;
uint32_t nof_frames = 20; uint32_t nof_frames = 20;
float uhd_gain=40, uhd_freq=2.4e9; float uhd_rx_gain=40, uhd_tx_gain=60, uhd_freq=2.4e9;
char *uhd_args=""; char *uhd_args="";
char *output_filename = "prach_rx"; char *output_filename = "prach_rx";
@ -56,20 +56,21 @@ void usage(char *prog) {
printf("Usage: %s \n", prog); printf("Usage: %s \n", prog);
printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-f UHD TX/RX frequency [Default %.2f MHz]\n", uhd_freq/1e6); printf("\t-f UHD TX/RX frequency [Default %.2f MHz]\n", uhd_freq/1e6);
printf("\t-g UHD TX/RX gain [Default %.1f dB]\n", uhd_gain); printf("\t-g UHD RX gain [Default %.1f dB]\n", uhd_rx_gain);
printf("\t-G UHD TX gain [Default %.1f dB]\n", uhd_tx_gain);
printf("\t-p Number of UL RB [Default %d]\n", nof_prb); printf("\t-p Number of UL RB [Default %d]\n", nof_prb);
printf("\t-F Preamble format [Default %d]\n", preamble_format); printf("\t-F Preamble format [Default %d]\n", preamble_format);
printf("\t-O Frequency offset [Default %d]\n", frequency_offset); printf("\t-O Frequency offset [Default %d]\n", frequency_offset);
printf("\t-s sequence index [Default %d]\n", seq_idx); printf("\t-s sequence index [Default %d]\n", seq_idx);
printf("\t-r Root sequence index [Default %d]\n", root_seq_idx); printf("\t-r Root sequence index [Default %d]\n", root_seq_idx);
printf("\t-t Time advance (us) [Default %d]\n", timeadv); printf("\t-t Time advance (us) [Default %.1f us]\n", timeadv);
printf("\t-z Zero correlation zone config [Default %d]\n", zero_corr_zone); printf("\t-z Zero correlation zone config [Default %d]\n", zero_corr_zone);
printf("\t-o Save transmitted PRACH in file [Default no]\n"); printf("\t-o Save transmitted PRACH in file [Default no]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "apfFgrstoPOz")) != -1) { while ((opt = getopt(argc, argv, "apfFgGrstoPOz")) != -1) {
switch (opt) { switch (opt) {
case 'a': case 'a':
uhd_args = argv[optind]; uhd_args = argv[optind];
@ -81,7 +82,10 @@ void parse_args(int argc, char **argv) {
uhd_freq = atof(argv[optind]); uhd_freq = atof(argv[optind]);
break; break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_rx_gain = atof(argv[optind]);
break;
case 'G':
uhd_tx_gain = atof(argv[optind]);
break; break;
case 'P': case 'P':
preamble_format = atoi(argv[optind]); preamble_format = atoi(argv[optind]);
@ -90,7 +94,7 @@ void parse_args(int argc, char **argv) {
frequency_offset = atoi(argv[optind]); frequency_offset = atoi(argv[optind]);
break; break;
case 't': case 't':
timeadv = atoi(argv[optind]); timeadv = atof(argv[optind]);
break; break;
case 'p': case 'p':
nof_prb = atoi(argv[optind]); nof_prb = atoi(argv[optind]);
@ -129,11 +133,11 @@ int main(int argc, char **argv) {
memset(preamble, 0, sizeof(cf_t)*MAX_LEN); memset(preamble, 0, sizeof(cf_t)*MAX_LEN);
srslte_prach_init(p, srslte_prach_init(p,
srslte_symbol_sz(nof_prb), srslte_symbol_sz(nof_prb),
preamble_format, preamble_format,
root_seq_idx, root_seq_idx,
high_speed_flag, high_speed_flag,
zero_corr_zone); zero_corr_zone);
int srate = srslte_sampling_freq_hz(nof_prb); int srate = srslte_sampling_freq_hz(nof_prb);
uint32_t flen = srate/1000; uint32_t flen = srate/1000;
@ -153,71 +157,78 @@ int main(int argc, char **argv) {
cf_t *buffer = malloc(sizeof(cf_t)*flen*nof_frames); cf_t *buffer = malloc(sizeof(cf_t)*flen*nof_frames);
// Send through UHD // Send through UHD
srslte_rf_t uhd; srslte_rf_t rf;
printf("Opening UHD device...\n"); printf("Opening RF device...\n");
if (srslte_rf_open(&uhd, uhd_args)) { if (srslte_rf_open(&rf, uhd_args)) {
fprintf(stderr, "Error opening &uhd\n"); fprintf(stderr, "Error opening &uhd\n");
exit(-1); exit(-1);
} }
printf("Subframe len: %d samples\n", flen); printf("Subframe len: %d samples\n", flen);
printf("Set RX gain: %.1f dB\n", uhd_gain); printf("Set RX gain: %.1f dB\n", uhd_rx_gain);
printf("Set TX gain: %.1f dB\n", 20+uhd_gain); printf("Set TX gain: %.1f dB\n", uhd_tx_gain);
printf("Set TX/RX freq: %.2f MHz\n", uhd_freq/ 1000000); printf("Set TX/RX freq: %.2f MHz\n", uhd_freq/ 1000000);
srslte_rf_set_rx_gain(&uhd, uhd_gain); srslte_rf_set_rx_gain(&rf, uhd_rx_gain);
srslte_rf_set_tx_gain(&uhd, 10+uhd_gain); srslte_rf_set_tx_gain(&rf, uhd_tx_gain);
srslte_rf_set_rx_freq(&uhd, uhd_freq); srslte_rf_set_rx_freq(&rf, uhd_freq);
srslte_rf_set_tx_freq(&uhd, uhd_freq); srslte_rf_set_tx_freq(&rf, uhd_freq);
if (srate < 10e6) { if (srate > 1e6) {
srslte_rf_set_master_clock_rate(&uhd, 4*srate); if (30720%((int) srate/1000) == 0) {
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
} else {
srslte_rf_set_master_clock_rate(&rf, 23.04e6);
}
} else { } else {
srslte_rf_set_master_clock_rate(&uhd, srate); printf("Invalid sampling rate %d Hz\n", srate);
exit(-1);
} }
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_rx_srate(&uhd, (double) srate); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate);
if (srate_rf != srate) { if (srate_rf != srate) {
fprintf(stderr, "Could not set sampling rate\n"); fprintf(stderr, "Could not set sampling rate\n");
exit(-1); exit(-1);
} }
srslte_rf_set_tx_srate(&uhd, (double) srate); srslte_rf_set_tx_srate(&rf, (double) srate);
sleep(1); sleep(1);
cf_t *zeros = calloc(sizeof(cf_t),flen); cf_t *zeros = calloc(sizeof(cf_t),flen);
FILE *f = NULL;
if (output_filename) {
f = fopen(output_filename, "w");
}
srslte_timestamp_t tstamp; srslte_timestamp_t tstamp;
srslte_rf_start_rx_stream(&uhd); srslte_rf_start_rx_stream(&rf);
uint32_t nframe=0; uint32_t nframe=0;
while(nframe<nof_frames) { while(nframe<nof_frames) {
printf("Rx subframe %d\n", nframe); printf("Rx subframe %d\n", nframe);
srslte_rf_recv_with_time(&uhd, &buffer[flen*nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs); srslte_rf_recv_with_time(&rf, &buffer[flen*nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs);
nframe++; nframe++;
if (nframe==9 || nframe==8) { if (nframe==9 || nframe==8) {
srslte_timestamp_add(&tstamp, 0, 2e-3-timeadv*1e-6); srslte_timestamp_add(&tstamp, 0, 2e-3-timeadv*1e-6);
if (nframe==8) { if (nframe==8) {
srslte_rf_send_timed2(&uhd, zeros, flen, tstamp.full_secs, tstamp.frac_secs, true, false); srslte_rf_send_timed2(&rf, zeros, flen, tstamp.full_secs, tstamp.frac_secs, true, false);
printf("Transmitting zeros\n"); printf("Transmitting zeros\n");
} else { } else {
srslte_rf_send_timed2(&uhd, preamble, flen, tstamp.full_secs, tstamp.frac_secs, true, true); srslte_rf_send_timed2(&rf, preamble, flen, tstamp.full_secs, tstamp.frac_secs, false, true);
printf("Transmitting PRACH\n"); printf("Transmitting PRACH\n");
} }
} }
} }
if (f) {
fwrite(buffer, 11*flen*sizeof(cf_t), 1, f); uint32_t indices[1024];
float offsets[1024];
uint32_t nof_detected;
if (srslte_prach_detect_offset(p, frequency_offset, &buffer[flen*10+p->N_cp], flen, indices, offsets, NULL, &nof_detected)) {
printf("Error detecting prach\n");
} }
if (f) { printf("Nof detected PRACHs: %d\n", nof_detected);
fclose(f); for (int i=0;i<nof_detected;i++) {
printf("%d/%d index=%d, offset=%.2f us (%d samples)\n",
i, nof_detected, indices[i], offsets[i]*1e6, (int) (offsets[i]*srate));
} }
srslte_vec_save_file(output_filename,buffer,11*flen*sizeof(cf_t));
srslte_prach_free(p); srslte_prach_free(p);
free(p); free(p);

@ -0,0 +1,225 @@
/**
*
* \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 <string.h>
#include "srslte/srslte.h"
#include "srslte/mex/mexutils.h"
/** MEX function to be called from MATLAB to test the channel estimator
*/
#define UECFG prhs[0]
#define PUCCHCFG prhs[1]
#define N_BITS prhs[2]
#define INPUT prhs[3]
#define THRESHOLD prhs[4]
#define NOF_INPUTS 4
void help()
{
mexErrMsgTxt
("[data, symbols, ce]=srslte_pucch(ue, chs, n_bits, input)\n\n");
}
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs < NOF_INPUTS) {
help();
return;
}
srslte_verbose = SRSLTE_VERBOSE_NONE;
srslte_cell_t cell;
bzero(&cell, sizeof(srslte_cell_t));
cell.nof_ports = 1;
cell.cp = SRSLTE_CP_NORM;
if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) {
mexErrMsgTxt("Field NCellID not found in UE config\n");
return;
}
if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) {
mexErrMsgTxt("Field NULRB not found in UE config\n");
return;
}
srslte_pucch_t pucch;
if (srslte_pucch_init(&pucch, cell)) {
mexErrMsgTxt("Error initiating PUSCH\n");
return;
}
uint32_t sf_idx = 0;
if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) {
mexErrMsgTxt("Field NSubframe not found in UE config\n");
return;
}
uint32_t rnti;
if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti)) {
mexErrMsgTxt("Field NSubframe not found in UE config\n");
return;
}
if (srslte_pucch_set_crnti(&pucch, (uint16_t) rnti&0xffff)) {
mexErrMsgTxt("Error setting C-RNTI\n");
return;
}
uint32_t n_pucch;
if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceIdx", &n_pucch)) {
mexErrMsgTxt("Field ResourceIdx not found in PUCCHCFG\n");
return;
}
srslte_pucch_cfg_t pucch_cfg;
bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t));
if (mexutils_read_uint32_struct(PUCCHCFG, "DeltaShift", &pucch_cfg.delta_pucch_shift)) {
mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n");
return;
}
if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceSize", &pucch_cfg.n_rb_2)) {
mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n");
return;
}
if (mexutils_read_uint32_struct(PUCCHCFG, "CyclicShifts", &pucch_cfg.N_cs)) {
mexErrMsgTxt("Field CyclicShifts not found in PUCCHCFG\n");
return;
}
bool group_hopping_en = false;
char *hop = mexutils_get_char_struct(UECFG, "Hopping");
if (hop) {
if (!strcmp(hop, "Group")) {
group_hopping_en = true;
}
mxFree(hop);
}
pucch.shortened = false;
uint32_t sh = 0;
mexutils_read_uint32_struct(PUCCHCFG, "Shortened", &sh);
if (sh == 1) {
pucch.shortened = true;
}
float *thresholds;
int th_len = 0;
if (nrhs > NOF_INPUTS) {
th_len = mexutils_read_f(THRESHOLD, &thresholds);
if (th_len == 2) {
srslte_pucch_set_threshold(&pucch, thresholds[0], thresholds[1]);
}
}
uint8_t bits[SRSLTE_PUCCH_MAX_BITS];
int nof_bits = (int) mxGetScalar(N_BITS);
srslte_pucch_format_t format;
switch(nof_bits) {
case 0:
format = SRSLTE_PUCCH_FORMAT_1;
break;
case 1:
format = SRSLTE_PUCCH_FORMAT_1A;
break;
case 2:
format = SRSLTE_PUCCH_FORMAT_1B;
break;
case 20:
format = SRSLTE_PUCCH_FORMAT_2;
break;
case 21:
format = SRSLTE_PUCCH_FORMAT_2A;
break;
case 22:
format = SRSLTE_PUCCH_FORMAT_2B;
break;
default:
mexErrMsgTxt("Invalid number of bits in parameter ack\n");
return;
}
if (nof_bits > 20) {
nof_bits = 20;
}
cf_t *sf_symbols = NULL;
int nof_re = mexutils_read_cf(INPUT, &sf_symbols);
if (nof_re < 0) {
mexErrMsgTxt("Error reading input\n");
return;
}
cf_t *ce = srslte_vec_malloc(nof_re*sizeof(cf_t));
if (!ce) {
perror("malloc");
return;
}
bzero(ce, nof_re*sizeof(cf_t));
srslte_chest_ul_t chest_ul;
if (srslte_chest_ul_init(&chest_ul, cell)) {
mexErrMsgTxt("Error initiating PUCCH DMRS\n");
return;
}
srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg;
pusch_cfg.group_hopping_en = group_hopping_en;
pusch_cfg.sequence_hopping_en = false;
srslte_chest_ul_set_cfg(&chest_ul, &pusch_cfg, &pucch_cfg, NULL);
srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en);
if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx)) {
mexErrMsgTxt("Error estimating PUCCH DMRS\n");
return;
}
if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)) {
mexErrMsgTxt("Error decoding PUCCH\n");
return;
}
if (nlhs >= 1) {
if (format != SRSLTE_PUCCH_FORMAT_1) {
mexutils_write_uint8(bits, &plhs[0], nof_bits, 1);
} else {
if (bits[0] == 1) {
mexutils_write_uint8(bits, &plhs[0], 0, 1);
} else {
mexutils_write_uint8(bits, &plhs[0], 0, 0);
}
}
}
if (nlhs >= 2) {
mexutils_write_cf(pucch.z, &plhs[1], 2*srslte_refsignal_dmrs_N_rs(format, cell.cp)*SRSLTE_NRE*2, 1);
}
if (nlhs >= 3) {
mexutils_write_cf(ce, &plhs[2], nof_re, 1);
}
srslte_pucch_free(&pucch);
free(sf_symbols);
return;
}

@ -70,7 +70,12 @@ const unsigned int buffer_size_tx = 1024;
const unsigned int num_transfers = 32; const unsigned int num_transfers = 32;
const unsigned int timeout_ms = 4000; const unsigned int timeout_ms = 4000;
char* rf_blade_devname(void* h)
{
return DEVNAME;
}
int rf_blade_start_tx_stream(void *h) int rf_blade_start_tx_stream(void *h)
{ {
int status; int status;
@ -336,6 +341,10 @@ double rf_blade_set_rx_freq(void *h, double freq)
(uint32_t) freq, bladerf_strerror(status)); (uint32_t) freq, bladerf_strerror(status));
return -1; return -1;
} }
f_int=0;
bladerf_get_frequency(handler->dev, BLADERF_MODULE_RX, &f_int);
printf("set RX frequency to %u\n", f_int);
return freq; return freq;
} }
@ -350,6 +359,9 @@ double rf_blade_set_tx_freq(void *h, double freq)
return -1; return -1;
} }
f_int=0;
bladerf_get_frequency(handler->dev, BLADERF_MODULE_TX, &f_int);
printf("set TX frequency to %u\n", f_int);
return freq; return freq;
} }

@ -28,9 +28,14 @@
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/rf/rf.h" #include "srslte/rf/rf.h"
#define DEVNAME "bladerf"
SRSLTE_API int rf_blade_open(char *args, SRSLTE_API int rf_blade_open(char *args,
void **handler); void **handler);
SRSLTE_API char* rf_blade_devname(void *h);
SRSLTE_API int rf_blade_close(void *h); SRSLTE_API int rf_blade_close(void *h);
SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal);

@ -28,7 +28,8 @@
/* RF frontend API */ /* RF frontend API */
typedef struct { typedef struct {
const char *name; const char *name;
bool (*srslte_rf_rx_wait_lo_locked) (void*); char* (*srslte_rf_devname) (void *h);
bool (*srslte_rf_rx_wait_lo_locked) (void *h);
int (*srslte_rf_start_rx_stream)(void *h); int (*srslte_rf_start_rx_stream)(void *h);
int (*srslte_rf_stop_rx_stream)(void *h); int (*srslte_rf_stop_rx_stream)(void *h);
void (*srslte_rf_flush_buffer)(void *h); void (*srslte_rf_flush_buffer)(void *h);
@ -67,6 +68,7 @@ typedef struct {
static rf_dev_t dev_uhd = { static rf_dev_t dev_uhd = {
"UHD", "UHD",
rf_uhd_devname,
rf_uhd_rx_wait_lo_locked, rf_uhd_rx_wait_lo_locked,
rf_uhd_start_rx_stream, rf_uhd_start_rx_stream,
rf_uhd_stop_rx_stream, rf_uhd_stop_rx_stream,
@ -102,6 +104,7 @@ static rf_dev_t dev_uhd = {
static rf_dev_t dev_blade = { static rf_dev_t dev_blade = {
"bladeRF", "bladeRF",
rf_blade_devname,
rf_blade_rx_wait_lo_locked, rf_blade_rx_wait_lo_locked,
rf_blade_start_rx_stream, rf_blade_start_rx_stream,
rf_blade_stop_rx_stream, rf_blade_stop_rx_stream,
@ -160,6 +163,7 @@ static rf_dev_t dev_dummy = {
dummy_fnc, dummy_fnc,
dummy_fnc, dummy_fnc,
dummy_fnc, dummy_fnc,
dummy_fnc,
dummy_fnc, dummy_fnc,
dummy_fnc, dummy_fnc,
dummy_fnc, dummy_fnc,

@ -137,7 +137,7 @@ void srslte_rf_set_rx_cal(srslte_rf_t *rf, srslte_rf_cal_t *cal) {
const char* srslte_rf_name(srslte_rf_t *rf) { const char* srslte_rf_name(srslte_rf_t *rf) {
return ((rf_dev_t*) rf->dev)->name; return ((rf_dev_t*) rf->dev)->srslte_rf_devname(rf->handler);
} }
bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *rf) bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *rf)

@ -36,6 +36,7 @@
#include "uhd_c_api.h" #include "uhd_c_api.h"
typedef struct { typedef struct {
char *devname;
uhd_usrp_handle usrp; uhd_usrp_handle usrp;
uhd_rx_streamer_handle rx_stream; uhd_rx_streamer_handle rx_stream;
uhd_tx_streamer_handle tx_stream; uhd_tx_streamer_handle tx_stream;
@ -117,6 +118,12 @@ static bool isLocked(rf_uhd_handler_t *handler, char *sensor_name, uhd_sensor_va
return val_out; return val_out;
} }
char* rf_uhd_devname(void* h)
{
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
return handler->devname;
}
bool rf_uhd_rx_wait_lo_locked(void *h) bool rf_uhd_rx_wait_lo_locked(void *h)
{ {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
@ -238,7 +245,7 @@ int rf_uhd_open(char *args, void **h)
/* Set priority to UHD threads */ /* Set priority to UHD threads */
uhd_set_thread_priority(uhd_default_thread_priority, true); uhd_set_thread_priority(uhd_default_thread_priority, true);
/* Set correct options for the USRP device */ /* Find available devices */
uhd_string_vector_handle devices_str; uhd_string_vector_handle devices_str;
uhd_string_vector_make(&devices_str); uhd_string_vector_make(&devices_str);
uhd_usrp_find("", &devices_str); uhd_usrp_find("", &devices_str);
@ -251,15 +258,19 @@ int rf_uhd_open(char *args, void **h)
if (args == NULL) { if (args == NULL) {
args = ""; args = "";
} }
handler->devname = NULL;
/* If device type or name not given in args, choose a B200 */ /* If device type or name not given in args, choose a B200 */
if (args[0]=='\0') { if (args[0]=='\0') {
if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) {
// If B200 is available, use it // If B200 is available, use it
args = "type=b200,recv_frame_size=9232,send_frame_size=9232"; args = "type=b200,recv_frame_size=9232,send_frame_size=9232";
handler->devname = DEVNAME_B200;
} else if (find_string(devices_str, "type=x300")) { } else if (find_string(devices_str, "type=x300")) {
// Else if X300 is available, set master clock rate now (can't be changed later) // Else if X300 is available, set master clock rate now (can't be changed later)
args = "type=x300,master_clock_rate=184.32e6"; args = "type=x300,master_clock_rate=184.32e6";
handler->dynamic_rate = false; handler->dynamic_rate = false;
handler->devname = DEVNAME_X300;
} }
} else { } else {
// If args is set and x300 type is specified, make sure master_clock_rate is defined // If args is set and x300 type is specified, make sure master_clock_rate is defined
@ -267,6 +278,9 @@ int rf_uhd_open(char *args, void **h)
sprintf(args2, "%s,master_clock_rate=184.32e6",args); sprintf(args2, "%s,master_clock_rate=184.32e6",args);
args = args2; args = args2;
handler->dynamic_rate = false; handler->dynamic_rate = false;
handler->devname = DEVNAME_X300;
} else if (strstr(args, "type=b200")) {
handler->devname = DEVNAME_B200;
} }
} }
@ -277,7 +291,19 @@ int rf_uhd_open(char *args, void **h)
fprintf(stderr, "Error opening UHD: code %d\n", error); fprintf(stderr, "Error opening UHD: code %d\n", error);
return -1; return -1;
} }
if (!handler->devname) {
char dev_str[1024];
uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024);
if (strstr(dev_str, "B2") || strstr(dev_str, "B2")) {
handler->devname = DEVNAME_B200;
} else if (strstr(dev_str, "X3") || strstr(dev_str, "X3")) {
handler->devname = DEVNAME_X300;
}
}
if (!handler->devname) {
handler->devname = "uhd_unknown";
}
size_t channel = 0; size_t channel = 0;
uhd_stream_args_t stream_args = { uhd_stream_args_t stream_args = {
.cpu_format = "fc32", .cpu_format = "fc32",
@ -286,6 +312,11 @@ int rf_uhd_open(char *args, void **h)
.channel_list = &channel, .channel_list = &channel,
.n_channels = 1 .n_channels = 1
}; };
// Set external clock reference
if (strstr(args, "clock=external")) {
uhd_usrp_set_clock_source(handler->usrp, "external", 0);
}
handler->has_rssi = get_has_rssi(handler); handler->has_rssi = get_has_rssi(handler);
if (handler->has_rssi) { if (handler->has_rssi) {

@ -30,9 +30,15 @@
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/rf/rf.h" #include "srslte/rf/rf.h"
#define DEVNAME_B200 "uhd_b200"
#define DEVNAME_X300 "uhd_x300"
SRSLTE_API int rf_uhd_open(char *args, SRSLTE_API int rf_uhd_open(char *args,
void **handler); void **handler);
SRSLTE_API char* rf_uhd_devname(void *h);
SRSLTE_API int rf_uhd_close(void *h); SRSLTE_API int rf_uhd_close(void *h);
SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal);

@ -304,7 +304,12 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
/* Correlate input with PSS sequence */ /* Correlate input with PSS sequence
*
* We do not reverse time-domain PSS signal because it's conjugate is symmetric.
* The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2
* This is why we can use FFT-based convolution
*/
if (q->frame_size >= q->fft_size) { if (q->frame_size >= q->fft_size) {
#ifdef CONVOLUTION_FFT #ifdef CONVOLUTION_FFT
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));

@ -61,6 +61,7 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
q->detect_cp = true; q->detect_cp = true;
q->sss_en = true; q->sss_en = true;
q->mean_cfo = 0; q->mean_cfo = 0;
q->mean_cfo2 = 0;
q->N_id_2 = 1000; q->N_id_2 = 1000;
q->N_id_1 = 1000; q->N_id_1 = 1000;
q->cfo_i = 0; q->cfo_i = 0;
@ -77,9 +78,17 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_cfo_init(&q->cfocorr2, q->frame_size)) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
// Set a CFO tolerance of approx 100 Hz // Set a CFO tolerance of approx 50 Hz
srslte_cfo_set_tol(&q->cfocorr, 100.0/(15000.0*q->fft_size)); srslte_cfo_set_tol(&q->cfocorr, 50.0/(15000.0*q->fft_size));
// Set a CFO tolerance of approx 50 Hz
srslte_cfo_set_tol(&q->cfocorr2, 50.0/(15000.0*q->fft_size));
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size); q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size);
@ -89,6 +98,12 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset,
} }
} }
q->temp = srslte_vec_malloc(sizeof(cf_t)*2*q->frame_size);
if (!q->temp) {
perror("malloc");
goto clean_exit;
}
srslte_sync_set_cp(q, SRSLTE_CP_NORM); srslte_sync_set_cp(q, SRSLTE_CP_NORM);
if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) { if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) {
@ -124,6 +139,7 @@ void srslte_sync_free(srslte_sync_t *q) {
srslte_pss_synch_free(&q->pss); srslte_pss_synch_free(&q->pss);
srslte_sss_synch_free(&q->sss); srslte_sss_synch_free(&q->sss);
srslte_cfo_free(&q->cfocorr); srslte_cfo_free(&q->cfocorr);
srslte_cfo_free(&q->cfocorr2);
srslte_cp_synch_free(&q->cp_synch); srslte_cp_synch_free(&q->cp_synch);
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
if (q->cfo_i_corr[i]) { if (q->cfo_i_corr[i]) {
@ -131,6 +147,9 @@ void srslte_sync_free(srslte_sync_t *q) {
} }
srslte_pss_synch_free(&q->pss_i[i]); srslte_pss_synch_free(&q->pss_i[i]);
} }
if (q->temp) {
free(q->temp);
}
} }
} }
@ -185,7 +204,7 @@ uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q) {
} }
float srslte_sync_get_cfo(srslte_sync_t *q) { float srslte_sync_get_cfo(srslte_sync_t *q) {
return q->mean_cfo + q->cfo_i; return q->mean_cfo2 + q->cfo_i;
} }
void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) { void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) {
@ -413,6 +432,8 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
if (peak_position) { if (peak_position) {
*peak_position = 0; *peak_position = 0;
} }
cf_t *input_cfo = input;
if (q->enable_cfo_corr) { if (q->enable_cfo_corr) {
float cfo = cfo_estimate(q, input); float cfo = cfo_estimate(q, input);
@ -421,19 +442,21 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha);
/* Correct CFO with the averaged CFO estimation */ /* Correct CFO with the averaged CFO estimation */
srslte_cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size); srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size);
input_cfo = q->temp;
} }
/* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */ /* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */
if (q->find_cfo_i && q->enable_cfo_corr) { if (q->find_cfo_i && q->enable_cfo_corr) {
q->cfo_i = cfo_i_estimate(q, input, find_offset, &peak_pos); q->cfo_i = cfo_i_estimate(q, input_cfo, find_offset, &peak_pos);
if (q->cfo_i != 0) { if (q->cfo_i != 0) {
srslte_vec_prod_ccc(input, q->cfo_i_corr[q->cfo_i<0?0:1], input, q->frame_size); srslte_vec_prod_ccc(input_cfo, q->cfo_i_corr[q->cfo_i<0?0:1], input_cfo, q->frame_size);
INFO("Compensating cfo_i=%d\n", q->cfo_i); INFO("Compensating cfo_i=%d\n", q->cfo_i);
} }
} else { } else {
srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2);
peak_pos = srslte_pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value); peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value);
if (peak_pos < 0) { if (peak_pos < 0) {
fprintf(stderr, "Error calling finding PSS sequence\n"); fprintf(stderr, "Error calling finding PSS sequence\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -449,7 +472,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
// Set an invalid N_id_1 indicating SSS is yet to be detected // Set an invalid N_id_1 indicating SSS is yet to be detected
q->N_id_1 = 1000; q->N_id_1 = 1000;
if (sync_sss(q, input, find_offset + peak_pos, q->cp) < 0) { if (sync_sss(q, input_cfo, find_offset + peak_pos, q->cp) < 0) {
DEBUG("No space for SSS processing. Frame starts at %d\n", peak_pos); DEBUG("No space for SSS processing. Frame starts at %d\n", peak_pos);
} }
} }
@ -459,13 +482,16 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
if (q->detect_cp) { if (q->detect_cp) {
if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) {
srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input, peak_pos + find_offset)); srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_cfo, peak_pos + find_offset));
} else { } else {
DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos);
} }
} }
if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) {
float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]);
q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha);
ret = SRSLTE_SYNC_FOUND; ret = SRSLTE_SYNC_FOUND;
} else { } else {
ret = SRSLTE_SYNC_FOUND_NOSPACE; ret = SRSLTE_SYNC_FOUND_NOSPACE;

@ -37,7 +37,6 @@
#define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define MAX_LOCATIONS 64
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported
const uint32_t nof_ue_formats = 2; const uint32_t nof_ue_formats = 2;
@ -159,6 +158,15 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
*/ */
void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) {
srslte_pdsch_set_rnti(&q->pdsch, rnti); srslte_pdsch_set_rnti(&q->pdsch, rnti);
// Compute UE-specific and Common search space for this RNTI
for (int cfi=0;cfi<3;cfi++) {
for (int sf_idx=0;sf_idx<10;sf_idx++) {
q->current_ss_ue[cfi][sf_idx].nof_locations = srslte_pdcch_ue_locations(&q->pdcch, q->current_ss_ue[cfi][sf_idx].loc, MAX_CANDIDATES_UE, sf_idx, cfi+1, rnti);
}
q->current_ss_common[cfi].nof_locations = srslte_pdcch_common_locations(&q->pdcch, q->current_ss_common[cfi].loc, MAX_CANDIDATES_COM, cfi+1);
}
q->current_rnti = rnti; q->current_rnti = rnti;
} }
@ -178,12 +186,8 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
* - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti()
* - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti()
*/ */
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx) { int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) {
return srslte_ue_dl_decode_rnti_rv(q, input, data, sf_idx, q->current_rnti, 0); return srslte_ue_dl_decode_rnti(q, input, data, tti, q->current_rnti);
}
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti) {
return srslte_ue_dl_decode_rnti_rv(q, input, data, sf_idx, rnti, 0);
} }
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) { int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) {
@ -241,61 +245,94 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
return srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx); return srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx);
} }
int srslte_ue_dl_decode_rnti_rv_packet(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint8_t *data, int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti)
uint32_t cfi, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
{ {
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
srslte_ra_dl_grant_t grant;
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
uint32_t cfi;
q->nof_detected++;
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ uint32_t sf_idx = tti%10;
if (srslte_ue_dl_cfg_grant(q, grant, cfi, sf_idx, rvidx)) {
return SRSLTE_ERROR;
}
if (q->pdsch_cfg.rv == 0) { if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant->mcs.tbs); return ret;
} }
// Uncoment next line to do ZF by default in pdsch_ue example if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) {
//float noise_estimate = 0; fprintf(stderr, "Error extracting LLRs\n");
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); return SRSLTE_ERROR;
}
int found_dci = srslte_ue_dl_find_dl_dci(q, cfi, sf_idx, rnti, &dci_msg);
if (found_dci == 1) {
if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) {
fprintf(stderr, "Error unpacking DCI\n");
return SRSLTE_ERROR;
}
/* ===== These lines of code are supposed to be MAC functionality === */
uint32_t rvidx = 0;
if (dci_unpacked.rv_idx < 0) {
uint32_t sfn = tti/10;
uint32_t k = (sfn/2)%4;
rvidx = ((uint32_t) ceilf((float)1.5*k))%4;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
} else {
rvidx = dci_unpacked.rv_idx;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
}
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx)) {
return SRSLTE_ERROR;
}
/* ===== End of MAC functionality ========== */
q->nof_detected++;
if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { // Uncoment next line to do ZF by default in pdsch_ue example
ret = srslte_pdsch_decode_rnti(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, //float noise_estimate = 0;
q->sf_symbols, q->ce, float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
noise_estimate,
rnti, data);
if (ret == SRSLTE_ERROR) { if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) {
q->pkt_errors++; ret = srslte_pdsch_decode_rnti(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { q->sf_symbols, q->ce,
fprintf(stderr, "Error calling srslte_pdsch_decode()\n"); noise_estimate,
} else if (ret == SRSLTE_SUCCESS) { rnti, data);
if (SRSLTE_VERBOSE_ISDEBUG()) {
INFO("Decoded Message: ", 0); if (ret == SRSLTE_ERROR) {
srslte_vec_fprint_hex(stdout, data, q->pdsch_cfg.grant.mcs.tbs); q->pkt_errors++;
} } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling srslte_pdsch_decode()\n");
}
} }
q->pkts_total++;
/*
printf("Saving signal...\n");
srslte_vec_save_file("input", input, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
srslte_ue_dl_save_signal(q, &q->softbuffer, sf_idx, rvidx, rnti, cfi);
//exit(-1);
*/
} }
return ret;
}
q->pkts_total++;
if (found_dci == 1 && ret == SRSLTE_SUCCESS) {
return q->pdsch_cfg.grant.mcs.tbs;
} else {
return 0;
}
}
uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) {
return q->last_location.ncce; return q->last_location.ncce;
} }
#define MAX_CANDIDATES_UE 16 // From 36.213 Table 9.1.1-1
#define MAX_CANDIDATES_COM 6 // From 36.213 Table 9.1.1-1
#define MAX_CANDIDATES (MAX_CANDIDATES_UE + MAX_CANDIDATES_COM)
typedef struct {
srslte_dci_format_t format;
srslte_dci_location_t loc[MAX_CANDIDATES];
uint32_t nof_locations;
} dci_blind_search_t;
static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space, uint16_t rnti, srslte_dci_msg_t *dci_msg) static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space, uint16_t rnti, srslte_dci_msg_t *dci_msg)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
@ -304,8 +341,10 @@ static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space,
ret = 0; ret = 0;
int i=0; int i=0;
while (!ret && i < search_space->nof_locations) { while (!ret && i < search_space->nof_locations) {
INFO("Searching format %s in %d,%d\n", DEBUG("Searching format %s in %d,%d (%d/%d)\n",
srslte_dci_format_string(search_space->format), search_space->loc[i].ncce, search_space->loc[i].L); srslte_dci_format_string(search_space->format), search_space->loc[i].ncce, search_space->loc[i].L,
i, search_space->nof_locations);
if (srslte_pdcch_decode_msg(&q->pdcch, dci_msg, &search_space->loc[i], search_space->format, &crc_rem)) { if (srslte_pdcch_decode_msg(&q->pdcch, dci_msg, &search_space->loc[i], search_space->format, &crc_rem)) {
fprintf(stderr, "Error decoding DCI msg\n"); fprintf(stderr, "Error decoding DCI msg\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -316,10 +355,15 @@ static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space,
{ {
q->pending_ul_dci_rnti = crc_rem; q->pending_ul_dci_rnti = crc_rem;
memcpy(&q->pending_ul_dci_msg, dci_msg, sizeof(srslte_dci_msg_t)); memcpy(&q->pending_ul_dci_msg, dci_msg, sizeof(srslte_dci_msg_t));
memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t));
// Else if we found it, save location and leave // Else if we found it, save location and leave
} else if (dci_msg->format == search_space->format) { } else if (dci_msg->format == search_space->format) {
ret = 1; ret = 1;
memcpy(&q->last_location, &search_space->loc[i], sizeof(srslte_dci_location_t)); if (dci_msg->format == SRSLTE_DCI_FORMAT0) {
memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t));
} else {
memcpy(&q->last_location, &search_space->loc[i], sizeof(srslte_dci_location_t));
}
} }
} }
i++; i++;
@ -342,10 +386,19 @@ int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u
// Configure and run DCI blind search // Configure and run DCI blind search
dci_blind_search_t search_space; dci_blind_search_t search_space;
search_space.format = SRSLTE_DCI_FORMAT0; dci_blind_search_t *current_ss = &search_space;
search_space.nof_locations = srslte_pdcch_ue_locations(&q->pdcch, search_space.loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti); if (q->current_rnti == rnti) {
current_ss = &q->current_ss_ue[cfi-1][sf_idx];
} else {
// If locations are not pre-generated, generate them now
current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti);
}
srslte_pdcch_set_cfi(&q->pdcch, cfi);
current_ss->format = SRSLTE_DCI_FORMAT0;
INFO("Searching UL C-RNTI in %d ue locations\n", search_space.nof_locations); INFO("Searching UL C-RNTI in %d ue locations\n", search_space.nof_locations);
return dci_blind_search(q, &search_space, rnti, dci_msg); return dci_blind_search(q, current_ss, rnti, dci_msg);
} else { } else {
return 0; return 0;
} }
@ -390,25 +443,42 @@ static int find_dl_dci_type_siprarnti(srslte_ue_dl_t *q, uint32_t cfi, uint16_t
static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
{ {
int ret = SRSLTE_SUCCESS; int ret = SRSLTE_SUCCESS;
dci_blind_search_t search_space;
dci_blind_search_t *current_ss = &search_space;
// Search UE-specific search space // Search UE-specific search space
dci_blind_search_t search_space; if (q->current_rnti == rnti) {
search_space.nof_locations = srslte_pdcch_ue_locations(&q->pdcch, search_space.loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti); current_ss = &q->current_ss_ue[cfi-1][sf_idx];
INFO("Searching DL C-RNTI in %d ue locations, %d formats\n", search_space.nof_locations, nof_ue_formats); } else {
// If locations are not pre-generated, generate them now
current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti);
}
srslte_pdcch_set_cfi(&q->pdcch, cfi);
INFO("Searching DL C-RNTI in %d ue locations, %d formats\n", current_ss->nof_locations, nof_ue_formats);
for (int f=0;f<nof_ue_formats;f++) { for (int f=0;f<nof_ue_formats;f++) {
search_space.format = ue_formats[f]; current_ss->format = ue_formats[f];
if ((ret = dci_blind_search(q, &search_space, rnti, dci_msg))) { if ((ret = dci_blind_search(q, current_ss, rnti, dci_msg))) {
return ret; return ret;
} }
} }
// Search Format 1A in the Common SS also // Search Format 1A in the Common SS also
search_space.format = SRSLTE_DCI_FORMAT1A; if (q->current_rnti == rnti) {
search_space.nof_locations = srslte_pdcch_common_locations(&q->pdcch, search_space.loc, MAX_CANDIDATES_COM, cfi); current_ss = &q->current_ss_common[cfi-1];
} else {
// If locations are not pre-generated, generate them now
current_ss->nof_locations = srslte_pdcch_common_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_COM, cfi);
}
srslte_pdcch_set_cfi(&q->pdcch, cfi);
// Search for RNTI only if there is room for the common search space // Search for RNTI only if there is room for the common search space
if (search_space.nof_locations > 0) { if (current_ss->nof_locations > 0) {
INFO("Searching DL C-RNTI in %d ue locations, format 1A\n", search_space.nof_locations, nof_ue_formats); current_ss->format = SRSLTE_DCI_FORMAT1A;
return dci_blind_search(q, &search_space, rnti, dci_msg); INFO("Searching DL C-RNTI in %d ue locations, format 1A\n", current_ss->nof_locations);
return dci_blind_search(q, current_ss, rnti, dci_msg);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -423,52 +493,15 @@ int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i
} }
} }
int srslte_ue_dl_decode_rnti_rv(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
{
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
srslte_ra_dl_grant_t grant;
int ret = SRSLTE_ERROR;
uint32_t cfi;
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
return ret;
}
if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) {
fprintf(stderr, "Error extracting LLRs\n");
return SRSLTE_ERROR;
}
int found_dci = srslte_ue_dl_find_dl_dci(q, cfi, sf_idx, rnti, &dci_msg);
if (found_dci == 1) {
if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) {
fprintf(stderr, "Error unpacking DCI\n");
return SRSLTE_ERROR;
}
ret = srslte_ue_dl_decode_rnti_rv_packet(q, &grant, data, cfi, sf_idx, rnti, rvidx);
}
if (found_dci == 1 && ret == SRSLTE_SUCCESS) {
return q->pdsch_cfg.grant.mcs.tbs;
} else {
return 0;
}
}
bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, uint32_t n_dmrs) bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, uint32_t n_dmrs)
{ {
uint8_t ack_bit; uint8_t ack_bit;
float distance; float distance;
uint32_t ngroup, nseq; uint32_t ngroup, nseq;
srslte_phich_calc(&q->phich, n_prb_lowest, n_dmrs, &ngroup, &nseq); srslte_phich_calc(&q->phich, n_prb_lowest, n_dmrs, &ngroup, &nseq);
DEBUG("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d\n", INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n",
sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq); sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq,
srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich));
if (!srslte_phich_decode(&q->phich, q->sf_symbols, q->ce, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { if (!srslte_phich_decode(&q->phich, q->sf_symbols, q->ce, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) {
INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance);
} else { } else {

@ -451,7 +451,7 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) {
if (q->next_rf_sample_offset < 0) { if (q->next_rf_sample_offset < 0) {
q->next_rf_sample_offset = -q->next_rf_sample_offset; q->next_rf_sample_offset = -q->next_rf_sample_offset;
} }
/* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */
if (q->recv_callback(q->stream, &input_buffer[q->next_rf_sample_offset], q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { if (q->recv_callback(q->stream, &input_buffer[q->next_rf_sample_offset], q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -529,7 +529,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
break; break;
case SRSLTE_SYNC_FOUND_NOSPACE: case SRSLTE_SYNC_FOUND_NOSPACE:
/* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */
printf("No space for SSS/CP detection. Realigning frame...\n"); INFO("No space for SSS/CP detection. Realigning frame...\n",0);
q->recv_callback(q->stream, dummy_offset_buffer, q->frame_len/2, NULL); q->recv_callback(q->stream, dummy_offset_buffer, q->frame_len/2, NULL);
srslte_sync_reset(&q->sfind); srslte_sync_reset(&q->sfind);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
@ -605,14 +605,12 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) {
} }
q->frame_total_cnt++; q->frame_total_cnt++;
} else { }
if (q->correct_cfo) { if (q->correct_cfo) {
srslte_cfo_correct(&q->sfind.cfocorr, srslte_cfo_correct(&q->sfind.cfocorr,
input_buffer, input_buffer,
input_buffer, input_buffer,
-srslte_sync_get_cfo(&q->strack) / q->fft_size); -srslte_sync_get_cfo(&q->strack) / q->fft_size);
}
} }
break; break;
} }

@ -65,6 +65,8 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q,
goto clean_exit; goto clean_exit;
} }
srslte_cfo_set_tol(&q->cfo, 0);
if (srslte_pusch_init(&q->pusch, q->cell)) { if (srslte_pusch_init(&q->pusch, q->cell)) {
fprintf(stderr, "Error creating PUSCH object\n"); fprintf(stderr, "Error creating PUSCH object\n");
goto clean_exit; goto clean_exit;
@ -218,64 +220,22 @@ int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant,
return srslte_pusch_cfg(&q->pusch, &q->pusch_cfg, grant, &q->uci_cfg, &q->hopping_cfg, &q->srs_cfg, tti, rvidx, current_tx_nb); return srslte_pusch_cfg(&q->pusch, &q->pusch_cfg, grant, &q->uci_cfg, &q->hopping_cfg, &q->srs_cfg, tti, rvidx, current_tx_nb);
} }
int pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t *format, // Encode bits from uci_data
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], uint8_t pucch2_bits[2], void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format,
srslte_cp_t cp) uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS],
uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS])
{ {
int ret = SRSLTE_SUCCESS; if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) {
pucch_bits[0] = uci_data->uci_ack;
// No CQI data pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a
if (uci_data->uci_cqi_len == 0) {
// 1-bit ACK + optional SR
if (uci_data->uci_ack_len == 1) {
*format = SRSLTE_PUCCH_FORMAT_1A;
pucch_bits[0] = uci_data->uci_ack;
}
// 2-bit ACK + optional SR
else if (uci_data->uci_ack_len == 2) {
*format = SRSLTE_PUCCH_FORMAT_1B;
pucch_bits[0] = uci_data->uci_ack;
pucch_bits[1] = uci_data->uci_ack_2;
}
// SR only
else if (uci_data->scheduling_request) {
*format = SRSLTE_PUCCH_FORMAT_1;
} else {
ret = SRSLTE_ERROR;
}
} }
// CQI data if (format >= SRSLTE_PUCCH_FORMAT_2) {
else {
srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits);
// CQI and no ack if (format > SRSLTE_PUCCH_FORMAT_2) {
if (uci_data->uci_ack_len == 0) {
*format = SRSLTE_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (uci_data->uci_cqi_len > 0 && uci_data->uci_ack_len == 1) {
*format = SRSLTE_PUCCH_FORMAT_2A;
pucch2_bits[0] = uci_data->uci_ack;
}
// CQI + 2-bit ACK
else if (uci_data->uci_cqi_len > 0 && uci_data->uci_ack_len == 2) {
*format = SRSLTE_PUCCH_FORMAT_2B;
pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[0] = uci_data->uci_ack;
pucch2_bits[1] = uci_data->uci_ack_2; pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a
}
// CQI + 2-bit ACK + cyclic prefix
else if (uci_data->uci_cqi_len > 0 && uci_data->uci_ack_len == 1 && SRSLTE_CP_ISEXT(cp)) {
*format = SRSLTE_PUCCH_FORMAT_2B;
pucch2_bits[0] = uci_data->uci_ack;
pucch2_bits[1] = uci_data->uci_ack_2;
} else {
ret = SRSLTE_ERROR;
} }
} }
if (ret) {
fprintf(stderr, "Unsupported combination of UCI parameters: ack_len=%d, cqi_len=%d\n",
uci_data->uci_ack, uci_data->uci_cqi_len);
}
return ret;
} }
/* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal /* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal
@ -301,35 +261,25 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data,
bzero(pucch_bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); bzero(pucch_bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
bzero(pucch2_bits, 2*sizeof(uint8_t)); bzero(pucch2_bits, 2*sizeof(uint8_t));
srslte_pucch_format_t format = srslte_pucch_get_format(&uci_data, q->cell.cp);
// Encode UCI information // Encode UCI information
if (pucch_encode_bits(&uci_data, &q->last_pucch_format, pucch_bits, pucch2_bits, q->cell.cp)) { pucch_encode_bits(&uci_data, format, pucch_bits, pucch2_bits);
return SRSLTE_ERROR;
}
// Choose n_pucch // Choose n_pucch
uint32_t n_pucch = 0; uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data.scheduling_request, &q->pucch_sched);
if (uci_data.scheduling_request) {
n_pucch = q->pucch_sched.n_pucch_sr; if (srslte_pucch_encode(&q->pucch, format, n_pucch, sf_idx, pucch_bits, q->sf_symbols)) {
} else if (q->last_pucch_format < SRSLTE_PUCCH_FORMAT_2) {
if (q->pucch_sched.sps_enabled) {
n_pucch = q->pucch_sched.n_pucch_1[q->pucch_sched.tpc_for_pucch%4];
} else {
n_pucch = pdcch_n_cce + q->pucch_sched.N_pucch_1;
}
} else {
n_pucch = q->pucch_sched.n_pucch_2;
}
if (srslte_pucch_encode(&q->pucch, q->last_pucch_format, n_pucch, sf_idx, pucch_bits, q->sf_symbols)) {
fprintf(stderr, "Error encoding TB\n"); fprintf(stderr, "Error encoding TB\n");
return ret; return ret;
} }
if (srslte_refsignal_dmrs_pucch_gen(&q->signals, q->last_pucch_format, n_pucch, sf_idx, pucch2_bits, q->refsignal)) if (srslte_refsignal_dmrs_pucch_gen(&q->signals, format, n_pucch, sf_idx, pucch2_bits, q->refsignal))
{ {
fprintf(stderr, "Error generating PUSCH DRMS signals\n"); fprintf(stderr, "Error generating PUSCH DRMS signals\n");
return ret; return ret;
} }
srslte_refsignal_dmrs_pucch_put(&q->signals, q->last_pucch_format, n_pucch, q->refsignal, q->sf_symbols); srslte_refsignal_dmrs_pucch_put(&q->signals, format, n_pucch, q->refsignal, q->sf_symbols);
if (srslte_ue_ul_srs_tx_enabled(&q->signals.srs_cfg, tti) && q->pucch.shortened) { if (srslte_ue_ul_srs_tx_enabled(&q->signals.srs_cfg, tti) && q->pucch.shortened) {
if (q->signals_pregenerated) { if (q->signals_pregenerated) {
@ -339,6 +289,8 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data,
srslte_refsignal_srs_put(&q->signals, tti, q->srs_signal, q->sf_symbols); srslte_refsignal_srs_put(&q->signals, tti, q->srs_signal, q->sf_symbols);
} }
} }
q->last_pucch_format = format;
srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal);

Loading…
Cancel
Save