Commit f9fc712a authored by Raymond Knopp's avatar Raymond Knopp

Merge branch 'NR_RRC_PRACH_procedures' of...

Merge branch 'NR_RRC_PRACH_procedures' of https://gitlab.eurecom.fr/oai/openairinterface5g into NR_RRC_PRACH_procedures
parents e9ff6bad 6e404180
...@@ -2835,7 +2835,7 @@ add_executable(nr_prachsim ...@@ -2835,7 +2835,7 @@ add_executable(nr_prachsim
${T_SOURCE} ${T_SOURCE}
${SHLIB_LOADER_SOURCES}) ${SHLIB_LOADER_SOURCES})
target_link_libraries(nr_prachsim target_link_libraries(nr_prachsim
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB SCHED_NR_UE_LIB RRC_LIB NR_RRC_LIB L2_NR CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} ${ITTI_LIB} dl) -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB MAC_UE_NR SCHED_NR_UE_LIB RRC_LIB NR_RRC_LIB L2_NR CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} ${ITTI_LIB} dl)
add_executable(nr_ulschsim add_executable(nr_ulschsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c
......
...@@ -801,7 +801,7 @@ int main( int argc, char **argv ) { ...@@ -801,7 +801,7 @@ int main( int argc, char **argv ) {
} }
if (UE[CC_id]->frame_parms.threequarter_fs == 1) factor = factor*.75; if (UE[CC_id]->frame_parms.threequarter_fs == 1) factor = factor*.75;
UE[CC_id]->N_TA_offset = (int)(N_TA_offset * factor); UE[CC_id]->N_TA_offset = (int)(N_TA_offset * factor);
LOG_I(PHY,"UE %d Setting N_TA_offset to %d samples (factor %f, UL Freq %d, N_RB %d)\n", UE[CC_id]->Mod_id, UE[CC_id]->N_TA_offset, factor, UE[CC_id]->frame_parms.ul_CarrierFreq, N_RB); LOG_I(PHY,"UE %d Setting N_TA_offset to %d samples (factor %f, UL Freq %lu, N_RB %d)\n", UE[CC_id]->Mod_id, UE[CC_id]->N_TA_offset, factor, UE[CC_id]->frame_parms.ul_CarrierFreq, N_RB);
} }
} }
......
...@@ -75,8 +75,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -75,8 +75,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
fapi_nr_ul_config_prach_pdu *prach_pdu = &ue->prach_vars[gNB_id]->prach_pdu; fapi_nr_ul_config_prach_pdu *prach_pdu = &ue->prach_vars[gNB_id]->prach_pdu;
uint8_t Mod_id, fd_occasion, preamble_index, restricted_set, not_found; uint8_t Mod_id, fd_occasion, preamble_index, restricted_set, not_found;
uint16_t rootSequenceIndex, prach_fmt_id, NCS, *prach_root_sequence_map, preamble_offset; uint16_t rootSequenceIndex, prach_fmt_id, NCS, *prach_root_sequence_map, preamble_offset = 0;
uint16_t preamble_shift, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx; uint16_t preamble_shift = 0, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx;
int16_t prach_tmp[98304*2*4] __attribute__((aligned(32))); int16_t prach_tmp[98304*2*4] __attribute__((aligned(32)));
int16_t Ncp, amp, *prach, *prach2, *prachF, *Xu; int16_t Ncp, amp, *prach, *prach2, *prachF, *Xu;
int32_t Xu_re, Xu_im, samp_count; int32_t Xu_re, Xu_im, samp_count;
...@@ -95,7 +95,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -95,7 +95,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
n_ra_prb = prach_pdu->freq_msg1; n_ra_prb = prach_pdu->freq_msg1;
NCS = prach_pdu->num_cs; NCS = prach_pdu->num_cs;
prach_fmt_id = prach_pdu->prach_format; prach_fmt_id = prach_pdu->prach_format;
preamble_index = 0; //prach_resources->ra_PreambleIndex // temporary hardcoded preamble_index = prach_resources->ra_PreambleIndex;
fd_occasion = 0; fd_occasion = 0;
prach_len = 0; prach_len = 0;
dftlen = 0; dftlen = 0;
...@@ -118,15 +118,15 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -118,15 +118,15 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
#if defined (OAI_USRP) #if defined (OAI_USRP)
prach_start = (ue->rx_offset + slot*samp_count - ue->hw_timing_advance - ue->N_TA_offset); prach_start = (ue->rx_offset + slot*samp_count - ue->hw_timing_advance - ue->N_TA_offset);
#else //normal case (simulation)
prach_start = slot*samp_count - ue->N_TA_offset;
#endif
if (prach_start<0) if (prach_start<0)
prach_start += (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME); prach_start += (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME);
if (prach_start >= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME)) if (prach_start >= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME))
prach_start -= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME); prach_start -= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME);
#else //normal case (simulation)
prach_start = slot*(fp->samples_per_subframe)-ue->N_TA_offset;
#endif
// First compute physical root sequence // First compute physical root sequence
/************************************************************************ /************************************************************************
...@@ -138,10 +138,9 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -138,10 +138,9 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
prach_root_sequence_map = (prach_sequence_length == 0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; prach_root_sequence_map = (prach_sequence_length == 0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;
if (restricted_set == 0) {
// This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index // This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS))); preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS)));
if (restricted_set == 0) {
// This is the \nu corresponding to the preamble index // This is the \nu corresponding to the preamble index
preamble_shift = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS)); preamble_shift = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS));
preamble_shift *= NCS; preamble_shift *= NCS;
...@@ -204,9 +203,6 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -204,9 +203,6 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
} }
} }
preamble_offset = 0;
preamble_shift = 0;
// now generate PRACH signal // now generate PRACH signal
#ifdef NR_PRACH_DEBUG #ifdef NR_PRACH_DEBUG
if (NCS>0) if (NCS>0)
...@@ -573,8 +569,6 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){ ...@@ -573,8 +569,6 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
} else if (prach_fmt_id == 1 || prach_fmt_id == 4) { // 6x1536 } else if (prach_fmt_id == 1 || prach_fmt_id == 4) { // 6x1536
printf(" CHECK 3/4 sampling prachFormat == 0xa2\n");
Ncp+=24; // This assumes we are transmitting starting in symbol 0 of a PRACH slot, 30 kHz, full sampling Ncp+=24; // This assumes we are transmitting starting in symbol 0 of a PRACH slot, 30 kHz, full sampling
prach2 = prach+(Ncp<<1); prach2 = prach+(Ncp<<1);
idft1536(prachF,prach2,1); idft1536(prachF,prach2,1);
......
...@@ -4495,7 +4495,7 @@ uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue, ...@@ -4495,7 +4495,7 @@ uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue,
// - power control as per 38.213 ch 7.4 // - power control as per 38.213 ch 7.4
void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id, runmode_t runmode) { void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id, runmode_t runmode) {
int frame_tx = proc->frame_tx, nr_tti_tx = proc->nr_tti_tx, prach_power, tx_amp; int frame_tx = proc->frame_tx, nr_tti_tx = proc->nr_tti_tx, prach_power; // tx_amp
uint16_t /*preamble_tx = 50,*/ pathloss; uint16_t /*preamble_tx = 50,*/ pathloss;
uint8_t mod_id = ue->Mod_id; uint8_t mod_id = ue->Mod_id;
UE_MODE_t UE_mode = get_nrUE_mode(mod_id, ue->CC_id, gNB_id); UE_MODE_t UE_mode = get_nrUE_mode(mod_id, ue->CC_id, gNB_id);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h>
#include "common/config/config_userapi.h" #include "common/config/config_userapi.h"
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
...@@ -35,7 +36,6 @@ ...@@ -35,7 +36,6 @@
#include "SCHED_NR/sched_nr.h" #include "SCHED_NR/sched_nr.h"
#include "SCHED_NR_UE/phy_frame_config_nr.h" #include "SCHED_NR_UE/phy_frame_config_nr.h"
#include "PHY/phy_vars_nr_ue.h" #include "PHY/phy_vars_nr_ue.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h" #include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/NR_REFSIG/nr_mod_table.h" #include "PHY/NR_REFSIG/nr_mod_table.h"
#include "PHY/MODULATION/modulation_eNB.h" #include "PHY/MODULATION/modulation_eNB.h"
...@@ -47,107 +47,74 @@ ...@@ -47,107 +47,74 @@
#include "nr_unitary_defs.h" #include "nr_unitary_defs.h"
#include "OCG_vars.h" #include "OCG_vars.h"
#include <pthread.h> #define NR_PRACH_DEBUG 1
#define PRACH_WRITE_OUTPUT_DEBUG 1
PHY_VARS_gNB *gNB; PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE; PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC; RAN_CONTEXT_t RC;
RU_t *ru; RU_t *ru;
double cpuf; double cpuf;
extern uint16_t prach_root_sequence_map0_3[838]; extern uint16_t prach_root_sequence_map0_3[838];
void dump_nr_prach_config(NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe);
uint16_t NB_UE_INST=1; uint16_t NB_UE_INST=1;
openair0_config_t openair0_cfg[MAX_CARDS]; openair0_config_t openair0_cfg[MAX_CARDS];
uint8_t nfapi_mode=0; uint8_t nfapi_mode=0;
int sl_ahead = 0;
//void dump_nr_prach_config(NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe);
void nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources, /* temporary dummy implem of get_softmodem_optmask, till basic simulators implemented as device */
module_id_t mod_id, uint64_t get_softmodem_optmask(void) {return 0;}
int CC_id, softmodem_params_t *get_softmodem_params(void) {return 0;}
UE_MODE_t UE_mode,
frame_t frame,
uint8_t gNB_id,
int nr_tti_tx) { return;}
void nr_Msg1_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint8_t gNB_id) { return;}
uint16_t nr_ue_process_rar(module_id_t mod_id, void pdcp_run (const protocol_ctxt_t *const ctxt_pP) { return;}
int CC_id,
frame_t frameP,
uint8_t * dlsch_buffer,
rnti_t * t_crnti,
uint8_t preamble_index,
uint8_t * selected_rar_buffer) { return 0;}
int is_nr_prach_subframe(NR_DL_FRAME_PARMS *fp,uint32_t frame,uint8_t slot) { return(1);} boolean_t pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
const srb_flag_t srb_flagP,
const MBMS_flag_t MBMS_flagP,
const rb_id_t rb_idP,
const sdu_size_t sdu_buffer_sizeP,
mem_block_t *const sdu_buffer_pP) {return(false);}
int get_nr_prach_fmt(int prachConfigIndex,int frame_type,int fr) { return(0xa2); } void nr_ip_over_LTE_DRB_preconfiguration(void){}
void pdcp_layer_init(void) {}
int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, const int CC_id, const uint8_t gNB_index, const int8_t channel, const uint8_t* pduP, const sdu_size_t pdu_len) {return 0;}
int main(int argc, char **argv){
int main(int argc, char **argv)
{
char c; char c;
double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0;
int i,aa,aarx; double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs, bw;
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1=0.0,ue_speed0=0.0,ue_speed1=0.0; int i, aa, aarx, **txdata, trial, n_frames = 1, prach_start, rx_prach_start; //, ntrials=1;
uint8_t snr1set=0; int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, loglvl = OAILOG_INFO, numRA = 0, prachStartSymbol = 0;
uint8_t ue_speed1set=0; uint8_t snr1set = 0, ue_speed1set = 0, transmission_mode = 1, n_tx = 1, n_rx = 1, awgn_flag = 0, msg1_frequencystart = 0, num_prach_fd_occasions = 1, prach_format;
int **txdata; uint8_t frame = 1, subframe = 19, config_index = 98, prach_sequence_length = 1, num_root_sequences = 16, restrictedSetConfig = 0, N_dur, N_t_slot, start_symbol;
double **s_re,**s_im,**r_re,**r_im; uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format, format0, format1;
double iqim=0.0; uint32_t tx_lev = 10000, prach_errors = 0, samp_count; //,tx_lev_dB;
int trial; //, ntrials=1; uint64_t SSB_positions = 0x01, absoluteFrequencyPointA = 640000;
uint8_t transmission_mode = 1,n_tx=1,n_rx=1;
uint16_t Nid_cell=0;
uint8_t awgn_flag=0;
uint8_t hs_flag=0;
int n_frames=1;
channel_desc_t *UE2gNB;
uint32_t nsymb,tx_lev=10000; //,tx_lev_dB;
// int8_t interf1=-19,interf2=-19; // int8_t interf1=-19,interf2=-19;
NR_DL_FRAME_PARMS *frame_parms;
SCM_t channel_model=Rayleigh1;
// uint8_t abstraction_flag=0,calibration_flag=0; // uint8_t abstraction_flag=0,calibration_flag=0;
// double prach_sinr; // double prach_sinr;
int N_RB_UL=273; // uint32_t nsymb;
uint32_t prach_errors=0; // uint16_t preamble_max, preamble_energy_max;
uint8_t subframe=9;
uint16_t preamble_energy, preamble_tx=50, preamble_delay; NR_DL_FRAME_PARMS *frame_parms;
uint16_t preamble_max,preamble_energy_max;
NR_PRACH_RESOURCES_t prach_resources; NR_PRACH_RESOURCES_t prach_resources;
//uint8_t prach_fmt; nfapi_nr_prach_config_t *prach_config;
//int N_ZC; nfapi_nr_prach_pdu_t *prach_pdu;
int delay = 0; fapi_nr_prach_config_t *ue_prach_config;
double delay_avg=0; fapi_nr_ul_config_prach_pdu *ue_prach_pdu;
double ue_speed = 0;
int NCS_config = 13,rootSequenceIndex=0;
int threequarter_fs = 0;
int mu=1;
uint64_t SSB_positions=0x01;
int loglvl=OAILOG_INFO;
channel_desc_t *UE2gNB;
SCM_t channel_model = Rayleigh1;
cpuf = get_cpu_freq_GHz(); cpuf = get_cpu_freq_GHz();
if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) { if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) {
exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
} }
randominit(0); randominit(0);
while ((c = getopt (argc, argv, "hHaA:Cr:p:g:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) { while ((c = getopt (argc, argv, "hHaA:Cr:p:g:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) {
switch (c) { switch (c) {
case 'a': case 'a':
...@@ -262,7 +229,7 @@ int main(int argc, char **argv) ...@@ -262,7 +229,7 @@ int main(int argc, char **argv)
case 'H': case 'H':
printf("High-Speed Flag enabled\n"); printf("High-Speed Flag enabled\n");
hs_flag = 1; restrictedSetConfig = 1;
break; break;
case 'L': case 'L':
...@@ -343,20 +310,13 @@ int main(int argc, char **argv) ...@@ -343,20 +310,13 @@ int main(int argc, char **argv)
} }
} }
// Configure log
logInit(); logInit();
set_glog(loglvl); set_glog(loglvl);
T_stdout = 1; T_stdout = 1;
SET_LOG_DEBUG(PRACH); SET_LOG_DEBUG(PRACH);
if (snr1set==0) { // Configure gNB and RU
if (n_frames==1)
snr1 = snr0+.1;
else
snr1 = snr0+5.0;
}
RC.gNB = (PHY_VARS_gNB**) malloc(2*sizeof(PHY_VARS_gNB *)); RC.gNB = (PHY_VARS_gNB**) malloc(2*sizeof(PHY_VARS_gNB *));
RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB)); RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB));
memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB)); memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
...@@ -368,96 +328,192 @@ int main(int argc, char **argv) ...@@ -368,96 +328,192 @@ int main(int argc, char **argv)
gNB = RC.gNB[0]; gNB = RC.gNB[0];
ru = RC.ru[0]; ru = RC.ru[0];
if (ue_speed1set==0) {
if (n_frames==1)
ue_speed1 = ue_speed0+10;
else
ue_speed1 = ue_speed0+50;
}
printf("SNR0 %f, SNR1 %f\n",snr0,snr1);
frame_parms = &gNB->frame_parms; frame_parms = &gNB->frame_parms;
prach_config = &gNB->gNB_config.prach_config;
prach_pdu = &gNB->prach_vars.list[0].pdu;
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
s_re = malloc(2*sizeof(double*)); s_re = malloc(2*sizeof(double*));
s_im = malloc(2*sizeof(double*)); s_im = malloc(2*sizeof(double*));
r_re = malloc(2*sizeof(double*)); r_re = malloc(2*sizeof(double*));
r_im = malloc(2*sizeof(double*)); r_im = malloc(2*sizeof(double*));
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_tx = n_tx;
frame_parms->nb_antennas_rx = n_rx; frame_parms->nb_antennas_rx = n_rx;
frame_parms->N_RB_DL = N_RB_UL; frame_parms->N_RB_DL = N_RB_UL;
frame_parms->N_RB_UL = N_RB_UL; frame_parms->N_RB_UL = N_RB_UL;
frame_parms->threequarter_fs = threequarter_fs; frame_parms->threequarter_fs = threequarter_fs;
nr_phy_config_request_sim(gNB,N_RB_UL,N_RB_UL,mu,Nid_cell,SSB_positions);
frame_parms->frame_type = TDD; frame_parms->frame_type = TDD;
frame_parms->freq_range = nr_FR1; frame_parms->freq_range = nr_FR1;
frame_parms->numerology_index = mu;
nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions);
nsymb = (frame_parms->Ncp == 0) ? 14 : 12; //nsymb = (frame_parms->Ncp == 0) ? 14 : 12;
printf("FFT Size %d, Extended Prefix %d, Samples per subframe %d,Frame type %s, Frequency Range %s\n",NUMBER_OF_OFDM_CARRIERS, printf("FFT Size %d, Extended Prefix %d, Samples per subframe %d, Frame type %s, Frequency Range %s\n",
frame_parms->Ncp,frame_parms->samples_per_subframe,frame_parms->frame_type == FDD ? "FDD" : "TDD", frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2"); NUMBER_OF_OFDM_CARRIERS,
frame_parms->Ncp,
frame_parms->samples_per_subframe,
frame_parms->frame_type == FDD ? "FDD" : "TDD",
frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2");
ru->nr_frame_parms=frame_parms; ru->nr_frame_parms = frame_parms;
ru->if_south = LOCAL_RF; ru->if_south = LOCAL_RF;
ru->nb_tx = n_tx; ru->nb_tx = n_tx;
ru->nb_rx = n_rx; ru->nb_rx = n_rx;
gNB->gNB_config.carrier_config.num_tx_ant.value=1; gNB->gNB_config.carrier_config.num_tx_ant.value = 1;
gNB->gNB_config.carrier_config.num_rx_ant.value=1; gNB->gNB_config.carrier_config.num_rx_ant.value = 1;
gNB->gNB_config.prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *) malloc(gNB->gNB_config.prach_config.num_prach_fd_occasions.value*sizeof(nfapi_nr_num_prach_fd_occasions_t));
gNB->gNB_config.prach_config.num_prach_fd_occasions_list[0].prach_root_sequence_index.value = 1;
gNB->gNB_config.prach_config.num_prach_fd_occasions_list[0].num_root_sequences.value = 16;
gNB->gNB_config.prach_config.prach_sequence_length.value = 1;
gNB->gNB_config.prach_config.num_prach_fd_occasions_list[0].k1.value = 0;
gNB->gNB_config.prach_config.restricted_set_config.value = 0;
gNB->gNB_config.tdd_table.tdd_period.value = 6; gNB->gNB_config.tdd_table.tdd_period.value = 6;
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config)); gNB->gNB_config.prach_config.num_prach_fd_occasions.value = num_prach_fd_occasions;
gNB->gNB_config.prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(nfapi_nr_num_prach_fd_occasions_t));
gNB->proc.slot_rx = subframe;
get_nr_prach_info_from_index(config_index,
(int)frame,
(int)subframe,
absoluteFrequencyPointA,
mu,
frame_parms->frame_type,
&format,
&start_symbol,
&N_t_slot,
&N_dur);
format0 = format&0xff; // first column of format from table
format1 = (format>>8)&0xff; // second column of format from table
if (format1 != 0xff) {
switch(format0) {
case 0xa1:
prach_format = 9;
break;
case 0xa2:
prach_format = 10;
break;
case 0xa3:
prach_format = 11;
break;
default:
AssertFatal(1==0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
}
} else {
switch(format0) {
case 0xa1:
prach_format = 0;
break;
case 0xa2:
prach_format = 1;
break;
case 0xa3:
prach_format = 2;
break;
case 0xb1:
prach_format = 3;
break;
case 0xb2:
prach_format = 4;
break;
case 0xb3:
prach_format = 5;
break;
case 0xb4:
prach_format = 6;
break;
case 0xc0:
prach_format = 7;
break;
case 0xc2:
prach_format = 8;
break;
case 0:
// long formats are handled @ PHY
break;
case 1:
// long formats are handled @ PHY
break;
case 2:
// long formats are handled @ PHY
break;
case 3:
// long formats are handled @ PHY
break;
default:
AssertFatal(1==0, "Invalid PRACH format");
}
}
prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index.value = rootSequenceIndex;
prach_config->num_prach_fd_occasions_list[fd_occasion].k1.value = msg1_frequencystart;
prach_config->restricted_set_config.value = restrictedSetConfig;
prach_config->prach_sequence_length.value = prach_sequence_length;
prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value = num_root_sequences;
prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig);
prach_pdu->prach_format = prach_format;
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
RC.nb_nr_L1_inst=1; RC.nb_nr_L1_inst=1;
phy_init_nr_gNB(gNB,0,0); phy_init_nr_gNB(gNB,0,0);
nr_phy_init_RU(ru); nr_phy_init_RU(ru);
gNB->common_vars.rxdata = ru->common.rxdata;
set_tdd_config_nr(&gNB->gNB_config, mu, 7, 6, 2, 4);
// Configure UE
set_tdd_config_nr(&gNB->gNB_config, 1,
7, 6,
2, 4);
//configure UE
UE = malloc(sizeof(PHY_VARS_NR_UE)); UE = malloc(sizeof(PHY_VARS_NR_UE));
memset((void*)UE,0,sizeof(PHY_VARS_NR_UE)); memset((void*)UE,0,sizeof(PHY_VARS_NR_UE));
PHY_vars_UE_g = malloc(2*sizeof(PHY_VARS_NR_UE**)); PHY_vars_UE_g = malloc(2*sizeof(PHY_VARS_NR_UE**));
PHY_vars_UE_g[0] = malloc(2*sizeof(PHY_VARS_NR_UE*)); PHY_vars_UE_g[0] = malloc(2*sizeof(PHY_VARS_NR_UE*));
PHY_vars_UE_g[0][0] = UE; PHY_vars_UE_g[0][0] = UE;
memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
if (init_nr_ue_signal(UE, 1, 0) != 0) UE->nrUE_config.prach_config.num_prach_fd_occasions_list = (fapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(fapi_nr_num_prach_fd_occasions_t));
{
if (init_nr_ue_signal(UE, 1, 0) != 0){
printf("Error at UE NR initialisation\n"); printf("Error at UE NR initialisation\n");
exit(-1); exit(-1);
} }
ue_prach_pdu = &UE->prach_vars[0]->prach_pdu;
ue_prach_config = &UE->nrUE_config.prach_config;
UE->prach_resources[0] = &prach_resources;
txdata = UE->common_vars.txdata; txdata = UE->common_vars.txdata;
printf("txdata %p\n",&txdata[0][subframe*frame_parms->samples_per_subframe]);
double fs,bw; UE->prach_vars[0]->amp = AMP;
ue_prach_pdu->root_seq_id = rootSequenceIndex;
ue_prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig);
ue_prach_pdu->restricted_set = restrictedSetConfig;
ue_prach_pdu->freq_msg1 = msg1_frequencystart;
ue_prach_pdu->prach_format = prach_format;
ue_prach_config->prach_sub_c_spacing = mu;
ue_prach_config->prach_sequence_length = prach_sequence_length;
ue_prach_config->restricted_set_config = restrictedSetConfig;
ue_prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences = num_root_sequences;
ue_prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index = rootSequenceIndex;
ue_prach_config->num_prach_fd_occasions_list[fd_occasion].k1 = msg1_frequencystart;
if (preamble_tx == 99)
preamble_tx = (uint16_t)(taus()&0x3f);
bw = N_RB_UL*(180e3)*(1<<gNB->frame_parms.numerology_index); if (n_frames == 1)
AssertFatal(bw<=122.88e6,"Illegal channel bandwidth %f (mu %d,N_RB_UL %d)\n",gNB->frame_parms.numerology_index,N_RB_UL); printf("raPreamble %d\n",preamble_tx);
if (bw <= 30.72e6) fs = 30.72e6;
else if (bw <= 61.44e6) fs = 61.44e6; UE->prach_resources[0]->ra_PreambleIndex = preamble_tx;
else if (bw <= 122.88e6) fs = 122.88e6;
LOG_I(PHY,"Running with bandwidth %f Hz, fs %f samp/s, FRAME_LENGTH_COMPLEX_SAMPLES %d\n",bw,fs,FRAME_LENGTH_COMPLEX_SAMPLES);
// Configure channel
bw = N_RB_UL*(180e3)*(1 << frame_parms->numerology_index);
AssertFatal(bw<=122.88e6,"Illegal channel bandwidth %f (mu %d,N_RB_UL %d)\n", bw, frame_parms->numerology_index, N_RB_UL);
if (bw <= 30.72e6)
fs = 30.72e6;
else if (bw <= 61.44e6)
fs = 61.44e6;
else if (bw <= 122.88e6)
fs = 122.88e6;
LOG_I(PHY,"Running with bandwidth %f Hz, fs %f samp/s, FRAME_LENGTH_COMPLEX_SAMPLES %d\n",bw,fs,FRAME_LENGTH_COMPLEX_SAMPLES);
UE2gNB = new_channel_desc_scm(UE->frame_parms.nb_antennas_tx, UE2gNB = new_channel_desc_scm(UE->frame_parms.nb_antennas_tx,
gNB->frame_parms.nb_antennas_rx, gNB->frame_parms.nb_antennas_rx,
...@@ -486,82 +542,80 @@ int main(int argc, char **argv) ...@@ -486,82 +542,80 @@ int main(int argc, char **argv)
bzero(r_im[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double)); bzero(r_im[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
} }
UE->frame_parms.prach_config_common.rootSequenceIndex=rootSequenceIndex; // compute PRACH sequence
UE->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex=98; compute_nr_prach_seq(prach_config->prach_sequence_length.value,
UE->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=NCS_config; prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value,
UE->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag=hs_flag; prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index.value,
UE->frame_parms.prach_config_common.prach_ConfigInfo.restrictedSetConfig=0; gNB->X_u);
UE->frame_parms.prach_config_common.prach_ConfigInfo.msg1_frequencystart=0;
gNB->frame_parms.prach_config_common.rootSequenceIndex=rootSequenceIndex;
gNB->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex=98;
gNB->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=NCS_config;
gNB->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag=hs_flag;
gNB->frame_parms.prach_config_common.prach_ConfigInfo.restrictedSetConfig=0;
gNB->frame_parms.prach_config_common.prach_ConfigInfo.msg1_frequencystart=0;
gNB->proc.slot_rx = subframe<<1;
gNB->common_vars.rxdata = ru->common.rxdata;
compute_nr_prach_seq(&gNB->gNB_config,0,gNB->X_u);
compute_nr_prach_seq(&gNB->gNB_config,0,UE->X_u);
UE->prach_vars[0]->amp = AMP;
UE->prach_resources[0] = &prach_resources;
if (preamble_tx == 99)
preamble_tx = (uint16_t)(taus()&0x3f);
if (n_frames == 1)
printf("raPreamble %d\n",preamble_tx);
UE->prach_resources[0]->ra_PreambleIndex = preamble_tx; compute_nr_prach_seq(ue_prach_config->prach_sequence_length,
UE->prach_resources[0]->ra_TDD_map_index = 0; ue_prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences,
ue_prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index,
UE->X_u);
/*tx_lev = generate_nr_prach(UE, /*tx_lev = generate_nr_prach(UE,
0, //gNB_id, 0, //gNB_id,
subframe); */ //commented for testing purpose subframe); */ //commented for testing purpose
UE_nr_rxtx_proc_t proc={0}; UE_nr_rxtx_proc_t proc={0};
proc.frame_tx=0;proc.nr_tti_tx=subframe; proc.frame_tx = frame;
proc.nr_tti_tx = subframe;
nr_ue_prach_procedures(UE,&proc,0,0); nr_ue_prach_procedures(UE,&proc,0,0);
/* tx_lev_dB not used later, no need to set */ /* tx_lev_dB not used later, no need to set */
//tx_lev_dB = (unsigned int) dB_fixed(tx_lev); //tx_lev_dB = (unsigned int) dB_fixed(tx_lev);
LOG_M("txsig0.m","txs0", &txdata[0][subframe*frame_parms->samples_per_subframe],frame_parms->samples_per_subframe,1,1); if (mu == 0)
samp_count = frame_parms->samples_per_subframe;
else
samp_count = (subframe%(frame_parms->slots_per_subframe/2)) ? frame_parms->samples_per_slotN0 : frame_parms->samples_per_slot0;
prach_start = subframe*samp_count - UE->N_TA_offset;
#ifdef NR_PRACH_DEBUG
LOG_M("txsig0.m", "txs0", &txdata[0][prach_start], samp_count, 1, 1);
//LOG_M("txsig1.m","txs1", txdata[1],FRAME_LENGTH_COMPLEX_SAMPLES,1,1); //LOG_M("txsig1.m","txs1", txdata[1],FRAME_LENGTH_COMPLEX_SAMPLES,1,1);
#endif
// multipath channel // multipath channel
// dump_nr_prach_config(&gNB->frame_parms,subframe); // dump_nr_prach_config(&gNB->frame_parms,subframe);
for (i=0; i<frame_parms->samples_per_slot<<1; i++) { for (i = 0; i < samp_count<<1; i++) {
for (aa=0; aa<1; aa++) { for (aa=0; aa<1; aa++) {
if (awgn_flag == 0) { if (awgn_flag == 0) {
s_re[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); s_re[aa][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
s_im[aa][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); s_im[aa][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
} else { } else {
for (aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) { for (aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
if (aa==0) { if (aa==0) {
r_re[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); r_re[aarx][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
r_im[aarx][i] = ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); r_im[aarx][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
} else { } else {
r_re[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)]); r_re[aarx][i] += ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
r_im[aarx][i] += ((double)(((short *)&txdata[aa][subframe*frame_parms->samples_per_subframe]))[(i<<1)+1]); r_im[aarx][i] += ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
} }
} }
} }
} }
} }
if (snr1set == 0) {
if (n_frames == 1)
snr1 = snr0 + .1;
else
snr1 = snr0 + 5.0;
}
printf("SNR0 %f, SNR1 %f\n", snr0, snr1);
if (ue_speed1set == 0) {
if (n_frames == 1)
ue_speed1 = ue_speed0 + 10;
else
ue_speed1 = ue_speed0 + 50;
}
rx_prach_start = subframe*frame_parms->get_samples_per_slot(subframe,frame_parms);
for (SNR=snr0; SNR<snr1; SNR+=.2) { for (SNR=snr0; SNR<snr1; SNR+=.2) {
for (ue_speed=ue_speed0; ue_speed<ue_speed1; ue_speed+=10) { for (ue_speed=ue_speed0; ue_speed<ue_speed1; ue_speed+=10) {
...@@ -573,6 +627,8 @@ int main(int argc, char **argv) ...@@ -573,6 +627,8 @@ int main(int argc, char **argv)
for (trial=0; trial<n_frames; trial++) { for (trial=0; trial<n_frames; trial++) {
uint16_t preamble_rx, preamble_energy, N_ZC;
sigma2_dB = 10*log10((double)tx_lev) - SNR; sigma2_dB = 10*log10((double)tx_lev) - SNR;
if (n_frames==1) if (n_frames==1)
...@@ -582,10 +638,8 @@ int main(int argc, char **argv) ...@@ -582,10 +638,8 @@ int main(int argc, char **argv)
sigma2 = pow(10,sigma2_dB/10); sigma2 = pow(10,sigma2_dB/10);
// printf("Sigma2 %f (sigma2_dB %f)\n",sigma2,sigma2_dB); // printf("Sigma2 %f (sigma2_dB %f)\n",sigma2,sigma2_dB);
if (awgn_flag == 0) { if (awgn_flag == 0) {
multipath_tv_channel(UE2gNB,s_re,s_im,r_re,r_im, multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, frame_parms->samples_per_tti<<1, 0);
frame_parms->samples_per_slot<<1,0);
} }
if (n_frames==1) { if (n_frames==1) {
...@@ -594,63 +648,48 @@ int main(int argc, char **argv) ...@@ -594,63 +648,48 @@ int main(int argc, char **argv)
10*log10(tx_lev)); 10*log10(tx_lev));
} }
for (i=0; i<frame_parms->samples_per_subframe; i++) { for (i = 0; i< frame_parms->get_samples_per_slot(subframe,frame_parms); i++) {
for (aa=0; aa<gNB->frame_parms.nb_antennas_rx; aa++) { for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
((short*) &gNB->common_vars.rxdata[aa][rx_prach_start])[2*i] = (short) (.167*(r_re[aa][i] +sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_subframe)])[2*i] = (short) (.167*(r_re[aa][i] +sqrt(sigma2/2)*gaussdouble(0.0,1.0))); ((short*) &gNB->common_vars.rxdata[aa][rx_prach_start])[2*i+1] = (short) (.167*(r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
((short*) &gNB->common_vars.rxdata[aa][subframe*(frame_parms->samples_per_subframe)])[2*i+1] = (short) (.167*(r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
} }
} }
uint16_t preamble_rx;
rx_nr_prach_ru(ru, rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, frame, subframe);
1,
0,
0,
0,
subframe<<1);
gNB->prach_vars.rxsigF = ru->prach_rxsigF; gNB->prach_vars.rxsigF = ru->prach_rxsigF;
rx_nr_prach(gNB, prach_pdu, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay);
nfapi_nr_prach_pdu_t prach_pdu; printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx);
prach_pdu.num_cs = 34;
prach_pdu.prach_format = 1; // A2
rx_nr_prach(gNB, if (preamble_rx != preamble_tx)
&prach_pdu,
0,
subframe<<1,
&preamble_rx,
&preamble_energy,
&preamble_delay);
if (preamble_rx!=preamble_tx)
prach_errors++; prach_errors++;
else { else
delay_avg += (double)preamble_delay; delay_avg += (double)preamble_delay;
}
N_ZC = (prach_sequence_length) ? 139 : 839;
if (n_frames==1) { if (n_frames==1) {
printf("preamble %d (tx %d) : energy %d, delay %d\n",preamble_rx,preamble_tx,preamble_energy,preamble_delay); printf("preamble %d (tx %d) : energy %d, delay %d\n",preamble_rx,preamble_tx,preamble_energy,preamble_delay);
#ifdef NR_PRACH_DEBUG
LOG_M("prach0.m","prach0", &txdata[0][prach_start], samp_count, 1, 1);
LOG_M("prach0.m","prach0", &txdata[0][subframe*frame_parms->samples_per_slot<<1],frame_parms->samples_per_slot<<1,1,1); LOG_M("prachF0.m","prachF0", &gNB->prach_vars.prachF[0], N_ZC, 1, 1);
LOG_M("prachF0.m","prachF0", &gNB->prach_vars.prachF[0],1024,1,1); LOG_M("rxsig0.m","rxs0", &gNB->common_vars.rxdata[0][rx_prach_start], frame_parms->samples_per_subframe, 1, 1);
LOG_M("rxsig0.m","rxs0", //LOG_M("ru_rxsig0.m","rxs0", &ru->common.rxdata[0][rx_prach_start], frame_parms->samples_per_subframe, 1, 1);
&gNB->common_vars.rxdata[0][subframe*frame_parms->samples_per_subframe], LOG_M("rxsigF0.m","rxsF0", gNB->prach_vars.rxsigF[0], N_ZC, 1, 1);
frame_parms->samples_per_subframe,1,1); LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1);
LOG_M("rxsigF0.m","rxsF0", gNB->prach_vars.rxsigF[0],839*4,1,1); LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1);
LOG_M("prach_preamble.m","prachp",&gNB->X_u[0],839,1,1); #endif
} }
} }
printf("SNR %f dB, UE Speed %f km/h: errors %d/%d (delay %f)\n", SNR, ue_speed, prach_errors, n_frames, delay_avg/(double)(n_frames-prach_errors));
printf("SNR %f dB, UE Speed %f km/h: errors %d/%d (delay %f)\n",SNR,ue_speed,prach_errors,n_frames,delay_avg/(double)(n_frames-prach_errors));
//printf("(%f,%f)\n",ue_speed,(double)prach_errors/(double)n_frames); //printf("(%f,%f)\n",ue_speed,(double)prach_errors/(double)n_frames);
} // UE Speed loop } // UE Speed loop
//printf("SNR %f dB, UE Speed %f km/h: errors %d/%d (delay %f)\n",SNR,ue_speed,prach_errors,n_frames,delay_avg/(double)(n_frames-prach_errors)); //printf("SNR %f dB, UE Speed %f km/h: errors %d/%d (delay %f)\n",SNR,ue_speed,prach_errors,n_frames,delay_avg/(double)(n_frames-prach_errors));
// printf("(%f,%f)\n",SNR,(double)prach_errors/(double)n_frames); // printf("(%f,%f)\n",SNR,(double)prach_errors/(double)n_frames);
} //SNR loop } //SNR loop
for (i=0; i<2; i++) { for (i=0; i<2; i++) {
free(s_re[i]); free(s_re[i]);
free(s_im[i]); free(s_im[i]);
...@@ -663,17 +702,5 @@ int main(int argc, char **argv) ...@@ -663,17 +702,5 @@ int main(int argc, char **argv)
free(r_re); free(r_re);
free(r_im); free(r_im);
return(0); return(0);
} }
/*
for (i=1;i<4;i++)
memcpy((void *)&PHY_vars->tx_vars[0].TX_DMA_BUFFER[i*12*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX*2],
(void *)&PHY_vars->tx_vars[0].TX_DMA_BUFFER[0],
12*OFDM_SYMBOL_SIZE_SAMPLES_NO_PREFIX*2);
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment