Send PRACH from worker thread with zero time advance

master
Ismael Gomez 7 years ago
parent e446c14214
commit ab7a0842ba

@ -53,6 +53,7 @@ public:
cf_t* get_buffer(uint32_t antenna_idx); cf_t* get_buffer(uint32_t antenna_idx);
void set_tti(uint32_t tti, uint32_t tx_tti); void set_tti(uint32_t tti, uint32_t tx_tti);
void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
void set_prach(cf_t *prach_ptr, float prach_power);
void set_cfo(float cfo); void set_cfo(float cfo);
void set_ul_params(bool pregen_disabled = false); void set_ul_params(bool pregen_disabled = false);
@ -169,6 +170,8 @@ private:
bool sr_configured; bool sr_configured;
float cfo; float cfo;
bool rar_cqi_request; bool rar_cqi_request;
cf_t *prach_ptr;
float prach_power;
uint32_t rssi_read_cnt; uint32_t rssi_read_cnt;

@ -58,14 +58,12 @@ namespace srsue {
bool is_ready_to_send(uint32_t current_tti); bool is_ready_to_send(uint32_t current_tti);
bool is_pending(); bool is_pending();
int tx_tti(); int tx_tti();
cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL);
void send(srslte::radio* radio_handler, float cfo, float pathloss, srslte_timestamp_t rx_time);
float get_p0_preamble();
static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission
private: private:
const static int MAX_LEN_SF = 3;
LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config; LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config;
phy_args_t *args; phy_args_t *args;

@ -367,6 +367,11 @@ void phch_recv::run_thread()
dummy_buffer[i] = (cf_t*) malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); dummy_buffer[i] = (cf_t*) malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
} }
uint32_t prach_nof_sf = 0;
uint32_t prach_sf_cnt = 0;
cf_t *prach_ptr = NULL;
float prach_power = 0;
while (running) while (running)
{ {
Debug("SYNC: state=%s\n", phy_state.to_string()); Debug("SYNC: state=%s\n", phy_state.to_string());
@ -423,40 +428,46 @@ void phch_recv::run_thread()
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
worker->set_cfo(get_tx_cfo());
worker_com->set_sync_metrics(metrics); worker_com->set_sync_metrics(metrics);
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
prach_ptr = prach_buffer->generate(get_tx_cfo(), &prach_nof_sf, &prach_power);
if (!prach_ptr) {
Error("Generating PRACH\n");
}
}
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_t rx_time, tx_time, tx_time_prach; srslte_timestamp_t rx_time, tx_time;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_copy(&tx_time, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time);
if (prach_ptr) {
srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3);
} else {
srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3 - time_adv_sec); srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3 - time_adv_sec);
worker->set_tx_time(tx_time, next_offset); }
next_offset = 0;
Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power);
worker->set_cfo(get_tx_cfo());
worker->set_tti(tti, tx_mutex_cnt); worker->set_tti(tti, tx_mutex_cnt);
worker->set_tx_time(tx_time, next_offset);
next_offset = 0;
tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex;
// Reset Uplink TX buffer to avoid mixing packets in TX queue // Advance/reset prach subframe pointer
/* if (prach_ptr) {
if (prach_buffer->is_pending()) { prach_sf_cnt++;
Info("SYNC: PRACH pending: Reset UL\n"); if (prach_sf_cnt == prach_nof_sf) {
radio_h->tx_end(); prach_sf_cnt = 0;
}*/ prach_ptr = NULL;
}
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_copy(&tx_time_prach, &rx_time);
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3);
prach_buffer->send(radio_h, get_tx_cfo(), worker_com->pathloss, tx_time_prach);
radio_h->tx_end();
worker_com->p0_preamble = prach_buffer->get_p0_preamble();
worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble);
} }
// Start worker
workers_pool->start_worker(worker); workers_pool->start_worker(worker);
// Save signal for Intra-frequency measurement
if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) {
srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]);
} }

