diff --git a/targets/RT/USER/ru_control.c b/targets/RT/USER/ru_control.c new file mode 100644 index 0000000000000000000000000000000000000000..bc2224cdcd2e120ec1489882444066d6d917be7f --- /dev/null +++ b/targets/RT/USER/ru_control.c @@ -0,0 +1,757 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see <http://www.gnu.org/licenses/>. + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file lte-ru.c + * \brief Top-level threads for RU entity + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <sys/sysinfo.h> +#include "rt_wrapper.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "PHY/types.h" + +#include "PHY/defs_common.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/phy_extern.h" +#include "LAYER2/MAC/mac_extern.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" +#include "SCHED/sched_eNB.h" +#include "PHY/LTE_ESTIMATION/lte_estimation.h" +#include "PHY/INIT/phy_init.h" + +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_extern.h" +#include "PHY_INTERFACE/phy_interface.h" + +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" + +void configure_ru(int idx, + void *arg); + +void configure_rru(int idx, + void *arg); + +int attach_rru(RU_t *ru); + +void fill_rf_config(RU_t *ru, char *rf_config_file); + +void* ru_thread_control( void* param ); + +extern void phy_init_RU(RU_t*); + +extern const char ru_states[6][9]; +const char rru_format_options[4][20] = {"OAI_IF5_only","OAI_IF4p5_only","OAI_IF5_and_IF4p5","MBP_IF5"}; +const char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"}; +const char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"}; + +extern int oai_exit; +extern void wait_eNBs(void); + +int send_tick(RU_t *ru){ + + RRU_CONFIG_msg_t rru_config_msg; + + rru_config_msg.type = RAU_tick; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + + LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d cannot access remote radio\n",ru->idx); + + return 0; +} + +int send_config(RU_t *ru, RRU_CONFIG_msg_t rru_config_msg){ + + + rru_config_msg.type = RRU_config; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + + LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d\n",ru->idx, + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send configuration to remote radio\n",ru->idx); + + return 0; + +} + +int send_capab(RU_t *ru){ + + RRU_CONFIG_msg_t rru_config_msg; + RRU_capabilities_t *cap; + int i=0; + + rru_config_msg.type = RRU_capabilities; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + cap = (RRU_capabilities_t*)&rru_config_msg.msg[0]; + LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", + (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx); + switch (ru->function) { + case NGFI_RRU_IF4p5: + cap->FH_fmt = OAI_IF4p5_only; + break; + case NGFI_RRU_IF5: + cap->FH_fmt = OAI_IF5_only; + break; + case MBP_RRU_IF5: + cap->FH_fmt = MBP_IF5; + break; + default: + AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function); + break; + } + cap->num_bands = ru->num_bands; + for (i=0;i<ru->num_bands;i++) { + LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n", + ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain); + cap->band_list[i] = ru->band[i]; + cap->nb_rx[i] = ru->nb_rx; + cap->nb_tx[i] = ru->nb_tx; + cap->max_pdschReferenceSignalPower[i] = ru->max_pdschReferenceSignalPower; + cap->max_rxgain[i] = ru->max_rxgain; + } + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send capabilities to RAU\n",ru->idx); + + return 0; + +} + +int attach_rru(RU_t *ru) { + + ssize_t msg_len,len; + RRU_CONFIG_msg_t rru_config_msg; + int received_capabilities=0; + + wait_eNBs(); + // Wait for capabilities + while (received_capabilities==0) { + + memset((void*)&rru_config_msg,0,sizeof(rru_config_msg)); + rru_config_msg.type = RAU_tick; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d cannot access remote radio\n",ru->idx); + + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + + // wait for answer with timeout + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RRU %d\n",ru->idx); + } + else if (rru_config_msg.type == RRU_capabilities) { + AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len); + LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx, + (int)rru_config_msg.len,(int)msg_len, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->num_bands, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_rxgain[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_tx[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_rx[0]); + received_capabilities=1; + } + else { + LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx); + } + } + configure_ru(ru->idx, + (RRU_capabilities_t *)&rru_config_msg.msg[0]); + + rru_config_msg.type = RRU_config; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx, + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send configuration to remote radio\n",ru->idx); + + return 0; +} + +int connect_rau(RU_t *ru) { + + RRU_CONFIG_msg_t rru_config_msg; + ssize_t msg_len; + int tick_received = 0; + int configuration_received = 0; + RRU_capabilities_t *cap; + int i; + int len; + + // wait for RAU_tick + while (tick_received == 0) { + + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RAU\n"); + } + else { + if (rru_config_msg.type == RAU_tick) { + LOG_I(PHY,"Tick received from RAU\n"); + tick_received = 1; + } + else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type); + } + } + + // send capabilities + + rru_config_msg.type = RRU_capabilities; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + cap = (RRU_capabilities_t*)&rru_config_msg.msg[0]; + LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", + (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx); + switch (ru->function) { + case NGFI_RRU_IF4p5: + cap->FH_fmt = OAI_IF4p5_only; + break; + case NGFI_RRU_IF5: + cap->FH_fmt = OAI_IF5_only; + break; + case MBP_RRU_IF5: + cap->FH_fmt = MBP_IF5; + break; + default: + AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function); + break; + } + cap->num_bands = ru->num_bands; + for (i=0;i<ru->num_bands;i++) { + LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n", + ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain); + cap->band_list[i] = ru->band[i]; + cap->nb_rx[i] = ru->nb_rx; + cap->nb_tx[i] = ru->nb_tx; + cap->max_pdschReferenceSignalPower[i] = ru->max_pdschReferenceSignalPower; + cap->max_rxgain[i] = ru->max_rxgain; + } + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send capabilities to RAU\n",ru->idx); + + // wait for configuration + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + while (configuration_received == 0) { + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + rru_config_msg.len))<0) { + LOG_I(PHY,"Waiting for configuration from RAU\n"); + } + else { + LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + configure_rru(ru->idx, + (void*)&rru_config_msg.msg[0]); + configuration_received = 1; + } + } + return 0; +} + +int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { + + FH_fmt_options_t fmt = cap->FH_fmt; + + int i; + int found_band=0; + + LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->frame_parms.eutra_band); + for (i=0;i<cap->num_bands;i++) { + LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx); + if (ru->frame_parms.eutra_band == cap->band_list[i]) { + found_band=1; + break; + } + } + + if (found_band == 0) { + LOG_I(PHY,"Couldn't find target EUTRA band %d on RRU %d\n",ru->frame_parms.eutra_band,ru->idx); + return(-1); + } + + switch (ru->if_south) { + case LOCAL_RF: + AssertFatal(1==0, "This RU should not have a local RF, exiting\n"); + return(0); + break; + case REMOTE_IF5: + if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0); + break; + case REMOTE_IF4p5: + if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0); + break; + case REMOTE_MBP_IF5: + if (fmt == MBP_IF5) return(0); + break; + default: + LOG_I(PHY,"No compatible Fronthaul interface found for RRU %d\n", ru->idx); + return(-1); + } + + return(-1); +} + +void configure_ru(int idx, + void *arg) { + + RU_t *ru = RC.ru[idx]; + RRU_config_t *config = (RRU_config_t *)arg; + RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg; + int ret; + + LOG_I(PHY, "Received capabilities from RRU %d\n",idx); + + + if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]); + + AssertFatal((ret=check_capabilities(ru,capabilities)) == 0, + "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret); + // take antenna capabilities of RRU + ru->nb_tx = capabilities->nb_tx[0]; + ru->nb_rx = capabilities->nb_rx[0]; + + // Pass configuration to RRU + LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->frame_parms.eutra_band); + // wait for configuration + config->FH_fmt = ru->if_south; + config->num_bands = 1; + config->band_list[0] = ru->frame_parms.eutra_band; + config->tx_freq[0] = ru->frame_parms.dl_CarrierFreq; + config->rx_freq[0] = ru->frame_parms.ul_CarrierFreq; + config->tdd_config[0] = ru->frame_parms.tdd_config; + config->tdd_config_S[0] = ru->frame_parms.tdd_config_S; + config->att_tx[0] = ru->att_tx; + config->att_rx[0] = ru->att_rx; + config->N_RB_DL[0] = ru->frame_parms.N_RB_DL; + config->N_RB_UL[0] = ru->frame_parms.N_RB_UL; + config->threequarter_fs[0] = ru->frame_parms.threequarter_fs; + if (ru->if_south==REMOTE_IF4p5) { + config->prach_FreqOffset[0] = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset; + config->prach_ConfigIndex[0] = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; + LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0]); + +#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + int i; + for (i=0;i<4;i++) { + config->emtc_prach_CElevel_enable[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]; + config->emtc_prach_FreqOffset[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i]; + config->emtc_prach_ConfigIndex[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i]; + } +#endif + } + + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); +} + +void configure_rru(int idx, + void *arg) { + + RRU_config_t *config = (RRU_config_t *)arg; + RU_t *ru = RC.ru[idx]; + + ru->frame_parms.eutra_band = config->band_list[0]; + ru->frame_parms.dl_CarrierFreq = config->tx_freq[0]; + ru->frame_parms.ul_CarrierFreq = config->rx_freq[0]; + if (ru->frame_parms.dl_CarrierFreq == ru->frame_parms.ul_CarrierFreq) { + ru->frame_parms.frame_type = TDD; + ru->frame_parms.tdd_config = config->tdd_config[0]; + ru->frame_parms.tdd_config_S = config->tdd_config_S[0]; + } + else + ru->frame_parms.frame_type = FDD; + ru->att_tx = config->att_tx[0]; + ru->att_rx = config->att_rx[0]; + ru->frame_parms.N_RB_DL = config->N_RB_DL[0]; + ru->frame_parms.N_RB_UL = config->N_RB_UL[0]; + ru->frame_parms.threequarter_fs = config->threequarter_fs[0]; + ru->frame_parms.pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0]; + if (ru->function==NGFI_RRU_IF4p5) { + ru->frame_parms.att_rx = ru->att_rx; + ru->frame_parms.att_tx = ru->att_tx; + + LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx); + ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0]; + ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; +#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + for (int i=0;i<4;i++) { + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] = config->emtc_prach_CElevel_enable[0][i]; + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i] = config->emtc_prach_FreqOffset[0][i]; + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i] = config->emtc_prach_ConfigIndex[0][i]; + } +#endif + } + + init_frame_parms(&ru->frame_parms,1); + + fill_rf_config(ru,ru->rf_config_file); + + +// phy_init_RU(ru); + +} + + +void* ru_thread_control( void* param ) { + + + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = &ru->proc; + RRU_CONFIG_msg_t rru_config_msg; + ssize_t msg_len; + int len, ret; + + + // Start IF device if any + if (ru->start_if) { + LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx); + AssertFatal( + ru->start_if(ru,NULL) == 0, "Could not start the IF device\n"); + + if (ru->if_south != LOCAL_RF) wait_eNBs(); + } + + + ru->state = (ru->function==eNodeB_3GPP)? RU_RUN : RU_IDLE; + LOG_I(PHY,"Control channel ON for RU %d\n", ru->idx); + + while (!oai_exit) // Change the cond + { + msg_len = sizeof(RRU_CONFIG_msg_t); // TODO : check what should be the msg len + + if (ru->state == RU_IDLE && ru->if_south != LOCAL_RF) + send_tick(ru); + + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_D(PHY,"Waiting msg for RU %d\n", ru->idx); + } + else + { + switch(rru_config_msg.type) + { + case RAU_tick: // RRU + if (ru->if_south != LOCAL_RF){ + LOG_I(PHY,"Received Tick msg...Ignoring\n"); + }else{ + LOG_I(PHY,"Tick received from RAU\n"); + + if (send_capab(ru) == 0) ru->state = RU_CONFIG; + } + break; + + case RRU_capabilities: // RAU + if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_capab msg...Ignoring\n"); + + else{ + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + + AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len); + LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx, + (int)rru_config_msg.len,(int)msg_len, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->num_bands, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_rxgain[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_tx[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_rx[0]); + + configure_ru(ru->idx,(RRU_capabilities_t *)&rru_config_msg.msg[0]); + + // send config + if (send_config(ru,rru_config_msg) == 0) ru->state = RU_CONFIG; + } + + break; + + case RRU_config: // RRU + if (ru->if_south == LOCAL_RF){ + LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + configure_rru(ru->idx, (void*)&rru_config_msg.msg[0]); + + + fill_rf_config(ru,ru->rf_config_file); + init_frame_parms(&ru->frame_parms,1); + ru->frame_parms.nb_antennas_rx = ru->nb_rx; + phy_init_RU(ru); + + //if (ru->is_slave == 1) lte_sync_time_init(&ru->frame_parms); + + if (ru->rfdevice.is_init != 1){ + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + } + + + if (ru->rfdevice.trx_config_func) AssertFatal((ru->rfdevice.trx_config_func(&ru->rfdevice,&ru->openair0_cfg)==0), + "Failed to configure RF device for RU %d\n",ru->idx); + + + + + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + + // send CONFIG_OK + + rru_config_msg.type = RRU_config_ok; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t); + LOG_I(PHY,"Sending CONFIG_OK to RAU %d\n", ru->idx); + + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send CONFIG_OK to RAU\n",ru->idx); + reset_proc(ru); + ru->state = RU_READY; + } else LOG_E(PHY,"Received RRU_config msg...Ignoring\n"); + + break; + + case RRU_config_ok: // RAU + if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_config_ok msg...Ignoring\n"); + else{ + + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + + // Set state to RUN for Master RU, Others on SYNC + ru->state = (ru->is_slave == 1) ? RU_SYNC : RU_RUN ; + ru->in_synch = 0; + + + LOG_I(PHY, "Signaling main thread that RU %d (is_slave %d) is ready in state %s\n",ru->idx,ru->is_slave,ru_states[ru->state]); + pthread_mutex_lock(&RC.ru_mutex); + RC.ru_mask &= ~(1<<ru->idx); + pthread_cond_signal(&RC.ru_cond); + pthread_mutex_unlock(&RC.ru_mutex); + + wait_sync("ru_thread_control"); + + // send start + rru_config_msg.type = RRU_start; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len + + + LOG_I(PHY,"Sending Start to RRU %d\n", ru->idx); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),"Failed to send msg to RU %d\n",ru->idx); + + + pthread_mutex_lock(&proc->mutex_ru); + proc->instance_cnt_ru = 1; + pthread_mutex_unlock(&proc->mutex_ru); + if (pthread_cond_signal(&proc->cond_ru_thread) != 0) { + LOG_E( PHY, "ERROR pthread_cond_signal for RU %d\n",ru->idx); + exit_fun( "ERROR pthread_cond_signal" ); + break; + } + } + break; + + case RRU_start: // RRU + if (ru->if_south == LOCAL_RF){ + LOG_I(PHY,"Start received from RAU\n"); + + if (ru->state == RU_READY){ + + LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); + pthread_mutex_lock(&RC.ru_mutex); + RC.ru_mask &= ~(1<<ru->idx); + pthread_cond_signal(&RC.ru_cond); + pthread_mutex_unlock(&RC.ru_mutex); + + wait_sync("ru_thread_control"); + + ru->state = (ru->is_slave == 1) ? RU_SYNC : RU_RUN ; + ru->cmd = EMPTY; + pthread_mutex_lock(&proc->mutex_ru); + proc->instance_cnt_ru = 1; + pthread_mutex_unlock(&proc->mutex_ru); + if (pthread_cond_signal(&proc->cond_ru_thread) != 0) { + LOG_E( PHY, "ERROR pthread_cond_signal for RU %d\n",ru->idx); + exit_fun( "ERROR pthread_cond_signal" ); + break; + } + } + else LOG_E(PHY,"RRU not ready, cannot start\n"); + + } else LOG_E(PHY,"Received RRU_start msg...Ignoring\n"); + + + break; + + case RRU_sync_ok: //RAU + if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_config_ok msg...Ignoring\n"); + else{ + if (ru->is_slave == 1){ + LOG_I(PHY,"Received RRU_sync_ok from RRU %d\n",ru->idx); + // Just change the state of the RRU to unblock ru_thread() + ru->state = RU_RUN; + }else LOG_E(PHY,"Received RRU_sync_ok from a master RRU...Ignoring\n"); + } + break; + case RRU_frame_resynch: //RRU + if (ru->if_south != LOCAL_RF) LOG_E(PHY,"Received RRU frame resynch message, should not happen in RAU\n"); + else { + LOG_I(PHY,"Received RRU_frame_resynch command\n"); + ru->cmd = RU_FRAME_RESYNCH; + ru->cmdval = ((uint16_t*)&rru_config_msg.msg[0])[0]; + LOG_I(PHY,"Received Frame Resynch messaage with value %d\n",ru->cmdval); + } + break; + + case RRU_stop: // RRU + if (ru->if_south == LOCAL_RF){ + LOG_I(PHY,"Stop received from RAU\n"); + + if (ru->state == RU_RUN || ru->state == RU_ERROR){ + + LOG_I(PHY,"Stopping RRU\n"); + ru->state = RU_READY; + // TODO: stop ru_thread + }else{ + LOG_I(PHY,"RRU not running, can't stop\n"); + } + }else LOG_E(PHY,"Received RRU_stop msg...Ignoring\n"); + + break; + + default: + if (ru->if_south != LOCAL_RF){ + if (ru->state == RU_IDLE){ + // Keep sending TICK + send_tick(ru); + } + } + + break; + } // switch + } //else + + + }//while + return(NULL); +}