Commit d2190230 authored by Florian Kaltenberger's avatar Florian Kaltenberger

first version of RX timed read. to be tested

parent 27266ddc
...@@ -625,55 +625,68 @@ void *emulatedRF_thread(void *param) { ...@@ -625,55 +625,68 @@ void *emulatedRF_thread(void *param) {
void rx_rf(RU_t *ru,int *frame,int *slot) { void rx_rf(RU_t *ru,int *frame,int *slot) {
RU_proc_t *proc = &ru->proc; RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
void *rxp[ru->nb_rx]; void *rxp[ru->nb_rx];
unsigned int rxs; unsigned int rxs, siglen;
int i; int i;
uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp);
openair0_timestamp ts,old_ts;
AssertFatal(*slot<fp->slots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); AssertFatal(*slot<fp->slots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
for (i=0; i<ru->nb_rx; i++) for (i=0; i<ru->nb_rx; i++)
rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
old_ts = proc->timestamp_rx;
LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]); LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]);
if(emulate_rf) { if (proc->first_rx==1) {
wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); proc->timestamp_rx = 0;
release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); proc->first_rx = 0;
rxs = samples_per_slot;
ts = old_ts + rxs;
} else {
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
&ts,
rxp,
samples_per_slot,
ru->nb_rx);
} }
int slot_type = nr_slot_select(cfg,*frame,*slot%fp->slots_per_frame);
if (slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT || IS_SOFTMODEM_RFSIM) {
if (slot_type == NR_MIXED_SLOT) {
uint16_t rxsymb = 0;
for(uint16_t symbol_count =0;symbol_count<fp->symbols_per_slot;symbol_count++) {
if (cfg->tdd_table.max_tdd_periodicity_list[*slot].max_num_of_symbol_per_slot_list[symbol_count].slot_config.value==1)
rxsymb++;
}
AssertFatal(rxsymb>0,"illegal rxsymb %d\n",rxsymb);
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (rxsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
}
else {
siglen = samples_per_slot;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); if(emulate_rf) {
proc->timestamp_rx = ts-ru->ts_offset; wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
rxs = siglen;
}
else {
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
proc->timestamp_rx,
rxp,
siglen,
ru->nb_rx);
}
//AssertFatal(rxs == fp->samples_per_subframe, //AssertFatal(rxs == siglen,"rx_rf: Asked for %d samples, got %d from USRP\n",siglen,rxs);
//"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs); if (rxs != siglen) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",siglen,rxs);
if (rxs != samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",samples_per_slot,rxs);
if (proc->first_rx == 1) {
ru->ts_offset = proc->timestamp_rx;
proc->timestamp_rx = 0;
} else {
if (proc->timestamp_rx - old_ts != fp->get_samples_per_slot((*slot-1)%fp->slots_per_frame,fp)) {
LOG_D(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - samples_per_slot,ru->ts_offset);
ru->ts_offset += (proc->timestamp_rx - old_ts - samples_per_slot);
proc->timestamp_rx = ts-ru->ts_offset;
}
} }
proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
uint32_t idx_sf = proc->timestamp_rx / fp->samples_per_subframe;
proc->tti_rx = (idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); //we always advance the timestamp by samples_per_slot, even if we have not read the (full) slot. This is to keep the timestamp updated even when there is no RX.
proc->timestamp_rx += samples_per_slot;
proc->frame_rx = *frame;
proc->tti_rx = *slot;
// synchronize first reception to frame 0 subframe 0 // synchronize first reception to frame 0 subframe 0
LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n", LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n",
ru->idx, ru->idx,
...@@ -687,29 +700,9 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { ...@@ -687,29 +700,9 @@ void rx_rf(RU_t *ru,int *frame,int *slot) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
} }
if (proc->first_rx == 0) {
if (proc->tti_rx != *slot) {
LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot);
exit_fun("Exiting");
}
if (proc->frame_rx != *frame) {
LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame);
exit_fun("Exiting");
}
} else {
proc->first_rx = 0;
*frame = proc->frame_rx;
*slot = proc->tti_rx;
}
//printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe); //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
if (rxs != samples_per_slot) {
//exit_fun( "problem receiving samples" );
LOG_E(PHY, "problem receiving samples\n");
}
} }
...@@ -735,7 +728,7 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { ...@@ -735,7 +728,7 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) {
if(slot_type == NR_MIXED_SLOT) { if(slot_type == NR_MIXED_SLOT) {
txsymb = 0; txsymb = 0;
for(int symbol_count =0;symbol_count<NR_NUMBER_OF_SYMBOLS_PER_SLOT;symbol_count++) { for(int symbol_count =0;symbol_count<fp->symbols_per_slot;symbol_count++) {
if (cfg->tdd_table.max_tdd_periodicity_list[slot].max_num_of_symbol_per_slot_list[symbol_count].slot_config.value==0) if (cfg->tdd_table.max_tdd_periodicity_list[slot].max_num_of_symbol_per_slot_list[symbol_count].slot_config.value==0)
txsymb++; txsymb++;
} }
...@@ -920,6 +913,7 @@ int wakeup_synch(RU_t *ru) { ...@@ -920,6 +913,7 @@ int wakeup_synch(RU_t *ru) {
return(0); return(0);
} }
/*
void do_ru_synch(RU_t *ru) { void do_ru_synch(RU_t *ru) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
RU_proc_t *proc = &ru->proc; RU_proc_t *proc = &ru->proc;
...@@ -991,7 +985,7 @@ void do_ru_synch(RU_t *ru) { ...@@ -991,7 +985,7 @@ void do_ru_synch(RU_t *ru) {
ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0); ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
} }
*/
void wakeup_gNB_L1s(RU_t *ru) { void wakeup_gNB_L1s(RU_t *ru) {
...@@ -1480,7 +1474,7 @@ void *ru_thread( void *param ) { ...@@ -1480,7 +1474,7 @@ void *ru_thread( void *param ) {
} else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx); } else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx);
// if this is a slave RRU, try to synchronize on the DL frequency // if this is a slave RRU, try to synchronize on the DL frequency
if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru); //if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru);
} }
pthread_mutex_lock(&proc->mutex_FH1); pthread_mutex_lock(&proc->mutex_FH1);
......
...@@ -355,7 +355,7 @@ struct openair0_device_t { ...@@ -355,7 +355,7 @@ struct openair0_device_t {
* \param antenna_id Index of antenna for which to receive samples * \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read * \returns the number of sample read
*/ */
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id); int (*trx_read_func)(openair0_device *device, openair0_timestamp ptimestamp, void **buff, int nsamps,int antenna_id);
/*! \brief print the device statistics /*! \brief print the device statistics
* \param device the hardware to use * \param device the hardware to use
......
...@@ -106,6 +106,7 @@ typedef struct { ...@@ -106,6 +106,7 @@ typedef struct {
int wait_for_first_pps; int wait_for_first_pps;
int use_gps; int use_gps;
int first_tx; int first_tx;
int first_rx;
//! timestamp of RX packet //! timestamp of RX packet
openair0_timestamp rx_timestamp; openair0_timestamp rx_timestamp;
uint32_t recplay_mode; uint32_t recplay_mode;
...@@ -284,7 +285,7 @@ static int trx_usrp_start(openair0_device *device) { ...@@ -284,7 +285,7 @@ static int trx_usrp_start(openair0_device *device) {
// set pin 5 (Shutdown LNA) to 1 when the radio is transmitting and receiveing (ATR_XX) // set pin 5 (Shutdown LNA) to 1 when the radio is transmitting and receiveing (ATR_XX)
// (we use full duplex here, because our RX is on all the time - this might need to change later) // (we use full duplex here, because our RX is on all the time - this might need to change later)
s->usrp->set_gpio_attr("FP0", "ATR_XX", (1<<5), 0x7f); s->usrp->set_gpio_attr("FP0", "ATR_XX", (1<<5), 0x7f);
// set the output pins to 0 // set the output pins to 1
s->usrp->set_gpio_attr("FP0", "OUT", 7<<7, 0xf80); s->usrp->set_gpio_attr("FP0", "OUT", 7<<7, 0xf80);
// init recv and send streaming // init recv and send streaming
...@@ -526,7 +527,7 @@ static int trx_usrp_write(openair0_device *device, ...@@ -526,7 +527,7 @@ static int trx_usrp_write(openair0_device *device,
* \param antenna_id Index of antenna for which to receive samples * \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read * \returns the number of sample read
*/ */
static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp ptimestamp, void **buff, int nsamps, int cc) {
int samples_received=0; int samples_received=0;
static unsigned int cur_samples; static unsigned int cur_samples;
static int64_t wrap_count; static int64_t wrap_count;
...@@ -555,11 +556,11 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt ...@@ -555,11 +556,11 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt
if (s->recplay_state->use_mmap) { if (s->recplay_state->use_mmap) {
if (cur_samples < s->recplay_state->nb_samples) { if (cur_samples < s->recplay_state->nb_samples) {
*ptimestamp = (s->recplay_state->ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts; //*ptimestamp = (s->recplay_state->ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts;
if (cur_samples == 0) { if (cur_samples == 0) {
std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts
<< " ts=" << *ptimestamp << std::endl; << " ts=" << ptimestamp << std::endl;
} }
memcpy(buff[0], &s->recplay_state->ms_sample[cur_samples].samples[0], nsamps*4); memcpy(buff[0], &s->recplay_state->ms_sample[cur_samples].samples[0], nsamps*4);
...@@ -583,11 +584,11 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt ...@@ -583,11 +584,11 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt
ts0 = s->recplay_state->ms_sample->ts; ts0 = s->recplay_state->ms_sample->ts;
} }
*ptimestamp = ts0 + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)) + wrap_ts; //*ptimestamp = ts0 + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)) + wrap_ts;
if (cur_samples == 0) { if (cur_samples == 0) {
std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts
<< " ts=" << *ptimestamp << std::endl; << " ts=" << ptimestamp << std::endl;
} }
memcpy(buff[0], &s->recplay_state->ms_sample->samples[0], nsamps*4); memcpy(buff[0], &s->recplay_state->ms_sample->samples[0], nsamps*4);
...@@ -626,7 +627,7 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt ...@@ -626,7 +627,7 @@ static int trx_usrp_read_recplay(openair0_device *device, openair0_timestamp *pt
* \param antenna_id Index of antenna for which to receive samples * \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read * \returns the number of sample read
*/ */
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { static int trx_usrp_read(openair0_device *device, openair0_timestamp ptimestamp, void **buff, int nsamps, int cc) {
usrp_state_t *s = (usrp_state_t *)device->priv; usrp_state_t *s = (usrp_state_t *)device->priv;
int samples_received=0; int samples_received=0;
int nsamps2; // aligned to upper 32 or 16 byte boundary int nsamps2; // aligned to upper 32 or 16 byte boundary
...@@ -643,7 +644,16 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp ...@@ -643,7 +644,16 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
int16x8_t buff_tmp[2][nsamps2]; int16x8_t buff_tmp[2][nsamps2];
#endif #endif
if (device->type == USRP_B200_DEV) { if (ptimestamp==0)
s->usrp->set_time_now(uhd::time_spec_t(0.0));
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = nsamps;
stream_cmd.stream_now = false;
stream_cmd.time_spec = uhd::time_spec_t(ptimestamp,s->sample_rate);
s->rx_stream->issue_stream_cmd(stream_cmd);
if (cc>1) { if (cc>1) {
// receive multiple channels (e.g. RF A and RF B) // receive multiple channels (e.g. RF A and RF B)
std::vector<void *> buff_ptrs; std::vector<void *> buff_ptrs;
...@@ -692,19 +702,6 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp ...@@ -692,19 +702,6 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
#endif #endif
} }
} }
} else if (device->type == USRP_X300_DEV) {
if (cc>1) {
// receive multiple channels (e.g. RF A and RF B)
std::vector<void *> buff_ptrs;
for (int i=0; i<cc; i++) buff_ptrs.push_back(buff[i]);
samples_received = s->rx_stream->recv(buff_ptrs, nsamps, s->rx_md,1.0);
} else {
// receive a single channel (e.g. from connector RF A)
samples_received = s->rx_stream->recv(buff[0], nsamps, s->rx_md,1.0);
}
}
if (samples_received < nsamps) if (samples_received < nsamps)
LOG_E(HW,"[recv] received %d samples out of %d\n",samples_received,nsamps); LOG_E(HW,"[recv] received %d samples out of %d\n",samples_received,nsamps);
...@@ -714,13 +711,12 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp ...@@ -714,13 +711,12 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
s->rx_count += nsamps; s->rx_count += nsamps;
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
*ptimestamp = s->rx_timestamp;
if (s->recplay_mode == RECPLAY_RECORDMODE) { // record mode if (s->recplay_mode == RECPLAY_RECORDMODE) { // record mode
// Copy subframes to memory (later dump on a file) // Copy subframes to memory (later dump on a file)
if (s->recplay_state->nb_samples < s->recplay_state->u_sf_max) { if (s->recplay_state->nb_samples < s->recplay_state->u_sf_max) {
(s->recplay_state->ms_sample+s->recplay_state->nb_samples)->header = BELL_LABS_IQ_HEADER; (s->recplay_state->ms_sample+s->recplay_state->nb_samples)->header = BELL_LABS_IQ_HEADER;
(s->recplay_state->ms_sample+s->recplay_state->nb_samples)->ts = *ptimestamp; (s->recplay_state->ms_sample+s->recplay_state->nb_samples)->ts = ptimestamp;
memcpy((s->recplay_state->ms_sample+s->recplay_state->nb_samples)->samples, buff[0], nsamps*4); memcpy((s->recplay_state->ms_sample+s->recplay_state->nb_samples)->samples, buff[0], nsamps*4);
s->recplay_state->nb_samples++; s->recplay_state->nb_samples++;
} else exit_function(__FILE__, __FUNCTION__, __LINE__,"Recording reaches max iq limit\n"); } else exit_function(__FILE__, __FUNCTION__, __LINE__,"Recording reaches max iq limit\n");
......
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