@ -186,6 +186,11 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_)
log_phy_lib_h->step(tti); log_phy_lib_h->step(tti);
} }
void phch_worker::set_prach(cf_t *prach_ptr, float prach_power) {
this->prach_ptr = prach_ptr;
this->prach_power = prach_power;
}
void phch_worker::set_cfo(float cfo_) void phch_worker::set_cfo(float cfo_)
{ {
cfo = cfo_; cfo = cfo_;
@ -320,6 +325,14 @@ void phch_worker::work_imp()
/***** Uplink Processing + Transmission *******/ /***** Uplink Processing + Transmission *******/
bool signal_ready = false;
cf_t *signal_ptr = NULL;
/* Transmit PRACH if pending, or PUSCH/PUCCH otherwise */
if (prach_ptr) {
signal_ready = true;
signal_ptr = prach_ptr;
} else {
/* Generate SR if required*/ /* Generate SR if required*/
set_uci_sr(); set_uci_sr();
@ -350,7 +363,6 @@ void phch_worker::work_imp()
srslte_ue_ul_set_cfo(&ue_ul, cfo); srslte_ue_ul_set_cfo(&ue_ul, cfo);
/* Transmit PUSCH, PUCCH or SRS */ /* Transmit PUSCH, PUCCH or SRS */
bool signal_ready = false;
if (ul_action.tx_enabled) { if (ul_action.tx_enabled) {
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
@ -366,13 +378,16 @@ void phch_worker::work_imp()
encode_srs(); encode_srs();
signal_ready = true; signal_ready = true;
} }
signal_ptr = signal_buffer[0];
}
tr_log_end(); tr_log_end();
if (next_offset > 0) { if (next_offset > 0) {
phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
} else { } else {
phy->worker_end(tx_tti, signal_ready, &signal_buffer[0][-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
} }
if (!dl_action.generate_ack_callback) { if (!dl_action.generate_ack_callback) {

@ -341,6 +341,7 @@ void phy::reset()
{ {
Info("Resetting PHY\n"); Info("Resetting PHY\n");
n_ta = 0; n_ta = 0;
sf_recv.set_time_adv_sec(0);
pdcch_dl_search_reset(); pdcch_dl_search_reset();
for(uint32_t i=0;i<nof_workers;i++) { for(uint32_t i=0;i<nof_workers;i++) {
workers[i].reset(); workers[i].reset();

@ -75,7 +75,7 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb,
return; return;
} }
srslte_cfo_set_tol(&cfo_h, 0); srslte_cfo_set_tol(&cfo_h, 0);
signal_buffer = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t)); signal_buffer = (cf_t *) srslte_vec_malloc(MAX_LEN_SF * 30720 * sizeof(cf_t));
if (!signal_buffer) { if (!signal_buffer) {
perror("malloc"); perror("malloc");
return; return;
@ -159,10 +159,10 @@ bool prach::is_pending() {
bool prach::is_ready_to_send(uint32_t current_tti_) { bool prach::is_ready_to_send(uint32_t current_tti_) {
if (is_pending()) { if (is_pending()) {
// consider the number of subframes the transmission must be anticipated // consider the number of subframes the transmission must be anticipated
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240; uint32_t tti_tx = TTI_TX(current_tti_);
if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) { if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) {
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_); Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", tti_tx, current_tti_);
transmitted_tti = current_tti; transmitted_tti = tti_tx;
return true; return true;
} }
} }
@ -173,55 +173,31 @@ int prach::tx_tti() {
return transmitted_tti; return transmitted_tti;
} }
float prach::get_p0_preamble() cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) {
{
return target_power_dbm;
}
void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time) if (cell_initiated && preamble_idx >= 0 && nof_sf) {
{
// Get current TX gain
float old_gain = radio_handler->get_tx_gain();
// Correct CFO before transmission FIXME: UL SISO Only // Correct CFO before transmission FIXME: UL SISO Only
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
// If power control is enabled, choose amplitude and power // pad guard symbols with zeros
if (args->ul_pwr_ctrl_en) { uint32_t nsf = (len-1)/SRSLTE_SF_LEN_PRB(cell.nof_prb)+1;
// Get PRACH transmission power bzero(&signal_buffer[len], (nsf*SRSLTE_SF_LEN_PRB(cell.nof_prb)-len)*sizeof(cf_t));
float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm);
// Get output power for amplitude 1
radio_handler->set_tx_power(tx_power);
// Scale signal *nof_sf = nsf;
float digital_power = srslte_vec_avg_power_cf(signal_buffer, len);
float scale = sqrtf(pow(10,tx_power/10)/digital_power);
srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len); if (target_power) {
log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB, scale %.2f\n", *target_power = target_power_dbm;
pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale);
} else {
float prach_gain = args->prach_gain;
if (prach_gain > 0) {
radio_handler->set_tx_gain(prach_gain);
}
Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain);
} }
void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL}; Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n",
radio_handler->tx(tmp_buffer, len, tx_time); preamble_idx, cfo*15, nsf, target_power_dbm);
radio_handler->tx_end();
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n",
preamble_idx, cfo*15, tx_time.frac_secs);
preamble_idx = -1; preamble_idx = -1;
radio_handler->set_tx_gain(old_gain); return signal_buffer;
Debug("Restoring TX gain to %.0f dB\n", old_gain); } else {
return NULL;
}
} }
} // namespace srsue } // namespace srsue

Loading…
Cancel
Save