diff --git a/CMakeLists.txt b/CMakeLists.txt index de4ae15ab8..5854dae3d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1384,9 +1384,11 @@ set (MAC_NR_SRC_UE ${NR_UE_PHY_INTERFACE_DIR}/NR_IF_Module.c ${NR_UE_PHY_INTERFACE_DIR}/NR_Packet_Drop.c ${NR_UE_MAC_DIR}/config_ue.c + ${NR_UE_MAC_DIR}/config_ue_sl.c ${NR_UE_MAC_DIR}/mac_vars.c ${NR_UE_MAC_DIR}/main_ue_nr.c ${NR_UE_MAC_DIR}/nr_ue_procedures.c + ${NR_UE_MAC_DIR}/nr_ue_procedures_sl.c ${NR_UE_MAC_DIR}/nr_ue_scheduler.c ${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c ${NR_UE_MAC_DIR}/nr_ra_procedures.c diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 347b74900b..a1490c104f 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -987,6 +987,8 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf init_nsa_message(rrc_inst, reconfig_file, rbconfig_file); nr_rlc_activate_srb0(mac_inst->crnti, NULL, send_srb0_rrc); } + //TODO: Move this call to RRC + start_sidelink((&rrc_inst[i])->ue_id); } } diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index b856bf252c..5215f8540b 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -106,11 +106,9 @@ extern "C" #define CONFIG_L1_EMULATOR "Run in L1 emulated mode (disable PHY layer)\n" #define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n" #define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence" -#define CONFIG_HLP_SYNC_REF "Sync Reference in Sidelink\n" -#define CONFIG_HLP_NID1 "Set NID1 value in Sidelink\n" -#define CONFIG_HLP_NID2 "Set NID2 value in Sidelink\n" #define CONFIG_HLP_NOITTI "Do not start itti threads, call queue processing in place, inside the caller thread" #define CONFIG_HLP_LDPC_OFFLOAD "Enable LDPC offload to AMD Xilinx T2 telco card\n" +#define CONFIG_HLP_SYNC_REF "UE acts a Sync Reference in Sidelink. 0-none 1-GNB 2-GNSS 4-localtiming\n" /*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters common to eNodeB and UE */ @@ -143,8 +141,6 @@ extern "C" #define EMULATE_L1 softmodem_params.emulate_l1 #define CONTINUOUS_TX softmodem_params.continuous_tx #define SYNC_REF softmodem_params.sync_ref -#define NID1 softmodem_params.nid1 -#define NID2 softmodem_params.nid2 #define LDPC_OFFLOAD_FLAG softmodem_params.ldpc_offload_flag #define REORDER_THREAD_DISABLE softmodem_params.reorder_thread_disable @@ -191,10 +187,9 @@ extern int usrp_tx_thread; {"emulate-l1", CONFIG_L1_EMULATOR, PARAMFLAG_BOOL, .iptr=&EMULATE_L1, .defintval=0, TYPE_INT, 0}, \ {"continuous-tx", CONFIG_HLP_CONTINUOUS_TX, PARAMFLAG_BOOL, .iptr=&CONTINUOUS_TX, .defintval=0, TYPE_INT, 0}, \ {"disable-stats", CONFIG_HLP_STATS_DISABLE, PARAMFLAG_BOOL, .iptr=&stats_disabled, .defintval=0, TYPE_INT, 0}, \ - {"nid1", CONFIG_HLP_NID1, 0, .iptr=&NID1, .defintval=10, TYPE_INT, 0}, \ - {"nid2", CONFIG_HLP_NID2, 0, .iptr=&NID2, .defintval=1, TYPE_INT, 0}, \ {"no-itti-threads", CONFIG_HLP_NOITTI, PARAMFLAG_BOOL, .iptr=&softmodem_params.no_itti, .defintval=0, TYPE_INT, 0}, \ {"ldpc-offload-enable", CONFIG_HLP_LDPC_OFFLOAD, PARAMFLAG_BOOL, .iptr=&LDPC_OFFLOAD_FLAG, .defstrval=0, TYPE_INT, 0}, \ + {"sync-ref", CONFIG_HLP_SYNC_REF, 0, .uptr=&SYNC_REF, .defintval=0, TYPE_UINT, 0}, \ } // clang-format on @@ -353,9 +348,7 @@ typedef struct { int non_stop; int emulate_l1; int continuous_tx; - int sync_ref; - int nid1; - int nid2; + uint32_t sync_ref; int no_itti; int ldpc_offload_flag; } softmodem_params_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h index c567b329db..7ff96637b0 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h @@ -351,7 +351,7 @@ typedef struct uint16_t sl_bandwidth; //Absolute frequency of SL point A in KHz //n38 (2570-2620 Mhz), n47 (5855-5925 Mhz) are defined. - uint32_t sl_frequency; + uint64_t sl_frequency; //Only 1 SCS-SpecificCarrier allowed for NR-SL communication uint16_t sl_grid_size;// bandwidth for each numerology @@ -363,7 +363,7 @@ typedef struct uint8_t sl_frequency_shift_7p5khz; //Indicates presence of +/-5Khz shift wrt FREF for V2X reference frequencies. //Possible values: {-1,0,1} - uint8_t sl_value_N; + int8_t sl_value_N; } sl_nr_carrier_config_t; diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index 01dd1e3707..661f219240 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -57,4 +57,5 @@ MESSAGE_DEF(RRC_MAC_DRX_CONFIG_REQ, MESSAGE_PRIORITY_MED, rrc_mac_drx_config_req // gNB MESSAGE_DEF(NR_RRC_MAC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacCcchDataInd, nr_rrc_mac_ccch_data_ind) MESSAGE_DEF(NR_RRC_MAC_BCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacBcchDataInd, nr_rrc_mac_bcch_data_ind) +MESSAGE_DEF(NR_RRC_MAC_SBCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacSBcchDataInd, nr_rrc_mac_sbcch_data_ind) diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index ea2e5feed3..9a6817a41c 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -41,6 +41,7 @@ #define RRC_MAC_BCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_data_req #define RRC_MAC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_data_ind #define NR_RRC_MAC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_bcch_data_ind +#define NR_RRC_MAC_SBCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_sbcch_data_ind #define RRC_MAC_BCCH_MBMS_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_req #define RRC_MAC_BCCH_MBMS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_ind @@ -119,6 +120,17 @@ typedef struct NRRrcMacBcchDataInd_s { uint8_t rsrp; } NRRrcMacBcchDataInd; +typedef struct NRRrcMacSBcchDataInd_s { + uint32_t frame; + uint8_t slot; + uint32_t sdu_size; + uint8_t sdu[BCCH_SDU_SIZE]; + uint8_t gnb_index; + uint16_t rx_slss_id; + uint8_t rsrq; + uint8_t rsrp; +} NRRrcMacSBcchDataInd; + typedef struct RrcMacBcchMbmsDataReq_s { uint32_t frame; uint32_t sdu_size; diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c b/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c new file mode 100644 index 0000000000..ed5abb5846 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c @@ -0,0 +1,533 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" +#include "NR_SidelinkPreconfigNR-r16.h" +#include "mac_proto.h" + +void sl_ue_mac_free(uint8_t module_id) +{ + + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + + sl_nr_phy_config_request_t *sl_config = + &mac->SL_MAC_PARAMS->sl_phy_config.sl_config_req; + + uint8_t syncsource = sl_config->sl_sync_source.sync_source; + + //Allocated by MAC only in case of SYNC_REF_UE + //else it is freed as part of RRC pre-config structure + if (syncsource == SL_SYNC_SOURCE_SYNC_REF_UE) { + ASN_STRUCT_FREE (asn_DEF_NR_TDD_UL_DL_Pattern, mac->SL_MAC_PARAMS->sl_TDD_config); + } + + fapi_nr_max_tdd_periodicity_t *tdd_list = + sl_config->tdd_table.max_tdd_periodicity_list; + + // @todo: maybe this should be done by phy + if (tdd_list) { + int mu = sl_config->sl_bwp_config.sl_scs; + int nb_slots_to_set = TDD_CONFIG_NB_FRAMES*(1<tdd_table.max_tdd_periodicity_list); + } + + for (int i=0;iSL_MAC_PARAMS->sl_RxPool[i]); + } + for (int i=0;iSL_MAC_PARAMS->sl_TxPool[i]); + } + + free_and_zero(mac->SL_MAC_PARAMS); +} + +void sl_set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, + int mu, + NR_TDD_UL_DL_Pattern_t *pattern) +{ + const int nrofUplinkSlots = pattern->nrofUplinkSlots; + const int nrofUplinkSymbols = pattern->nrofUplinkSymbols; + const int nb_periods_per_frame = get_nb_periods_per_frame(pattern->dl_UL_TransmissionPeriodicity); + const int nb_slots_per_period = ((1 << mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME) / nb_periods_per_frame; + tdd_table->tdd_period_in_slots = nb_slots_per_period; + + LOG_I(PHY,"UL slots:%d, symbols:%d, slots_per_period:%d\n", + nrofUplinkSlots, nrofUplinkSymbols, nb_slots_per_period); + + tdd_table->max_tdd_periodicity_list = (fapi_nr_max_tdd_periodicity_t *) malloc(nb_slots_per_period * sizeof(fapi_nr_max_tdd_periodicity_t)); + + for(int memory_alloc = 0 ; memory_alloc < nb_slots_per_period; memory_alloc++) + tdd_table->max_tdd_periodicity_list[memory_alloc].max_num_of_symbol_per_slot_list = + (fapi_nr_max_num_of_symbol_per_slot_t *) malloc(NR_NUMBER_OF_SYMBOLS_PER_SLOT*sizeof(fapi_nr_max_num_of_symbol_per_slot_t)); + + int slot_number = (nb_slots_per_period - nrofUplinkSlots) - (nrofUplinkSymbols ? 1 : 0); + if (nrofUplinkSymbols != 0) { + for(int number_of_symbol = NR_NUMBER_OF_SYMBOLS_PER_SLOT - nrofUplinkSymbols; number_of_symbol < NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) { + tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config = 1; + } + slot_number++; + } + while(slot_number < nb_slots_per_period) { + for (int number_of_symbol = 0; number_of_symbol < nrofUplinkSlots * NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) { + tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol%NR_NUMBER_OF_SYMBOLS_PER_SLOT].slot_config = 1; + if((number_of_symbol + 1) % NR_NUMBER_OF_SYMBOLS_PER_SLOT == 0) + slot_number++; + } + } +} + +//Prepares the PHY config to be sent to PHY. Prepares from the Valus from MAC context. +static void sl_prepare_phy_config(int module_id, + sl_nr_phy_config_request_t *phycfg, + NR_SL_FreqConfigCommon_r16_t *freqcfg, + uint8_t sync_source, + uint32_t sl_OffsetDFN, + NR_TDD_UL_DL_ConfigCommon_t *sl_TDD_config) +{ + + + phycfg->sl_sync_source.sync_source = sync_source; + LOG_I(NR_MAC, "Sidelink CFG: sync source:%d\n", phycfg->sl_sync_source.sync_source); + + uint32_t pointA_ARFCN = freqcfg->sl_AbsoluteFrequencyPointA_r16; + AssertFatal(pointA_ARFCN, "sl_AbsoluteFrequencyPointA_r16 cannot be 0\n"); + + int sl_band = 0; + //REL 16 3GPP spec 38.101 section 5.2E.1 specifies 2 bands for operation on PC5 interface. + //Band 47, Band 38 + if (pointA_ARFCN >= 790334 && pointA_ARFCN <= 795000) + sl_band = 47; + else if (pointA_ARFCN >= 514000 && pointA_ARFCN <= 524000) + sl_band = 38; + + AssertFatal(sl_band, "not valid band for Sidelink operation\n"); + + uint32_t SSB_ARFCN = (freqcfg->sl_AbsoluteFrequencySSB_r16) + ? *freqcfg->sl_AbsoluteFrequencySSB_r16 : 0; + + AssertFatal(SSB_ARFCN, "sl_AbsoluteFrequencySSB cannot be 0\n"); + + LOG_I(NR_MAC, "SIDELINK CONFIGs: AbsFreqSSB:%d, AbsFreqPointA:%d, SL band:%d\n", + SSB_ARFCN,pointA_ARFCN, sl_band); + + //FREQSHIFT_7P5KHZ is DISABLED + phycfg->sl_carrier_config.sl_frequency_shift_7p5khz = 0; + phycfg->sl_carrier_config.sl_value_N = freqcfg->valueN_r16; + + NR_SCS_SpecificCarrier_t *carriercfg = + freqcfg->sl_SCS_SpecificCarrierList_r16.list.array[0]; + + AssertFatal(carriercfg, "SCS_SpecificCarrier cannot be NULL"); + + int bw_index = get_supported_band_index(carriercfg->subcarrierSpacing, + sl_band, + carriercfg->carrierBandwidth); + phycfg->sl_carrier_config.sl_bandwidth = get_supported_bw_mhz(FR1, bw_index); + + phycfg->sl_carrier_config.sl_frequency = + from_nrarfcn(sl_band,carriercfg->subcarrierSpacing,pointA_ARFCN); // freq in kHz + + phycfg->sl_carrier_config.sl_grid_size = carriercfg->carrierBandwidth; + //For sidelink offset to carrier is 0. hence not used + //phycfg->sl_carrier_config.sl_k0 = carriercfg->offsetToCarrier; + + NR_SL_BWP_Generic_r16_t *bwp_generic = NULL; + if (freqcfg->sl_BWP_List_r16 && + freqcfg->sl_BWP_List_r16->list.array[0] && + freqcfg->sl_BWP_List_r16->list.array[0]->sl_BWP_Generic_r16) + bwp_generic = freqcfg->sl_BWP_List_r16->list.array[0]->sl_BWP_Generic_r16; + + AssertFatal(bwp_generic, "SL-BWP Generic cannot be NULL"); + + NR_BWP_t *sl_bwp = bwp_generic->sl_BWP_r16; + AssertFatal(sl_bwp, "SL-BWP cannot be NULL"); + + int locbw = bwp_generic->sl_BWP_r16->locationAndBandwidth; + phycfg->sl_bwp_config.sl_bwp_size = NRRIV2BW(locbw, MAX_BWP_SIZE); + phycfg->sl_bwp_config.sl_bwp_start = NRRIV2PRBOFFSET(locbw, MAX_BWP_SIZE); + phycfg->sl_bwp_config.sl_scs = sl_bwp->subcarrierSpacing; + + + int scs_scaling = 1<<(phycfg->sl_bwp_config.sl_scs); + + if (pointA_ARFCN < 600000) + scs_scaling = scs_scaling*3; + if (pointA_ARFCN > 2016666) + scs_scaling = scs_scaling>>2; + //SSB arfcn points to middle RE of PSBCH 11 RBs + uint32_t diff = (SSB_ARFCN - 66*scs_scaling) - pointA_ARFCN; + //the RE offset from pointA where SSB starts + phycfg->sl_bwp_config.sl_ssb_offset_point_a = diff/scs_scaling; + +#ifdef SL_DEBUG + printf("diff:%d, scaling:%d, pointa:%d, ssb:%d\n", diff, scs_scaling, pointA_ARFCN, SSB_ARFCN); +#endif + + phycfg->sl_bwp_config.sl_dc_location = (bwp_generic->sl_TxDirectCurrentLocation_r16) ? + *bwp_generic->sl_TxDirectCurrentLocation_r16 : 0; + + const uint8_t values[] = {7,8,9,10,11,12,13,14}; + phycfg->sl_bwp_config.sl_num_symbols = (bwp_generic->sl_LengthSymbols_r16) ? + values[*bwp_generic->sl_LengthSymbols_r16] : 0; + + phycfg->sl_bwp_config.sl_start_symbol = (bwp_generic->sl_StartSymbol_r16) ? + *bwp_generic->sl_StartSymbol_r16 : 0; + + //0-EXTENDED, 1-NORMAL CP + phycfg->sl_bwp_config.sl_cyclic_prefix = (sl_bwp->cyclicPrefix) ? EXTENDED : NORMAL; + + AssertFatal(phycfg->sl_bwp_config.sl_cyclic_prefix == NORMAL, "Only NORMAL-CP Supported. Ext CP not yet supported\n"); + + + AssertFatal(phycfg->sl_bwp_config.sl_start_symbol >= 0 && phycfg->sl_bwp_config.sl_start_symbol <=7, + "Sidelink Start symbol should be in range 0-7\n"); + + AssertFatal(phycfg->sl_bwp_config.sl_num_symbols >= 7 && phycfg->sl_bwp_config.sl_num_symbols <=14, + "Num Sidelink symbols should be in range 7-14\n"); + + AssertFatal((phycfg->sl_bwp_config.sl_start_symbol + phycfg->sl_bwp_config.sl_num_symbols) <= 14, + "Incorrect configuration of Start and num SL symbols\n"); + + //Configure PHY with TDD config only if the sync source is known. + if (sync_source == SL_SYNC_SOURCE_LOCAL_TIMING || + sync_source == SL_SYNC_SOURCE_GNSS) { + + phycfg->config_mask = 0xF;//Total config is sent + phycfg->sl_sync_source.gnss_dfn_offset = sl_OffsetDFN; + + // TDD Table Configuration + sl_set_tdd_config_nr_ue(&phycfg->tdd_table, + phycfg->sl_bwp_config.sl_scs, + &sl_TDD_config->pattern1); + + LOG_I(NR_MAC, "SIDELINK CONFIGs: tdd config period:%ld, mu:%ld, DLslots:%ld,ULslots:%ld Mixedslotsym DL:UL %ld:%ld\n", + sl_TDD_config->pattern1.dl_UL_TransmissionPeriodicity, sl_TDD_config->referenceSubcarrierSpacing, + sl_TDD_config->pattern1.nrofDownlinkSlots, sl_TDD_config->pattern1.nrofUplinkSlots, + sl_TDD_config->pattern1.nrofDownlinkSymbols,sl_TDD_config->pattern1.nrofUplinkSymbols); + + } else if (sync_source == SL_SYNC_SOURCE_NONE) { + //Only Carrier config, BWP config sent + phycfg->config_mask = 0x9;//partial config is sent + } + +//#ifdef SL_DEBUG + char str[5][20] = {"NONE","GNBENB","GNSS","SYNC_REF_UE","LOCAL_TIMING"}; + LOG_I(NR_MAC, "UE[%d] Function %s - Phy config preparation:\n",module_id, __FUNCTION__); + LOG_I(NR_MAC, "UE[%d] Sync source params: sync_source :%d-%s, gnss_dfn_offset:%d, rx_slss_id:%d\n", + module_id,phycfg->sl_sync_source.sync_source, + str[phycfg->sl_sync_source.sync_source], + phycfg->sl_sync_source.gnss_dfn_offset, + phycfg->sl_sync_source.rx_slss_id); + LOG_I(NR_MAC, "UE[%d] Carrier CFG Params: freq:%ld, bw:%d, gridsize:%d, valueN:%d\n", + module_id,phycfg->sl_carrier_config.sl_frequency, + phycfg->sl_carrier_config.sl_bandwidth, + phycfg->sl_carrier_config.sl_grid_size, + phycfg->sl_carrier_config.sl_value_N); + LOG_I(NR_MAC, "UE[%d] SL-BWP Params: start:%d, size:%d, scs:%d, Ncp:%d, startsym:%d, numsym:%d,ssb_offset:%d,dcloc:%d\n", + module_id,phycfg->sl_bwp_config.sl_bwp_start, + phycfg->sl_bwp_config.sl_bwp_size, + phycfg->sl_bwp_config.sl_scs, + phycfg->sl_bwp_config.sl_cyclic_prefix, + phycfg->sl_bwp_config.sl_start_symbol, + phycfg->sl_bwp_config.sl_num_symbols, + phycfg->sl_bwp_config.sl_ssb_offset_point_a, + phycfg->sl_bwp_config.sl_dc_location); + +//#endif + + return; +} + +// RRC calls this API when RRC is configured with Sidelink PRE-configuration I.E +int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id, + NR_SL_PreconfigurationNR_r16_t *sl_preconfiguration, + uint8_t sync_source) +{ + + LOG_I(NR_MAC,"[UE%d] SL RRC->MAC CONFIG RECEIVED. Syncsource:%d\n", + module_id, sync_source); + + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + AssertFatal(sl_preconfiguration !=NULL,"SL-Preconfig Cannot be NULL"); + AssertFatal(mac, "mac should have an instance"); + + if (!mac->SL_MAC_PARAMS) + mac->SL_MAC_PARAMS = CALLOC(1, sizeof(sl_nr_ue_mac_params_t)); + + sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS; + + NR_SidelinkPreconfigNR_r16_t *sl_preconfig = &sl_preconfiguration->sidelinkPreconfigNR_r16; + + //Only one entry supported in rel16. + //Carrier freq config used for Sidelink + + NR_SL_FreqConfigCommon_r16_t *freqcfg = (sl_preconfig->sl_PreconfigFreqInfoList_r16) + ? sl_preconfig->sl_PreconfigFreqInfoList_r16->list.array[0] + : NULL; + + AssertFatal(freqcfg !=NULL,"SL fcfg Cannot be NULL"); + + //MAx num of consecutive HARQ DTX before triggering RLF. + const uint8_t MaxNumConsecutiveDTX[] = {1,2,3,4,6,8,16,32}; + sl_mac->sl_MaxNumConsecutiveDTX = (sl_preconfig->sl_MaxNumConsecutiveDTX_r16) + ? MaxNumConsecutiveDTX[*sl_preconfig->sl_MaxNumConsecutiveDTX_r16] + : 0; + + //priority of SL-SSB tx and rx + sl_mac->sl_SSB_PriorityNR = (sl_preconfig->sl_SSB_PriorityNR_r16) + ? *sl_preconfig->sl_SSB_PriorityNR_r16 : 0; + + //Indicates if CSI Reporting is enabled in UNICAST. is 0-ENABLED, 1-DISABLED + sl_mac->sl_CSI_Acquisition = (sl_preconfig->sl_CSI_Acquisition_r16) ? 0 : 1; + + //Used for DFN calculation in case Sync source = GNSS. + uint32_t sl_OffsetDFN = (sl_preconfig->sl_OffsetDFN_r16) + ? *sl_preconfig->sl_OffsetDFN_r16 : 0; + + NR_SL_BWP_ConfigCommon_r16_t *bwp = NULL; + if (freqcfg->sl_BWP_List_r16 && + freqcfg->sl_BWP_List_r16->list.array[0]) + bwp = freqcfg->sl_BWP_List_r16->list.array[0]; + + AssertFatal(bwp!=NULL, "BWP config common cannot be NULL\n"); + if (bwp->sl_BWP_PoolConfigCommon_r16) { + if (bwp->sl_BWP_PoolConfigCommon_r16->sl_RxPool_r16) { + + for (int i=0;isl_BWP_PoolConfigCommon_r16->sl_RxPool_r16->list.count;i++) { + NR_SL_ResourcePool_r16_t *rxpool = bwp->sl_BWP_PoolConfigCommon_r16->sl_RxPool_r16->list.array[i]; + if (rxpool) { + if (sl_mac->sl_RxPool[i] == NULL) + sl_mac->sl_RxPool[i] = malloc16_clear(sizeof(SL_ResourcePool_params_t)); + sl_mac->sl_RxPool[i]->respool = rxpool; + uint16_t sci_1a_len = 0, num_subch = 0; + sci_1a_len = sl_determine_sci_1a_len(&num_subch, + sl_mac->sl_RxPool[i]->respool, + &sl_mac->sl_RxPool[i]->sci_1a); + sl_mac->sl_RxPool[i]->num_subch = num_subch; + sl_mac->sl_RxPool[i]->sci_1a_len = sci_1a_len; + + LOG_I(NR_MAC,"Rxpool[%d] - num subchannels:%d, sci_1a_len:%d\n",i, + sl_mac->sl_RxPool[i]->num_subch, + sl_mac->sl_RxPool[i]->sci_1a_len); + + } + } + } + + if (bwp->sl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16) { + + for (int i=0;isl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16->list.count;i++) { + + NR_SL_ResourcePool_r16_t *txpool = + bwp->sl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16->list.array[0]->sl_ResourcePool_r16; + + if (txpool) { + if (sl_mac->sl_TxPool[i] == NULL) + sl_mac->sl_TxPool[i] = malloc16_clear(sizeof(SL_ResourcePool_params_t)); + sl_mac->sl_TxPool[i]->respool = txpool; + + uint16_t sci_1a_len = 0, num_subch = 0; + sci_1a_len = sl_determine_sci_1a_len(&num_subch, + sl_mac->sl_TxPool[i]->respool, + &sl_mac->sl_TxPool[i]->sci_1a); + + sl_mac->sl_TxPool[i]->num_subch = num_subch; + sl_mac->sl_TxPool[i]->sci_1a_len = sci_1a_len; + + LOG_I(NR_MAC,"Txpool[%d] - num subchannels:%d, sci_1a_len:%d\n",i, + sl_mac->sl_TxPool[i]->num_subch, + sl_mac->sl_TxPool[i]->sci_1a_len); + } + } + } + } + + if (sync_source == SL_SYNC_SOURCE_GNSS || + sync_source == SL_SYNC_SOURCE_LOCAL_TIMING) { + + NR_TDD_UL_DL_ConfigCommon_t *tdd_uldl_config = NULL; + if (sl_preconfig->sl_PreconfigGeneral_r16 && + sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16) + tdd_uldl_config = sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16; + + AssertFatal((tdd_uldl_config!=NULL), "Sidelink MAC CFG: TDD Config cannot be NULL"); + AssertFatal((tdd_uldl_config->pattern2 == NULL), "Sidelink MAC CFG: pattern2 not yet supported"); + + sl_mac->sl_TDD_config = sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16; + } + + //Do not copy TDD config yet as SYNC source is not yet found + if (sync_source == SL_SYNC_SOURCE_NONE) { + if (sl_mac->sl_TDD_config) + ASN_STRUCT_FREE(asn_DEF_NR_TDD_UL_DL_ConfigCommon, sl_mac->sl_TDD_config); + sl_mac->sl_TDD_config = NULL; + } + + nr_sl_phy_config_t *sl_phy_cfg = &sl_mac->sl_phy_config; + sl_phy_cfg->Mod_id = module_id; + sl_phy_cfg->CC_id = 0; + + sl_prepare_phy_config(module_id, &sl_phy_cfg->sl_config_req, + freqcfg, sync_source, sl_OffsetDFN, sl_mac->sl_TDD_config); + + return 0; +} + + +//Copies the values of SSB time allocation from ASN format to MAC context +static void sl_mac_config_ssb_time_alloc(uint8_t module_id, + NR_SL_SSB_TimeAllocation_r16_t *sl_SSB_TimeAllocation_r16, + sl_ssb_timealloc_t *ssb_time_alloc) +{ + + const uint8_t values[] = {1,2,4,8,16,32,64}; + ssb_time_alloc->sl_NumSSB_WithinPeriod = + (sl_SSB_TimeAllocation_r16->sl_NumSSB_WithinPeriod_r16 != NULL) + ? values[*sl_SSB_TimeAllocation_r16->sl_NumSSB_WithinPeriod_r16] : 0; + ssb_time_alloc->sl_TimeOffsetSSB = (sl_SSB_TimeAllocation_r16->sl_TimeOffsetSSB_r16 != NULL) + ? *sl_SSB_TimeAllocation_r16->sl_TimeOffsetSSB_r16 : 0; + ssb_time_alloc->sl_TimeInterval = (sl_SSB_TimeAllocation_r16->sl_TimeInterval_r16 != NULL) + ? *sl_SSB_TimeAllocation_r16->sl_TimeInterval_r16 : 0; + +} + + + +//This API is called by RRC after it determines that UE needs to transmit SL-SSB +// SLSS id and SL-MIB is given to MAC by RRC +void nr_rrc_mac_transmit_slss_req(module_id_t module_id, + uint8_t *sl_mib_payload, + uint16_t tx_slss_id, + NR_SL_SSB_TimeAllocation_r16_t *ssb_ta) +{ + + sl_nr_ue_mac_params_t *sl_mac = get_mac_inst(module_id)->SL_MAC_PARAMS; + AssertFatal(sl_mac,"sidelink MAC cannot be NULL"); + AssertFatal(tx_slss_id < 672,"SLSS id cannot be >= 672. id:%d", tx_slss_id); + AssertFatal(ssb_ta,"ssb_ta cannot be NULL"); + + sl_mac->tx_sl_bch.slss_id = tx_slss_id; + sl_mac->tx_sl_bch.status = 1; + memcpy(sl_mac->tx_sl_bch.sl_mib,sl_mib_payload, 4); + + sl_mac->tx_sl_bch.num_ssb = 0; + sl_mac->tx_sl_bch.ssb_slot = 0; + + sl_mac_config_ssb_time_alloc(module_id, + ssb_ta, + &sl_mac->tx_sl_bch.ssb_time_alloc); + + LOG_I(NR_MAC,"[UE%d]SL RRC->MAC: TX SLSS REQ SLSS-id:%d, SL-MIB:%x, numssb:%d, offset:%d, interval:%d\n", + module_id, sl_mac->tx_sl_bch.slss_id, + *((uint32_t *)sl_mib_payload), + sl_mac->tx_sl_bch.ssb_time_alloc.sl_NumSSB_WithinPeriod, + sl_mac->tx_sl_bch.ssb_time_alloc.sl_TimeOffsetSSB, + sl_mac->tx_sl_bch.ssb_time_alloc.sl_TimeInterval); + + uint8_t byte0 = 0; + uint8_t byte1 = 0; + sl_nr_bwp_config_t *cfg = &sl_mac->sl_phy_config.sl_config_req.sl_bwp_config; + sl_prepare_psbch_payload(sl_mac->sl_TDD_config, &byte0, &byte1, + cfg->sl_scs,cfg->sl_num_symbols,cfg->sl_start_symbol); + + sl_mac->tx_sl_bch.sl_mib[0] = byte0; + sl_mac->tx_sl_bch.sl_mib[1] = byte1 | sl_mac->tx_sl_bch.sl_mib[1]; + + LOG_I(NR_MAC, "[UE%d]SL RRC->MAC: TX SLSS REQ - TDD CONFIG STUFFED INSIDE - SL-MIB :%x\n", + module_id, *((uint32_t *)sl_mac->tx_sl_bch.sl_mib)); +} + +//This API is called by RRC after it determines that UE needs to keep +// receiving SL-SSB from the sync ref UE +void nr_rrc_mac_config_req_sl_mib(module_id_t module_id, + NR_SL_SSB_TimeAllocation_r16_t *ssb_ta, + uint16_t rx_slss_id, + uint8_t *sl_mib) +{ + + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS; + AssertFatal(sl_mac,"Sidelink MAC instance cannot be NULL"); + + AssertFatal(ssb_ta,"ssb_ta cannot be NULL"); + AssertFatal(rx_slss_id < 672,"SLSS id cannot be >= 672. id:%d", rx_slss_id); + AssertFatal(sl_mib,"sl_mib cannot be NULL"); + + sl_nr_phy_config_request_t *sl_config = &sl_mac->sl_phy_config.sl_config_req; + + //Update configs if Sync source is not set else nothing to be done + if ( sl_config->sl_sync_source.sync_source == SL_SYNC_SOURCE_NONE) { + //Set SYNC source as SYNC REF UE and send the remaining config to PHY + sl_config->config_mask = 0xF;//all configs done. + sl_config->sl_sync_source.sync_source = SL_SYNC_SOURCE_SYNC_REF_UE; + sl_config->sl_sync_source.rx_slss_id = rx_slss_id; + + + sl_mac->rx_sl_bch.status = 1; + sl_mac->rx_sl_bch.slss_id = rx_slss_id; + + sl_mac->rx_sl_bch.num_ssb = 0; + sl_mac->rx_sl_bch.ssb_slot = 0; + + sl_mac_config_ssb_time_alloc(module_id, + ssb_ta, + &sl_mac->rx_sl_bch.ssb_time_alloc); + + LOG_I(NR_MAC,"[UE%d]SL RRC->MAC: RX SLSS REQ SLSS-id:%d, SL-MIB:%x, numssb:%d, offset:%d, interval:%d\n", + module_id, sl_mac->rx_sl_bch.slss_id, + *((uint32_t *)sl_mib), + sl_mac->rx_sl_bch.ssb_time_alloc.sl_NumSSB_WithinPeriod, + sl_mac->rx_sl_bch.ssb_time_alloc.sl_TimeOffsetSSB, + sl_mac->rx_sl_bch.ssb_time_alloc.sl_TimeInterval); + + if (sl_mac->sl_TDD_config == NULL) + sl_mac->sl_TDD_config = CALLOC(sizeof(NR_TDD_UL_DL_ConfigCommon_t), 1); + + sl_nr_phy_config_request_t *cfg = &sl_mac->sl_phy_config.sl_config_req; + int ret = 1; + ret = sl_decode_sl_TDD_Config(sl_mac->sl_TDD_config, + sl_mib[0], sl_mib[1]&0xF0, + cfg->sl_bwp_config.sl_scs, + cfg->sl_bwp_config.sl_num_symbols, + cfg->sl_bwp_config.sl_start_symbol); + + if (ret == 0) { + //sl_tdd_config bytes are all 1's - no TDD config present use all slots for sidelink. + //Spec not clear -- TBD... + sl_mac->sl_TDD_config->pattern1.nrofUplinkSlots = + NR_NUMBER_OF_SUBFRAMES_PER_FRAME*(1<sl_bwp_config.sl_scs); + } + + sl_set_tdd_config_nr_ue(&cfg->tdd_table, + cfg->sl_bwp_config.sl_scs, + &sl_mac->sl_TDD_config->pattern1); + LOG_I(MAC, "SIDELINK CONFIGs: tdd config period:%ld, mu:%ld, DLslots:%ld,ULslots:%ld Mixedslotsym DL:UL %ld:%ld\n", + sl_mac->sl_TDD_config->pattern1.dl_UL_TransmissionPeriodicity,sl_mac->sl_TDD_config->referenceSubcarrierSpacing, + sl_mac->sl_TDD_config->pattern1.nrofDownlinkSlots, sl_mac->sl_TDD_config->pattern1.nrofUplinkSlots, + sl_mac->sl_TDD_config->pattern1.nrofDownlinkSymbols,sl_mac->sl_TDD_config->pattern1.nrofUplinkSymbols); + + } + +} + diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index f739d1f021..f5ec77d8af 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -47,6 +47,7 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" #include "LAYER2/MAC/mac.h" #include "NR_MAC_COMMON/nr_mac_extern.h" +#include "mac_defs_sl.h" /* RRC */ #include "NR_DRX-Config.h" @@ -543,6 +544,9 @@ typedef struct NR_UE_MAC_INST_s { pthread_mutex_t mutex_dl_info; + //SIDELINK MAC PARAMETERS + sl_nr_ue_mac_params_t *SL_MAC_PARAMS; + } NR_UE_MAC_INST_t; /*@}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h b/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h new file mode 100644 index 0000000000..5e3dc39e38 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h @@ -0,0 +1,157 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef __MAC_DEFS_SL_H__ +#define __MAC_DEFS_SL_H__ + +#include "sidelink_nr_ue_interface.h" +#include "NR_SL-ResourcePool-r16.h" +#include "NR_TDD-UL-DL-ConfigCommon.h" +#include "NR_MAC_COMMON/nr_mac.h" +#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h" + +#define SL_NR_MAC_NUM_RX_RESOURCE_POOLS 1 +#define SL_NR_MAC_NUM_TX_RESOURCE_POOLS 1 +#define SL_NUM_BYTES_TIMERESOURCEBITMAP 20 + +// Size of Fixed fields prio (3), sci_2ndstage(2), +// betaoffsetindicator(2), num dmrs ports (1), mcs (5bits) +#define SL_SCI_FORMAT_1A_LEN_IN_BITS_FIXED_FIELDS 13 + +#define NR_SBCCH_SL_BCH 0xFF + +#define sci_field_t dci_field_t + +typedef struct sidelink_sci_format_1a_fields { + + // Priority of this transmission + uint8_t priority; //3 bits + //Indicates the format to be used in 2nd stage i.e SCI format 2 sent on PSSCH + //00 - SCI FORMAT 2A, 01 - SCI FORMAT 2B, 10, 11 - Reserved + //Spec 38.212 Table 8.3.1.1-1 + uint8_t sci_format_2nd_stage; //2 bits + //Num modulated symbols for stage 2 SCI - TBD: + // Spec 38.212 Table 8.3.1.1-2 + uint8_t beta_offset_indicator; //2 bits + //determine the number of layers for data on PSSCH + // Spec 38.212 Table 8.3.1.1-3 + uint8_t num_dmrs_ports; //1 bit + //Modulation and coding scheme to be used for data on PSSCH + uint8_t mcs; //5 bits + + //Identifies the frequence resource (subchannels) to be used for PSSCH/PSCCH + //sl-MaxNumPerReserve is 2 - ceil(log2(N_subch*(N_subch+1)/2)) bits + //sl-MaxNumPerReserve is 3 - ceil(log2(N_subch*(N_subch+1)(2*N_subch+1)/6)) bits + sci_field_t frequency_resource_assignment; //variable + //Identifies the Time resource (slots) to be used for PSSCH/PSCCH + //sl-MaxNumPerReserve is 2 - 5 bits + //sl-MaxNumPerReserve is 3 - 9 bits + sci_field_t time_resource_assignment; //variable + //TBD: + //sl-MultiReserveResource is not configured - 0 bits + //sl-MultiReserveResource is configured - ceil(log2(number of entries in sl-ResourceReservePeriodList)) bits + sci_field_t resource_reservation_period; //variable + //Identifies the DMRS Pattern to be used on PSSCH + //ceil(log2(number of dmrs patterns in sl-PSSCH-DMRS-TimePatternList)) bits + sci_field_t dmrs_pattern; //variable + //Identifies the TABLE to be used to determine MCS on PSSCH + //1 table configured in sl-Additional-MCS-Table - 1 bit + //2 tables configured in sl-Additional-MCS-Table - 2 bits + //Not configured- 0 bits + sci_field_t additional_mcs_table_indicator; //variable + //Identifies the number of symbols for PSFCH + //sl-PSFCH-Period Not configured- 0 bits + //if sl-PSFCH-Period configured and value 2 or 4 - 1 bit + sci_field_t psfch_overhead_indication; //variable + //number of bits determined by sl-NumReservedbits + //Value encoded is 0 + sci_field_t reserved_bits; + +} sidelink_sci_format_1a_fields_t; + +typedef struct SL_ResourcePool_params { + + //This holds the structure from RRC + NR_SL_ResourcePool_r16_t *respool; + + //NUM Subchannels in this resource pool + uint16_t num_subch; + + //SCI-1A length is the same for this resource pool. + uint16_t sci_1a_len; + + //SCI-1A configuration according to RESPOOL configured. + sidelink_sci_format_1a_fields_t sci_1a; + +} SL_ResourcePool_params_t; + +typedef struct sl_ssb_timealloc { + + uint32_t sl_NumSSB_WithinPeriod; + uint32_t sl_TimeOffsetSSB; + uint32_t sl_TimeInterval; + +} sl_ssb_timealloc_t; + +typedef struct sl_bch_params { + + //configured from RRC + //Parameters used to determine PSBCH slot + sl_ssb_timealloc_t ssb_time_alloc; + uint16_t slss_id; + bool status; + uint8_t sl_mib[4]; + + //Parameters incremented by MAC PSBCH scheduler + //after every SSB txn/reception + uint16_t num_ssb; + uint16_t ssb_slot; + +} sl_bch_params_t; + +typedef struct sl_nr_ue_mac_params { + + //Holds the RX resource pool from RRC and its related parameters + SL_ResourcePool_params_t *sl_RxPool[SL_NR_MAC_NUM_RX_RESOURCE_POOLS]; + //Holds the TX resource pool from RRC and its related parameters + SL_ResourcePool_params_t *sl_TxPool[SL_NR_MAC_NUM_TX_RESOURCE_POOLS]; + + //Holds either the TDD config from RRC + //or TDD config decoded from SL-MIB + NR_TDD_UL_DL_ConfigCommon_t *sl_TDD_config; + + //Configured from RRC + uint32_t sl_MaxNumConsecutiveDTX; + uint32_t sl_SSB_PriorityNR; + uint8_t sl_CSI_Acquisition; + + //MAC prepares this and sends it to PHY + nr_sl_phy_config_t sl_phy_config; + + //Holds Broadcast params incase UE sends Sidelink SSB + sl_bch_params_t tx_sl_bch; + //Holds Broadcast params incase UE receives SL-SSB + sl_bch_params_t rx_sl_bch; + +} sl_nr_ue_mac_params_t; + + +#endif diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 76eb6cbf0a..512c6eb483 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -515,4 +515,28 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, RAR_grant_t *rar_grant, uint16_t rnti, const nr_dci_format_t dci_format); + +int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id, + NR_SL_PreconfigurationNR_r16_t *sl_preconfiguration, + uint8_t sync_source); + +void nr_rrc_mac_transmit_slss_req(module_id_t module_id, + uint8_t *sl_mib_payload, + uint16_t tx_slss_id, + NR_SL_SSB_TimeAllocation_r16_t *ssb_ta); +void nr_rrc_mac_config_req_sl_mib(module_id_t module_id, + NR_SL_SSB_TimeAllocation_r16_t *ssb_ta, + uint16_t rx_slss_id, + uint8_t *sl_mib); +void sl_prepare_psbch_payload(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t *bits_0_to_7, uint8_t *bits_8_to_11, + uint8_t mu, uint8_t L, uint8_t Y); + +uint8_t sl_decode_sl_TDD_Config(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t bits_0_to_7, uint8_t bits_8_to_11, + uint8_t mu, uint8_t L, uint8_t Y); + +uint8_t sl_determine_sci_1a_len(uint16_t *num_subchannels, + NR_SL_ResourcePool_r16_t *rpool, + sidelink_sci_format_1a_fields_t *sci_1a); #endif diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c new file mode 100644 index 0000000000..d514558b3e --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c @@ -0,0 +1,524 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "mac_defs_sl.h" + +#define SL_DEBUG + +uint8_t sl_process_TDD_UL_DL_config_patterns(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t mu, + double *slot_period_P, + uint8_t *w) +{ + + uint8_t return_value = 255; + *w = 0; + int pattern1_dlul_period = TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity; + +#ifdef SL_DEBUG + + printf("INPUT VALUES: function: %s\n", __func__); + printf("pattern1 periodicity:%d\n", pattern1_dlul_period); + if (TDD_UL_DL_Config->pattern1.ext1 != NULL && TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL ) + printf("pattern1 periodicity_v1530:%ld\n", *TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530); + if (TDD_UL_DL_Config->pattern2 != NULL) { + printf("mu:%d, pattern2 periodicity:%d\n", mu, pattern1_dlul_period); + if (TDD_UL_DL_Config->pattern2->ext1 != NULL && TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL ) + printf("pattern2 periodicity_v1530:%ld\n", *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530); + } + +#endif + + return_value = pattern1_dlul_period; + switch (pattern1_dlul_period) { + case 0: + *slot_period_P = 0.5; + break; + case 1: + *slot_period_P = 0.625; + break; + case 2: + *slot_period_P = 1.0; + break; + case 3: + *slot_period_P = 1.25; + break; + case 4: + *slot_period_P = 2.0; + break; + case 5: + *slot_period_P = 2.5; + break; + case 6: + *slot_period_P = 5.0; + return_value = 7; + break; + case 7: + *slot_period_P = 10.0; + return_value = 8; + break; + default: + AssertFatal(1==0,"Incorrect value of dl_UL_TransmissionPeriodicity\n"); + break; + } + + if (TDD_UL_DL_Config->pattern1.ext1 != NULL && + TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL ) { + if (*TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 == 1) { + *slot_period_P = 4.0; + return_value = 6; + } else { + *slot_period_P = 3.0; + return_value = 255; + } + } + + if (TDD_UL_DL_Config->pattern2 != NULL) { + + return_value = 255; + *w = 1; + + if ((*slot_period_P == 4.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 1)) { + return_value = 13; + *w = (mu == 3)? 2: 1; + } else if ((*slot_period_P == 3.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4)) { + return_value = 12; + *w = (mu == 3)? 2: 1; + } else if ((*slot_period_P == 3.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 2)) { + return_value = 8; + *w = (mu == 3)? 2: 1; + } else { + + switch (pattern1_dlul_period) { + case 7: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 7) { + return_value = 15; + *w = 1<pattern2->dl_UL_TransmissionPeriodicity == 6) { + return_value = 14; + *w = (mu==0)?1:1<<(mu-1); + } + break; + case 5: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 5) { + return_value = 11; + *w = (mu == 3)? 2: 1; + } + break; + case 4: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 0) { + return_value = 5; + } + else if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4) { + return_value = 7; + } + else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 0) { + return_value = 10; + *w = (mu == 3)? 2: 1; + } + break; + case 3: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 3) { + return_value = 4; + } + break; + case 2: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 2) { + return_value = 2; + } + else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 0) { + return_value = 6; + *w = (mu == 3)? 2: 1; + } + else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 1) { + return_value = 9; + *w = (mu == 3)? 2: 1; + } + break; + case 1: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 1) { + return_value = 1; + } + break; + case 0: + if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 0) { + return_value = 0; + } + else if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4) { + return_value = 3; + } + break; + default: + AssertFatal(1==0,"Incorrect value of dl_UL_TransmissionPeriodicity"); + } + } + } + +#ifdef SL_DEBUG + printf("OUTPUT VALUES: function %s\n",__func__); + printf("return_value:%d, *w:%d, slot_period_P:%f\n", return_value, *w, *slot_period_P); +#endif + + return return_value; +} + +/* +This procedures prepares the psbch payload of tdd configuration according +to section 16.1 in 38.213 +*/ +void sl_prepare_psbch_payload(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t *bits_0_to_7, uint8_t *bits_8_to_11, + uint8_t mu, uint8_t L, uint8_t Y) +{ + + uint8_t w = 0, a1_to_a4 = 0; + uint8_t mu_ref = 0, diff = 0; + uint8_t u_slots = 0, u_sym = 0, I1 = 0; + uint8_t u_sl_slots = 0, u_sl_slots_2 = 0; + double slot_period_P = 0.0; + + *bits_0_to_7 = 0xFF; // If TDD_UL_DL_Config = NULL all 12 bits are set to 1 + *bits_8_to_11 = 0xF0; + + if (TDD_UL_DL_Config != NULL) { + + mu_ref = TDD_UL_DL_Config->referenceSubcarrierSpacing; + diff = 1 << (mu-mu_ref); + u_slots = TDD_UL_DL_Config->pattern1.nrofUplinkSlots; + u_sym = TDD_UL_DL_Config->pattern1.nrofUplinkSymbols; + I1 = ((u_sym * diff) % L >= (L-Y)) ? 1 : 0; + +#ifdef SL_DEBUG + printf("INPUT VALUES: function %s\n", __func__); + printf("numerology:%d, number of symbols:%d, sl-startSymbol:%d\n", mu, L, Y); + printf("mu_ref:%d, u_slots:%d, u_sym:%d\n", mu_ref, u_slots, u_sym); + if (TDD_UL_DL_Config->pattern2 != NULL) + printf("u_slots_2:%ld, u_sym_2:%ld\n", TDD_UL_DL_Config->pattern2->nrofUplinkSlots, + TDD_UL_DL_Config->pattern2->nrofUplinkSymbols); +#endif + + u_sl_slots = (u_slots * diff) + floor((u_sym*diff)/L) + I1; + a1_to_a4 = sl_process_TDD_UL_DL_config_patterns(TDD_UL_DL_Config, mu, &slot_period_P, &w); + AssertFatal(a1_to_a4 != 255,"Incorrect return value, wrong configuration.\n"); + +#ifdef SL_DEBUG + printf("I1:%d, a1_to_a2:%d, u_sl_slots:%d\n", I1, a1_to_a4, u_sl_slots); +#endif + + if (TDD_UL_DL_Config->pattern2 != NULL) { + + uint8_t u_slots_2 = TDD_UL_DL_Config->pattern2->nrofUplinkSlots; + uint8_t u_sym_2 = TDD_UL_DL_Config->pattern2->nrofUplinkSymbols; + uint8_t I2 = ((u_sym_2 * diff) % L >= (L-Y)) ? 1 : 0; + uint16_t val = floor(((u_slots_2 * diff) + floor((u_sym_2*diff)/L) + I2)/w); + + u_sl_slots_2 = val * ceil((slot_period_P*(1<> 4); + *bits_8_to_11 = (u_sl_slots_2 & 0x0F) << 4; + +#ifdef SL_DEBUG + printf("I2:%d, val:%d, u_sl_slots_2:%d\n", I2, val, u_sl_slots_2); +#endif + + } else { + *bits_0_to_7 = 0x00 | (a1_to_a4 << 3) | ((u_sl_slots & 0x70) >> 4); + *bits_8_to_11 = (u_sl_slots & 0x0F) << 4; + } + } + +#ifdef SL_DEBUG + printf("OUTPUT VALUES: function %s\n", __func__); + printf("12 bits payload buf[0]:%x, buf[1]:%x\n", *bits_0_to_7, *bits_8_to_11); +#endif + +} + +/* +This procedures prepares the psbch payload of tdd configuration according +to section 16.1 in 38.213 +*/ +uint8_t sl_decode_sl_TDD_Config(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t bits_0_to_7, uint8_t bits_8_to_11, + uint8_t mu, uint8_t L, uint8_t Y) +{ + + AssertFatal(TDD_UL_DL_Config, "TDD_UL_DL_Config cannot be null"); + uint16_t num_SL_slots = 0, mixed_slot_numsym = 0; + + TDD_UL_DL_Config->pattern1.nrofDownlinkSlots = 0; + TDD_UL_DL_Config->pattern1.nrofDownlinkSymbols = 0; + TDD_UL_DL_Config->pattern1.nrofUplinkSlots = 0; + TDD_UL_DL_Config->pattern1.nrofUplinkSymbols = 0; + TDD_UL_DL_Config->referenceSubcarrierSpacing = mu; + TDD_UL_DL_Config->pattern1.ext1 = NULL; + + LOG_D(MAC, "bits_0_to_7:%x, bits_8_to_11:%x, mu:%d, L:%d, Y:%d\n", + bits_0_to_7, bits_8_to_11,mu, L, Y); + + //If all bits are 1 - indicates that no TDD config was present. + if ((bits_0_to_7 == 0xFF) && ((bits_8_to_11 & 0xF0) == 0xF0)) { + //If no TDD config present - use all slots for Sidelink. + //Spec not clear -- TBD.... + return 0; + } + + //Bit A0 if 1 indicates pattern2 as present. + if (bits_0_to_7 & 0x80) { + //Pattern1 and Pattern2 Present. + TDD_UL_DL_Config->pattern2 = malloc16_clear(sizeof(*TDD_UL_DL_Config->pattern2)); + AssertFatal(1==0,"Decoding Pattern2 - NOT YET IMPLEMENTED\n"); + } else { + + //Only Pattern1 Present. bits a1..a4 identify the periodicity. + uint8_t val = (bits_0_to_7 & 0x78) >> 3; + if (val >= 7) + TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity = val-1; + + if (val == 6) { + if (TDD_UL_DL_Config->pattern1.ext1 == NULL) + TDD_UL_DL_Config->pattern1.ext1 = calloc(1, sizeof(*TDD_UL_DL_Config->pattern1.ext1)); + if (TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 == NULL) + TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 = calloc(1, sizeof(long)); + *TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 = 1; + } + + //a5,a6..a11 bits from the 7th to 1st LSB of num SL slots + num_SL_slots = ((bits_0_to_7 & 0x07) << 4 ) | ((bits_8_to_11 & 0xF0) >> 4); + + TDD_UL_DL_Config->pattern1.nrofUplinkSlots = num_SL_slots; + TDD_UL_DL_Config->pattern1.nrofUplinkSymbols = mixed_slot_numsym; + + LOG_D(MAC, "SIDELINK: EXtracted TDD config from 12 bits - Sidelink Slots:%ld, Mixed_slot_symbols:%ld,dl_UL_TransmissionPeriodicity:%ld\n", + TDD_UL_DL_Config->pattern1.nrofUplinkSlots, TDD_UL_DL_Config->pattern1.nrofUplinkSymbols, + TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity); + } + return 1; +} + +/*Function used to prepare Sidelink MIB*/ +uint32_t sl_prepare_MIB(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config, + uint8_t incoverage, uint8_t mu, + uint8_t start_symbol, uint8_t L) +{ + + uint8_t sl_mib_payload[4] = {0,0,0,0}; + //int mu = UE->sl_frame_params.numerology_index, start_symbol = UE->start_symbol; + uint8_t byte0, byte1; + //int L = (UE->sl_frame_params.Ncp == 0) ? 14 : 12; + uint32_t sl_mib=0; + + sl_prepare_psbch_payload(TDD_UL_DL_Config, &byte0, &byte1, mu, L, start_symbol); + sl_mib_payload[0] = byte0; + sl_mib_payload[1] = byte1; + + AssertFatal(incoverage <= 1, "Invalid value for incoverage paramter for SL-MIB. Accepted values 0 or 1\n"); + sl_mib_payload[1] |= (incoverage << 3); + + sl_mib = sl_mib_payload[1]<<8 | sl_mib_payload[0]; + +#ifdef SL_DEBUG + printf("SIDELINK PSBCH SIM: NUM SYMBOLS:%d, mu:%d, start_symbol:%d incoverage:%d \n", + L, mu, start_symbol, incoverage); + printf("SIDELINK PSBCH PAYLOAD: psbch_a:%x, sl_mib_payload:%x %x %x %x\n", + sl_mib, sl_mib_payload[0],sl_mib_payload[1], sl_mib_payload[2], sl_mib_payload[3]); +#endif + + return sl_mib; +} + +uint16_t sl_get_subchannel_size(NR_SL_ResourcePool_r16_t *rpool) +{ + + uint16_t subch_size = 0; + const uint8_t subchsizes[8] = {10, 12, 15, 20, 25, 50, 75, 100}; + + subch_size = (rpool->sl_SubchannelSize_r16) + ? subchsizes[*rpool->sl_SubchannelSize_r16] : 0; + + AssertFatal(subch_size,"Subch Size cannot be 0.Resource Pool Configuration Error\n"); + + return subch_size; +} + +uint16_t sl_get_num_subch(NR_SL_ResourcePool_r16_t *rpool) +{ + + uint16_t num_subch = 0; + uint16_t subch_size = sl_get_subchannel_size(rpool); + uint16_t num_rbs = (rpool->sl_RB_Number_r16) ? *rpool->sl_RB_Number_r16 : 0; + + AssertFatal(num_rbs,"NumRbs in rpool cannot be 0.Resource Pool Configuration Error\n"); + + num_subch = num_rbs/subch_size; + + LOG_I(NR_MAC, "Subch_size:%d, numRBS:%d, num_subch:%d\n", + subch_size,num_rbs,num_subch); + + return (num_subch); +} + +//This function determines SCI 1A Len in bits based on the configuration in the resource pool. +uint8_t sl_determine_sci_1a_len(uint16_t *num_subchannels, + NR_SL_ResourcePool_r16_t *rpool, + sidelink_sci_format_1a_fields_t *sci_1a) +{ + + uint8_t num_bits = 0; + + //Size of Fixed fields prio (3), sci_2ndstage(2), + //betaoffsetindicator(2), num dmrs ports (1), mcs (5bits) + uint8_t sci_1a_len = SL_SCI_FORMAT_1A_LEN_IN_BITS_FIXED_FIELDS; + + *num_subchannels = sl_get_num_subch(rpool); + + uint16_t n_subch = *num_subchannels; + + LOG_D(NR_MAC,"Determine SCI-1A len - Num Subch:%d, sci 1A len fixed fields:%d\n", + *num_subchannels, sci_1a_len); + + NR_SL_UE_SelectedConfigRP_r16_t *selectedconfigRP = rpool->sl_UE_SelectedConfigRP_r16; + const uint8_t maxnum_values[] = {2,3}; + uint8_t sl_MaxNumPerReserve = (selectedconfigRP && + selectedconfigRP->sl_MaxNumPerReserve_r16) + ? maxnum_values[*selectedconfigRP->sl_MaxNumPerReserve_r16] + : 0; + + //Determine bits for Freq and Time Resource assignment + if (sl_MaxNumPerReserve == 3) { + num_bits = ceil(log2(n_subch * (n_subch + 1) * (2*n_subch + 1)/6)); + sci_1a_len += num_bits; + sci_1a->frequency_resource_assignment.nbits = num_bits; + sci_1a_len += 9; + sci_1a->time_resource_assignment.nbits = 9; + } else { + num_bits = ceil(log2((n_subch * (n_subch + 1)) >> 1)); + sci_1a_len += num_bits; + sci_1a->frequency_resource_assignment.nbits = num_bits; + sci_1a_len += 5; + sci_1a->time_resource_assignment.nbits = 5; + } + + LOG_D(NR_MAC,"sci 1A - sl_MaxNumPerReserve:%d, sci 1a len:%d, FRA nbits:%d, TRA nbits:%d\n", + sl_MaxNumPerReserve,sci_1a_len, + sci_1a->frequency_resource_assignment.nbits, + sci_1a->time_resource_assignment.nbits); + + //Determine bits for res reservation period + uint8_t n_rsvperiod = (selectedconfigRP && + selectedconfigRP->sl_ResourceReservePeriodList_r16) + ? selectedconfigRP->sl_ResourceReservePeriodList_r16->list.count : 0; + + #define SL_IE_ENABLED 0 + if (selectedconfigRP && + selectedconfigRP->sl_MultiReserveResource_r16 == SL_IE_ENABLED) { + num_bits = ceil(log2(n_rsvperiod)); + sci_1a_len += num_bits; + sci_1a->resource_reservation_period.nbits = num_bits; + } else + sci_1a->resource_reservation_period.nbits = 0; + + LOG_D(NR_MAC,"sci 1A - n_rsvperiod:%d, sci 1a len:%d, res reserve period.nbits:%d\n", + n_rsvperiod, sci_1a_len, + sci_1a->resource_reservation_period.nbits); + + + uint8_t n_dmrspatterns = 0; + if (rpool->sl_PSSCH_Config_r16 && + rpool->sl_PSSCH_Config_r16->present == NR_SetupRelease_SL_PSSCH_Config_r16_PR_setup) { + NR_SL_PSSCH_Config_r16_t *pssch_cfg = rpool->sl_PSSCH_Config_r16->choice.setup; + + //Determine bits for DMRS PATTERNS + n_dmrspatterns = (pssch_cfg && pssch_cfg->sl_PSSCH_DMRS_TimePatternList_r16) + ? pssch_cfg->sl_PSSCH_DMRS_TimePatternList_r16->list.count : 0; + } + + AssertFatal((n_dmrspatterns>=1) && (n_dmrspatterns <=3), + "Number of DMRS Patterns should be 1or2or3. Resource Pool Configuration Error.\n"); + + if (n_dmrspatterns) { + num_bits = ceil(log2(n_dmrspatterns)); + sci_1a_len += num_bits; + sci_1a->dmrs_pattern.nbits = num_bits; + } + + LOG_D(NR_MAC,"sci 1A - n_dmrspatterns:%d, sci 1a len:%d, dmrs_pattern.nbits:%d\n", + n_dmrspatterns, sci_1a_len, sci_1a->dmrs_pattern.nbits); + + //Determine bits for Additional MCS table + if (rpool->sl_Additional_MCS_Table_r16) { + int numbits = (*rpool->sl_Additional_MCS_Table_r16 > 1) ? 2 : 1; + sci_1a_len += numbits; + sci_1a->additional_mcs_table_indicator.nbits = numbits; + AssertFatal(*rpool->sl_Additional_MCS_Table_r16<=2, "additional table value cannot be > 2. Resource Pool Configuration Error.\n"); + } + + LOG_D(NR_MAC,"sci 1A - additional_table:%ld, sci 1a len:%d, additional table nbits:%d\n", + *rpool->sl_Additional_MCS_Table_r16, + sci_1a_len, + sci_1a->additional_mcs_table_indicator.nbits); + + uint8_t psfch_period = 0; + if (rpool->sl_PSFCH_Config_r16 && + rpool->sl_PSFCH_Config_r16->present == NR_SetupRelease_SL_PSFCH_Config_r16_PR_setup) { + NR_SL_PSFCH_Config_r16_t *psfch_config = rpool->sl_PSFCH_Config_r16->choice.setup; + + //Determine bits for PSFCH overhead indication + const uint8_t psfch_periods[] = {0,1,2,4}; + psfch_period = (psfch_config->sl_PSFCH_Period_r16) + ? psfch_periods[*psfch_config->sl_PSFCH_Period_r16] : 0; + } + + if ((psfch_period == 2) || (psfch_period == 4)) { + sci_1a_len += 1; + sci_1a->psfch_overhead_indication.nbits = 1; + } else + sci_1a->psfch_overhead_indication.nbits = 0; + + LOG_D(NR_MAC,"sci 1A - psfch_period:%d, sci 1a len:%d, psfch overhead nbits:%d\n", + psfch_period, sci_1a_len, + sci_1a->psfch_overhead_indication.nbits); + + //Determine number of reserved bits + uint8_t num_reservedbits = 0; + if (rpool->sl_PSCCH_Config_r16 && + rpool->sl_PSCCH_Config_r16->present == NR_SetupRelease_SL_PSCCH_Config_r16_PR_setup) { + NR_SL_PSCCH_Config_r16_t *pscch_config = rpool->sl_PSCCH_Config_r16->choice.setup; + + num_reservedbits = (pscch_config->sl_NumReservedBits_r16) + ? *pscch_config->sl_NumReservedBits_r16 : 0; + } + + AssertFatal((num_reservedbits>=2) || (num_reservedbits<=4) , + "Num Reserved bits can only be 2or3or4. Resource Pool Configuration Error.\n"); + sci_1a_len += num_reservedbits; + sci_1a->reserved_bits.nbits = num_reservedbits; + LOG_D(NR_MAC,"sci 1A - reserved_bits:%d, sci 1a len:%d, sci_1a->reserved_bits.nbits:%d\n", + num_reservedbits, sci_1a_len, sci_1a->reserved_bits.nbits); + + + LOG_D(NR_MAC,"sci 1A Length in bits: %d \n",sci_1a_len); + + return sci_1a_len; +} diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index 8ebf6f757b..0b61f3fc82 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -94,6 +94,32 @@ int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, AssertFatal(false, "use RLC instead\n"); break; + case NR_SBCCH_SL_BCH: + if (pdu_len>0) { + LOG_T(NR_RRC, "[UE %d] Received SL-MIB for NR_SBCCH_SL_BCH.\n", module_id); + + MessageDef *message_p; + int msg_sdu_size = BCCH_SDU_SIZE; + + if (pdu_len > msg_sdu_size) { + LOG_E(NR_RRC, "SDU larger than NR_SBCCH_SL_BCH SDU buffer size (%d, %d)", sdu_size, msg_sdu_size); + sdu_size = msg_sdu_size; + } else { + sdu_size = pdu_len; + } + + message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_SBCCH_DATA_IND); + memset(NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu, 0, BCCH_SDU_SIZE); + memcpy(NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu, pduP, sdu_size); + NR_RRC_MAC_SBCCH_DATA_IND (message_p).frame = frame; //frameP + NR_RRC_MAC_SBCCH_DATA_IND (message_p).slot = slot; + NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu_size = sdu_size; + NR_RRC_MAC_SBCCH_DATA_IND (message_p).gnb_index = gNB_index; + NR_RRC_MAC_SBCCH_DATA_IND (message_p).rx_slss_id = rnti;//rx_slss_id is rnti + itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(module_id), message_p); + } + break; + default: break; } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index e54cccf17b..2e821e3034 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -324,10 +324,8 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int nb_inst) // SRB0 activated by default ptr->Srb[0] = RB_ESTABLISHED; } - } - if (get_softmodem_params()->sl_mode) { - configure_NR_SL_Preconfig(get_softmodem_params()->sync_ref); + init_sidelink(rrc); } return NR_UE_rrc_inst; @@ -1437,6 +1435,14 @@ void *rrc_nrue(void *notUsed) nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(rrc, bcch->gnb_index, bcch->sdu, bcch->sdu_size, bcch->rsrq, bcch->rsrp); break; + case NR_RRC_MAC_SBCCH_DATA_IND: + LOG_D(NR_RRC, "[UE %ld] Received %s: gNB %d\n", instance, ITTI_MSG_NAME(msg_p), NR_RRC_MAC_SBCCH_DATA_IND(msg_p).gnb_index); + NRRrcMacSBcchDataInd *sbcch = &NR_RRC_MAC_SBCCH_DATA_IND(msg_p); + + nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(rrc, sbcch->gnb_index,sbcch->frame, sbcch->slot, sbcch->sdu, + sbcch->sdu_size, sbcch->rx_slss_id); + break; + case NR_RRC_MAC_CCCH_DATA_IND: { NRRrcMacCcchDataInd *ind = &NR_RRC_MAC_CCCH_DATA_IND(msg_p); nr_rrc_ue_decode_ccch(rrc, ind, 0); @@ -1921,3 +1927,17 @@ void handle_t300_expiry(NR_UE_RRC_INST_t *rrc) // TODO handle connEstFailureControl // TODO inform upper layers about the failure to establish the RRC connection } + +//This calls the sidelink preconf message after RRC, MAC instances are created. +void start_sidelink(int instance) +{ + + NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; + + if (get_softmodem_params()->sl_mode == 2) { + + //Process the Sidelink Preconfiguration + rrc_ue_process_sidelink_Preconfiguration(rrc, get_softmodem_params()->sync_ref); + + } +} diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index 9c2ef2a00a..3cd453197b 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -54,6 +54,8 @@ #include "NR_DL-DCCH-Message.h" #include "NR_SystemInformation.h" #include "NR_UE-NR-Capability.h" +#include "NR_SL-PreconfigurationNR-r16.h" +#include "NR_MasterInformationBlockSidelink.h" #include "RRC/NR/nr_rrc_common.h" #include "as_message.h" @@ -210,6 +212,10 @@ typedef struct NR_UE_RRC_INST_s { long selected_plmn_identity; Rrc_State_NR_t nrRrcState; as_nas_info_t initialNasMsg; + + //Sidelink params + NR_SL_PreconfigurationNR_r16_t *sl_preconfig; + } NR_UE_RRC_INST_t; #endif diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h index 45fb1a1c0f..4750c69ffe 100644 --- a/openair2/RRC/NR_UE/rrc_proto.h +++ b/openair2/RRC/NR_UE/rrc_proto.h @@ -121,7 +121,20 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, nr_sync_msg_t sync_msg); void nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(NR_UE_RRC_INST_t *rrc, struct NR_SetupRelease_RLF_TimersAndConstants *rlf_TimersAndConstants); -int configure_NR_SL_Preconfig(int sync_source); +int configure_NR_SL_Preconfig(NR_UE_RRC_INST_t *rrc,int sync_source); + +void init_sidelink(NR_UE_RRC_INST_t *rrc); +void start_sidelink(int instance); + +void rrc_ue_process_sidelink_Preconfiguration(NR_UE_RRC_INST_t *rrc_inst, int sync_ref); + +void nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(NR_UE_RRC_INST_t *rrc, + const uint8_t gNB_index, + const frame_t frame, + const int slot, + uint8_t* pduP, + const sdu_size_t pdu_len, + const uint16_t rx_slss_id); /** @}*/ #endif diff --git a/openair2/RRC/NR_UE/rrc_sl_preconfig.c b/openair2/RRC/NR_UE/rrc_sl_preconfig.c index 41e95b1079..7fe57ad1fb 100644 --- a/openair2/RRC/NR_UE/rrc_sl_preconfig.c +++ b/openair2/RRC/NR_UE/rrc_sl_preconfig.c @@ -27,6 +27,17 @@ #include "common/utils/LOG/log.h" #include "sl_preconfig_paramvalues.h" #include "common/config/config_userapi.h" +#include "rrc_defs.h" +#include "LAYER2/NR_MAC_UE/mac_proto.h" +#include "nr-uesoftmodem.h" + +void free_sl_rrc(NR_UE_RRC_INST_t *rrc) +{ + + if (rrc->sl_preconfig) { + ASN_STRUCT_FREE(asn_DEF_NR_SL_PreconfigurationNR_r16, rrc->sl_preconfig); + } +} static void prepare_NR_SL_SyncConfig(NR_SL_SyncConfig_r16_t *sl_syncconfig) { @@ -399,8 +410,7 @@ NR_SL_PreconfigurationNR_r16_t *prepare_NR_SL_PRECONFIGURATION(uint16_t num_tx_p return sl_preconfiguration; } - -int configure_NR_SL_Preconfig(int sync_source) +int configure_NR_SL_Preconfig(NR_UE_RRC_INST_t *rrc,int sync_source) { NR_SL_PreconfigurationNR_r16_t *sl_preconfig = NULL; @@ -424,9 +434,136 @@ int configure_NR_SL_Preconfig(int sync_source) } } - ASN_STRUCT_FREE(asn_DEF_NR_SL_PreconfigurationNR_r16, sl_preconfig); - sl_preconfig = NULL; - //END....... + rrc->sl_preconfig = sl_preconfig; return 0; } + +/*decode SL-BCH (SL-MIB) message*/ +static int8_t nr_sl_rrc_ue_decode_SL_MIB(const uint8_t gNB_index, + uint8_t *const bufferP, + const uint8_t buffer_len) +{ + NR_MasterInformationBlockSidelink_t *sl_mib = NULL; + + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_MasterInformationBlockSidelink, + (void **)&sl_mib, + (const void *)bufferP, buffer_len); + + int ret = 0; + if ((dec_rval.code != RC_OK) || (dec_rval.consumed == 0)) { + LOG_E(NR_RRC, "SL-MIB decode error\n"); + ret = -1; + } else { + + int bits_unused = sl_mib->directFrameNumber_r16.bits_unused; + uint16_t val_fn = sl_mib->directFrameNumber_r16.buf[0]; + val_fn = (val_fn << (8 - bits_unused)) + (sl_mib->directFrameNumber_r16.buf[1] >> bits_unused); + + uint8_t val_slot = sl_mib->slotIndex_r16.buf[0]; + + LOG_D(NR_RRC, "SL-RRC - Received MIB\n"); + LOG_D(NR_RRC, "SL-MIB Contents - DFN:%d\n" , val_fn); + LOG_D(NR_RRC, "SL-MIB Contents - SLOT:%d\n" , val_slot >> 1); + LOG_D(NR_RRC, "SL-MIB Contents - Incoverage:%d\n", sl_mib->inCoverage_r16); + LOG_D(NR_RRC, "SL-MIB Contents - sl-TDD-Config:%x\n" , *((uint16_t *)(sl_mib->sl_TDD_Config_r16.buf))); + + ASN_STRUCT_FREE(asn_DEF_NR_MasterInformationBlockSidelink, sl_mib); + + } + + return ret; +} + + +void nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(NR_UE_RRC_INST_t *rrc, + const uint8_t gNB_index, + const frame_t frame, + const int slot, + uint8_t* pduP, + const sdu_size_t pdu_len, + const uint16_t rx_slss_id) +{ + + nr_sl_rrc_ue_decode_SL_MIB(gNB_index, (uint8_t*)pduP, pdu_len); + + DevAssert(rrc->sl_preconfig); + + NR_SL_FreqConfigCommon_r16_t *fcfg = NULL; + if (rrc->sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16) + fcfg = rrc->sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16->list.array[0]; + DevAssert(fcfg); + + NR_SL_SSB_TimeAllocation_r16_t *sl_SSB_TimeAllocation = NULL; + + //Current implementation only supports one SSB Timeallocation + //Extend RRC to use multiple SSB Time allocations TBD.... + if (fcfg->sl_SyncConfigList_r16) + sl_SSB_TimeAllocation = fcfg->sl_SyncConfigList_r16->list.array[0]->sl_SSB_TimeAllocation1_r16; + DevAssert(sl_SSB_TimeAllocation); + + nr_rrc_mac_config_req_sl_mib(rrc->ue_id, + sl_SSB_TimeAllocation, + rx_slss_id, + pduP); + + return; +} + +void rrc_ue_process_sidelink_Preconfiguration(NR_UE_RRC_INST_t *rrc_inst, + sl_sync_source_enum_t sync_source) +{ + + AssertFatal(rrc_inst, "RRC instance not created.\n"); + + NR_SL_PreconfigurationNR_r16_t *sl_preconfig = rrc_inst->sl_preconfig; + AssertFatal(rrc_inst->sl_preconfig, "Check if SL-preconfig was created"); + + AssertFatal(sync_source != SL_SYNC_SOURCE_GNBENB, "Sync source GNB not supported\n"); + + nr_rrc_mac_config_req_sl_preconfig(rrc_inst->ue_id, sl_preconfig, sync_source); + + //TBD.. These should be chosen by RRC according to 3GPP 38.331 RRC specification. + //Currently hardcoding the values to these + uint16_t slss_id = 671, ssb_ta_index = 1; + //12 bits -sl-TDD-config will be filled by MAC + //Incoverage 1bit is FALSE as this is mode 2 + //DFN, sfn will be filled by PHY + uint8_t sl_mib_payload[4] = {0,0,0,0}; + + NR_SL_SSB_TimeAllocation_r16_t *ssb_ta = NULL; + NR_SL_FreqConfigCommon_r16_t *fcfg = NULL; + NR_SL_SyncConfig_r16_t *synccfg = NULL; + if (sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16) + fcfg = sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16->list.array[0]; + AssertFatal(fcfg, "Fcfg cannot be NULL\n"); + if (fcfg->sl_SyncConfigList_r16) + synccfg = fcfg->sl_SyncConfigList_r16->list.array[0]; + AssertFatal(synccfg, "Synccfg cannot be NULL\n"); + + if (ssb_ta_index == 1) + ssb_ta = synccfg->sl_SSB_TimeAllocation1_r16; + else if (ssb_ta_index == 2) + ssb_ta = synccfg->sl_SSB_TimeAllocation2_r16; + else if (ssb_ta_index == 3) + ssb_ta = synccfg->sl_SSB_TimeAllocation3_r16; + else DevAssert(0); + + AssertFatal(ssb_ta, "SSB_timeallocation cannot be NULL\n"); + + if (sync_source == SL_SYNC_SOURCE_LOCAL_TIMING || sync_source == SL_SYNC_SOURCE_GNSS) + nr_rrc_mac_transmit_slss_req(rrc_inst->ue_id,sl_mib_payload, slss_id, ssb_ta); + +} + +//For Sidelink mode 2 operation this prepares the sidelink preconfiguration +void init_sidelink(NR_UE_RRC_INST_t *rrc) +{ + int sync_ref = get_softmodem_params()->sync_ref; + + if (get_softmodem_params()->sl_mode == 2) { + //Preparation of the Sidelink PRE-Configuration message + configure_NR_SL_Preconfig(rrc, sync_ref); + + } +}