Commit ad2da99d authored by William Johnson's avatar William Johnson

testing of Discovery transmission/reception

parent ccdc09c8
...@@ -252,7 +252,7 @@ typedef struct { ...@@ -252,7 +252,7 @@ typedef struct {
// decode phich // decode phich
uint8_t decode_phich; uint8_t decode_phich;
} LTE_UL_UE_HARQ_t; } LTE_UL_UE_HARQ_t;
#ifdef Rel14 #ifdef Rel14
typedef enum { typedef enum {
...@@ -265,7 +265,7 @@ typedef struct { ...@@ -265,7 +265,7 @@ typedef struct {
/// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding)
int32_t *txdataF[8]; int32_t *txdataF[8];
/// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers? /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers?
int32_t **ue_spec_bf_weights[4]; int32_t **ue_spec_bf_weights[4];
/// dl channel estimates (estimated from ul channel estimates) /// dl channel estimates (estimated from ul channel estimates)
int32_t **calib_dl_ch_estimates; int32_t **calib_dl_ch_estimates;
/// Allocated RNTI (0 means DLSCH_t is not currently used) /// Allocated RNTI (0 means DLSCH_t is not currently used)
...@@ -413,7 +413,7 @@ typedef struct { ...@@ -413,7 +413,7 @@ typedef struct {
/// is done after a new scheduling /// is done after a new scheduling
uint16_t previous_first_rb; uint16_t previous_first_rb;
/// Current Number of RBs /// Current Number of RBs
uint16_t nb_rb; uint16_t nb_rb;
/// Current Modulation order /// Current Modulation order
uint8_t Qm; uint8_t Qm;
/// Transport block size /// Transport block size
...@@ -531,7 +531,7 @@ typedef enum { ...@@ -531,7 +531,7 @@ typedef enum {
HARQ_SR, HARQ_SR,
HARQ_CQI, HARQ_CQI,
SR_CQI, SR_CQI,
HARQ_SR_CQI HARQ_SR_CQI
} UCI_type_t; } UCI_type_t;
#ifdef Rel14 #ifdef Rel14
...@@ -556,7 +556,7 @@ typedef struct { ...@@ -556,7 +556,7 @@ typedef struct {
uint8_t srs_active; uint8_t srs_active;
/// PUCCH format to use /// PUCCH format to use
PUCCH_FMT_t pucch_fmt; PUCCH_FMT_t pucch_fmt;
/// number of PUCCH antenna ports /// number of PUCCH antenna ports
uint8_t num_antenna_ports; uint8_t num_antenna_ports;
/// number of PUCCH resources /// number of PUCCH resources
uint8_t num_pucch_resources; uint8_t num_pucch_resources;
...@@ -878,7 +878,7 @@ typedef struct { ...@@ -878,7 +878,7 @@ typedef struct {
typedef struct { typedef struct {
// SL Configuration // SL Configuration
/// Number of SL resource blocks (1-100) /// Number of SL resource blocks (1-100)
uint32_t N_SL_RB; uint32_t N_SL_RB;
/// prb-start (0-99) /// prb-start (0-99)
uint32_t prb_Start; uint32_t prb_Start;
...@@ -911,7 +911,7 @@ typedef struct { ...@@ -911,7 +911,7 @@ typedef struct {
// SLSCH Parameters // SLSCH Parameters
/// Number of Subbands (36.213 14.1.1.2) /// Number of Subbands (36.213 14.1.1.2)
uint32_t Nsb; uint32_t Nsb;
/// N_RB_HO (36.213 14.1.1.2) /// N_RB_HO (36.213 14.1.1.2)
uint32_t N_RB_HO; uint32_t N_RB_HO;
/// n_ss_PSSCH (36.211 9.2.4) /// n_ss_PSSCH (36.211 9.2.4)
...@@ -930,17 +930,16 @@ typedef struct { ...@@ -930,17 +930,16 @@ typedef struct {
uint32_t n_prime_PRB; uint32_t n_prime_PRB;
/// m_nprime_PRB_PSSCH (36.213 14.1.3) /// m_nprime_PRB_PSSCH (36.213 14.1.3)
uint32_t m_nprime_PRB_PSCCH; uint32_t m_nprime_PRB_PSCCH;
/// payload length /// payload length
int payload_length; int payload_length;
/// pointer to payload /// pointer to payload
uint8_t *payload; uint8_t *payload;
} SLSCH_t; } SLSCH_t;
typedef struct { typedef struct {
/// payload length /// payload length
int payload_length; int payload_length;
/// pointer to payload uint8_t payload[100];
uint8_t *payload;
} SLDCH_t; } SLDCH_t;
#define TTI_SYNC 0 #define TTI_SYNC 0
...@@ -954,13 +953,13 @@ typedef struct UE_tport_header_s { ...@@ -954,13 +953,13 @@ typedef struct UE_tport_header_s {
} UE_tport_header_t; } UE_tport_header_t;
typedef struct UE_tport_s { typedef struct UE_tport_s {
UE_tport_header_t header; UE_tport_header_t header;
union { union {
SLSS_t slss; SLSS_t slss;
SLDCH_t sldch; SLDCH_t sldch;
SLSCH_t slsch; SLSCH_t slsch;
}; };
uint8_t payload[1500]; uint8_t payload[1500];
} UE_tport_t; } UE_tport_t;
#endif #endif
......
...@@ -42,14 +42,13 @@ void generate_sldch(PHY_VARS_UE *ue,SLDCH_t *sldch,int frame_tx,int subframe_tx) ...@@ -42,14 +42,13 @@ void generate_sldch(PHY_VARS_UE *ue,SLDCH_t *sldch,int frame_tx,int subframe_tx)
pdu.header.packet_type = SLDCH; pdu.header.packet_type = SLDCH;
pdu.header.absSF = (frame_tx*10)+subframe_tx; pdu.header.absSF = (frame_tx*10)+subframe_tx;
memcpy((void*)&pdu.sldch,(void*)sldch,sizeof(SLDCH_t)-sizeof(uint8_t*));
AssertFatal(sldch->payload_length <=1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*), AssertFatal(sldch->payload_length <=1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*),
"SLDCH payload length > %d\n", "SLDCH payload length > %d\n",
1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*)); 1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*));
memcpy((void*)&pdu.payload[0], memcpy((void*)&pdu.sldch,
(void*)sldch->payload, (void*)sldch,
sldch->payload_length); sizeof(SLDCH_t));
LOG_I(PHY,"SLDCH configuration %d bytes, TBS payload %d bytes => %d bytes\n", LOG_I(PHY,"SLDCH configuration %d bytes, TBS payload %d bytes => %d bytes\n",
sizeof(SLDCH_t)-sizeof(uint8_t*), sizeof(SLDCH_t)-sizeof(uint8_t*),
...@@ -58,7 +57,7 @@ void generate_sldch(PHY_VARS_UE *ue,SLDCH_t *sldch,int frame_tx,int subframe_tx) ...@@ -58,7 +57,7 @@ void generate_sldch(PHY_VARS_UE *ue,SLDCH_t *sldch,int frame_tx,int subframe_tx)
multicast_link_write_sock(0, multicast_link_write_sock(0,
&pdu, &pdu,
sldch_header_len+sizeof(SLDCH_t)-sizeof(uint8_t*)+sldch->payload_length); sldch_header_len+sizeof(SLDCH_t));
} }
......
This diff is collapsed.
...@@ -117,7 +117,7 @@ void ue_init_mac(module_id_t module_idP) ...@@ -117,7 +117,7 @@ void ue_init_mac(module_id_t module_idP)
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING;
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING;
UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE;
UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer);
UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer);
UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange);
...@@ -463,7 +463,7 @@ ue_send_sdu( ...@@ -463,7 +463,7 @@ ue_send_sdu(
#ifdef DEBUG_HEADER_PARSING #ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] SDU %d : LCID %d, length %d\n",i,rx_lcids[i],rx_lengths[i]); LOG_D(MAC,"[UE] SDU %d : LCID %d, length %d\n",i,rx_lcids[i],rx_lengths[i]);
#endif #endif
if (rx_lcids[i] == CCCH) { if (rx_lcids[i] == CCCH) {
LOG_D(MAC,"[UE %d] rnti %x Frame %d : DLSCH -> DL-CCCH, RRC message (eNB %d, %d bytes)\n", LOG_D(MAC,"[UE %d] rnti %x Frame %d : DLSCH -> DL-CCCH, RRC message (eNB %d, %d bytes)\n",
...@@ -506,9 +506,9 @@ ue_send_sdu( ...@@ -506,9 +506,9 @@ ue_send_sdu(
rx_lengths[i], rx_lengths[i],
1, 1,
NULL); NULL);
} else if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1 )) { } else if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1 )) {
LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", module_idP, frameP,rx_lcids[i], eNB_index,rx_lengths[i]); LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", module_idP, frameP,rx_lcids[i], eNB_index,rx_lengths[i]);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG) #if defined(ENABLE_MAC_PAYLOAD_DEBUG)
...@@ -534,7 +534,7 @@ ue_send_sdu( ...@@ -534,7 +534,7 @@ ue_send_sdu(
payload_ptr+= rx_lengths[i]; payload_ptr+= rx_lengths[i];
} }
} // end if (payload_ptr != NULL) } // end if (payload_ptr != NULL)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
#if UE_TIMING_TRACE #if UE_TIMING_TRACE
stop_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu); stop_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu);
...@@ -1416,7 +1416,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf ...@@ -1416,7 +1416,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf
int highest_priority = 16; int highest_priority = 16;
int num_lcg_id_with_data = 0; int num_lcg_id_with_data = 0;
rlc_buffer_occupancy_t lcid_buffer_occupancy_old=0, lcid_buffer_occupancy_new=0; rlc_buffer_occupancy_t lcid_buffer_occupancy_old=0, lcid_buffer_occupancy_new=0;
LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n",
module_idP, frameP, subframe, buflen); module_idP, frameP, subframe, buflen);
...@@ -1919,7 +1919,7 @@ for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid ...@@ -1919,7 +1919,7 @@ for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid
#if UE_TIMING_TRACE #if UE_TIMING_TRACE
stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu);
#endif #endif
if (opt_enabled) { if (opt_enabled) {
trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0); trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0);
...@@ -2118,9 +2118,9 @@ ue_scheduler( ...@@ -2118,9 +2118,9 @@ ue_scheduler(
/* /*
if (lcid == DCCH) { if (lcid == DCCH) {
LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d Pending data for SRB1=%d for LCGID %d \n", LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d Pending data for SRB1=%d for LCGID %d \n",
module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]],
// UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); // UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]);
} }
*/ */
...@@ -2748,24 +2748,27 @@ SLSS_t *ue_get_slss(module_id_t Mod_id,int CC_id,frame_t frame_tx,sub_frame_t su ...@@ -2748,24 +2748,27 @@ SLSS_t *ue_get_slss(module_id_t Mod_id,int CC_id,frame_t frame_tx,sub_frame_t su
} }
SLDCH_t *ue_get_sldch(module_id_t Mod_id,int CC_id,frame_t frame_tx,sub_frame_t subframe_tx) { SLDCH_t *ue_get_sldch(module_id_t Mod_id,int CC_id,frame_t frame_tx,sub_frame_t subframe_tx) {
/* int sdu_length;
UE_MAC_INST *ue = &UE_mac_inst[Mod_id]; UE_MAC_INST *ue = &UE_mac_inst[Mod_id];
SLDCH_t *sldch = &UE_mac_inst[Mod_id].sldch; SLDCH_t *sldch = &UE_mac_inst[Mod_id].sldch;
LOG_I(MAC, "[ue_get_sldch]");
int sdu_length = mac_rrc_data_req(Mod_id, sldch->payload_length = mac_rrc_data_req(Mod_id,
CC_id, CC_id,
frame_tx, frame_tx,
SL_DISCOVERY, SL_DISCOVERY,
1, 1,
(char*)(ue->sldch_pdu.payload), //&UE_mac_inst[Mod_id].SL_Discovery[0].Tx_buffer.Payload[0], (char*)(sldch->payload), //&UE_mac_inst[Mod_id].SL_Discovery[0].Tx_buffer.Payload[0],
0, 0,
0, //eNB_indexP 0, //eNB_indexP
0); 0);
if (sdu_length >0 ) return (&ue->sldch); if (sldch->payload_length >0 ) {
LOG_I(MAC,"Got %d bytes from RRC for SLDCH @ %p\n",sldch->payload_length,sldch);
return (sldch);
}
else else
*/
return((SLDCH_t*)NULL); return((SLDCH_t*)NULL);
} }
...@@ -2807,7 +2810,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_ ...@@ -2807,7 +2810,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
ue->slsch_lcid = 3; ue->slsch_lcid = 3;
} }
} // we're not in the SCCH period } // we're not in the SCCH period
else if (((absSF & 3) == 0 ) && else if (((absSF & 3) == 0 ) &&
(ue->sltx_active == 1)) { // every 4th subframe, check for new data from RLC (ue->sltx_active == 1)) { // every 4th subframe, check for new data from RLC
// 10 PRBs, mcs 19 // 10 PRBs, mcs 19
int TBS = 4584/8; int TBS = 4584/8;
...@@ -2833,7 +2836,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_ ...@@ -2833,7 +2836,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
ue->slsch_lcid, ue->slsch_lcid,
req, req,
(char*)(ue->slsch_pdu.payload + sizeof(SLSCH_SUBHEADER_24_Bit_DST_LONG))); (char*)(ue->slsch_pdu.payload + sizeof(SLSCH_SUBHEADER_24_Bit_DST_LONG)));
// Notes: 1. hard-coded to 24-bit destination format for now // Notes: 1. hard-coded to 24-bit destination format for now
// 2. LCID hard-coded to 3 // 2. LCID hard-coded to 3
// 3. SRC/DST IDs with debug values // 3. SRC/DST IDs with debug values
...@@ -2844,7 +2847,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_ ...@@ -2844,7 +2847,7 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
LOG_I(MAC,"groupL2Id/destinationL2Id: 0x%08x \n",destL2Id); LOG_I(MAC,"groupL2Id/destinationL2Id: 0x%08x \n",destL2Id);
slsch->payload = (unsigned char*)ue->slsch_pdu.payload; slsch->payload = (unsigned char*)ue->slsch_pdu.payload;
if (sdu_length < 128) { if (sdu_length < 128) {
slsch->payload++; slsch->payload++;
SLSCH_SUBHEADER_24_Bit_DST_SHORT *shorth= (SLSCH_SUBHEADER_24_Bit_DST_SHORT *)slsch->payload; SLSCH_SUBHEADER_24_Bit_DST_SHORT *shorth= (SLSCH_SUBHEADER_24_Bit_DST_SHORT *)slsch->payload;
shorth->F=0; shorth->F=0;
...@@ -2890,6 +2893,6 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_ ...@@ -2890,6 +2893,6 @@ SLSCH_t *ue_get_slsch(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_
return(&ue->slsch); return(&ue->slsch);
} }
return(NULL); return(NULL);
} }
...@@ -102,7 +102,7 @@ mac_rrc_data_req( ...@@ -102,7 +102,7 @@ mac_rrc_data_req(
} }
// All even frames transmit SIB in SF 5 // All even frames transmit SIB in SF 5
AssertFatal(RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1 != 255, AssertFatal(RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1 != 255,
"[eNB %d] MAC Request for SIB1 and SIB1 not initialized\n",Mod_idP); "[eNB %d] MAC Request for SIB1 and SIB1 not initialized\n",Mod_idP);
if ((frameP%2) == 0) { if ((frameP%2) == 0) {
...@@ -312,7 +312,7 @@ mac_rrc_data_req( ...@@ -312,7 +312,7 @@ mac_rrc_data_req(
RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR);
return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR);
} }
if ((Srb_id & RAB_OFFSET) == BCCH_SI_BR){ // First SI message with SIB2/3 if ((Srb_id & RAB_OFFSET) == BCCH_SI_BR){ // First SI message with SIB2/3
memcpy(&buffer_pP[0], memcpy(&buffer_pP[0],
RC.rrc[Mod_idP]->carrier[CC_id].SIB23_BR, RC.rrc[Mod_idP]->carrier[CC_id].SIB23_BR,
...@@ -329,10 +329,11 @@ mac_rrc_data_req( ...@@ -329,10 +329,11 @@ mac_rrc_data_req(
LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size); LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size);
//TTN (for D2D) //TTN (for D2D)
if ((Srb_id & RAB_OFFSET) == SL_DISCOVERY){ if (Srb_id == SL_DISCOVERY && UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size > 0){
memcpy(&buffer_pP[0],&UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.Payload[0],UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size); memcpy(&buffer_pP[0],&UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.Payload[0],UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size);
uint8_t Ret_size=UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size; uint8_t Ret_size=UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size;
// msg("[RRC][UE %d] Sending SL_Discovery\n",Mod_id); LOG_I(RRC,"[UE %d] Sending SL_Discovery, size %d bytes\n",Mod_idP,Ret_size);
UE_rrc_inst[Mod_idP].SL_Discovery[eNB_index].Tx_buffer.payload_size = 0;
return(Ret_size); return(Ret_size);
} }
#endif #endif
...@@ -513,7 +514,7 @@ mac_rrc_data_ind( ...@@ -513,7 +514,7 @@ mac_rrc_data_ind(
} }
//TTN (for D2D) //TTN (for D2D)
if((srb_idP & RAB_OFFSET) == SL_DISCOVERY) { if(srb_idP == SL_DISCOVERY) {
decode_SL_Discovery_Message(&ctxt, eNB_indexP, sduP, sdu_lenP); decode_SL_Discovery_Message(&ctxt, eNB_indexP, sduP, sdu_lenP);
} }
...@@ -522,7 +523,7 @@ mac_rrc_data_ind( ...@@ -522,7 +523,7 @@ mac_rrc_data_ind(
} else { // This is an eNB } else { // This is an eNB
Srb_info = &RC.rrc[module_idP]->carrier[CC_id].Srb0; Srb_info = &RC.rrc[module_idP]->carrier[CC_id].Srb0;
LOG_D(RRC,"[eNB %d] Received SDU for CCCH on SRB %d\n",module_idP,Srb_info->Srb_id); LOG_D(RRC,"[eNB %d] Received SDU for CCCH on SRB %d\n",module_idP,Srb_info->Srb_id);
#if 0 //defined(ENABLE_ITTI) #if 0 //defined(ENABLE_ITTI)
{ {
MessageDef *message_p; MessageDef *message_p;
...@@ -740,7 +741,7 @@ void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index ...@@ -740,7 +741,7 @@ void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index
UE_rrc_inst[Mod_idP].Info[eNB_index].T310_cnt, UE_rrc_inst[Mod_idP].Info[eNB_index].T310_cnt,
UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt, UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt,
UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt); UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt);
#if defined(ENABLE_ITTI) #if defined(ENABLE_ITTI)
{ {
MessageDef *message_p; MessageDef *message_p;
...@@ -797,8 +798,8 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, ...@@ -797,8 +798,8 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP,
rrc_mac_remove_ue(Mod_instP,rntiP); rrc_mac_remove_ue(Mod_instP,rntiP);
} }
void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP, void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP,
const int CC_idP, const int CC_idP,
const frame_t frameP, const frame_t frameP,
const sub_frame_t subframeP, const sub_frame_t subframeP,
const rnti_t rntiP) const rnti_t rntiP)
......
...@@ -134,11 +134,9 @@ struct PC5SEstablishRsp{ ...@@ -134,11 +134,9 @@ struct PC5SEstablishRsp{
//example of PC5_DSICOVERY ANNOUNCEMENT (for testing only) //example of PC5_DSICOVERY ANNOUNCEMENT (for testing only)
typedef struct { typedef struct {
uint8_t msg_type; unsigned char bytes[29];
uint32_t discoveryGroupId; } __attribute__((__packed__)) PC5DiscoveryAnnouncement ;
//AnnouncerInfo
uint32_t proSeUEId;
} __attribute__((__packed__)) PC5DiscoveryAnnouncement;
struct sidelink_ctrl_element { struct sidelink_ctrl_element {
unsigned short type; unsigned short type;
...@@ -310,7 +308,7 @@ typedef struct uid_linear_allocator_s { ...@@ -310,7 +308,7 @@ typedef struct uid_linear_allocator_s {
#define PROTOCOL_RRC_CTXT_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_RRC_CTXT_FMT PROTOCOL_CTXT_FMT
#define PROTOCOL_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) #define PROTOCOL_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp)
/** @defgroup _rrc RRC /** @defgroup _rrc RRC
* @ingroup _oai2 * @ingroup _oai2
* @{ * @{
*/ */
...@@ -488,7 +486,7 @@ typedef struct SRB_INFO_TABLE_ENTRY_s { ...@@ -488,7 +486,7 @@ typedef struct SRB_INFO_TABLE_ENTRY_s {
SRB_INFO Srb_info; SRB_INFO Srb_info;
uint8_t Active; uint8_t Active;
uint8_t Status; uint8_t Status;
uint32_t Next_check_frame; uint32_t Next_check_frame;
} SRB_INFO_TABLE_ENTRY; } SRB_INFO_TABLE_ENTRY;
typedef struct MEAS_REPORT_LIST_s { typedef struct MEAS_REPORT_LIST_s {
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* \date 2010 - 2014 * \date 2010 - 2014
* \email navid.nikaein@eurecom.fr * \email navid.nikaein@eurecom.fr
* \version 1.0 * \version 1.0
*/ */
/** \addtogroup _rrc /** \addtogroup _rrc
* @{ * @{
...@@ -90,7 +90,7 @@ rrc_ue_decode_dcch( ...@@ -90,7 +90,7 @@ rrc_ue_decode_dcch(
); );
#ifdef Rel14 #ifdef Rel14
int decode_SL_DISCOVERY_Message( int decode_SL_Discovery_Message(
const protocol_ctxt_t* const ctxt_pP, const protocol_ctxt_t* const ctxt_pP,
const uint8_t eNB_index, const uint8_t eNB_index,
uint8_t* const Sdu, uint8_t* const Sdu,
...@@ -291,7 +291,7 @@ rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration( ...@@ -291,7 +291,7 @@ rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration(
const uint8_t ho_state const uint8_t ho_state
); );
void void
rrc_eNB_reconfigure_DRBs (const protocol_ctxt_t* const ctxt_pP, rrc_eNB_reconfigure_DRBs (const protocol_ctxt_t* const ctxt_pP,
rrc_eNB_ue_context_t* ue_context_pP); rrc_eNB_ue_context_t* ue_context_pP);
...@@ -396,14 +396,14 @@ mac_rrc_data_ind( ...@@ -396,14 +396,14 @@ mac_rrc_data_ind(
void mac_sync_ind( module_id_t Mod_instP, uint8_t status); void mac_sync_ind( module_id_t Mod_instP, uint8_t status);
void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP,
const int CC_id, const int CC_id,
const frame_t frameP, const frame_t frameP,
const sub_frame_t subframeP, const sub_frame_t subframeP,
const rnti_t rnti); const rnti_t rnti);
void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP, void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP,
const int CC_id, const int CC_id,
const frame_t frameP, const frame_t frameP,
const sub_frame_t subframeP, const sub_frame_t subframeP,
const rnti_t rnti); const rnti_t rnti);
......
This diff is collapsed.
...@@ -162,7 +162,7 @@ PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, ...@@ -162,7 +162,7 @@ PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
ue = (PHY_VARS_UE *)malloc(sizeof(PHY_VARS_UE)); ue = (PHY_VARS_UE *)malloc(sizeof(PHY_VARS_UE));
memset(ue,0,sizeof(PHY_VARS_UE)); memset(ue,0,sizeof(PHY_VARS_UE));
memcpy(&(ue->frame_parms), frame_parms, sizeof(LTE_DL_FRAME_PARMS)); memcpy(&(ue->frame_parms), frame_parms, sizeof(LTE_DL_FRAME_PARMS));
} }
else ue = PHY_vars_UE_g[UE_id][0]; else ue = PHY_vars_UE_g[UE_id][0];
...@@ -229,11 +229,11 @@ void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in) { ...@@ -229,11 +229,11 @@ void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in) {
int ret; int ret;
LOG_I(PHY,"UE : Calling Layer 2 for initialization\n"); LOG_I(PHY,"UE : Calling Layer 2 for initialization\n");
l2_init_ue(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL, l2_init_ue(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL,
0,// cba_group_active 0,// cba_group_active
0); // HO flag 0); // HO flag
for (inst=0;inst<nb_inst;inst++) { for (inst=0;inst<nb_inst;inst++) {
LOG_I(PHY,"Initializing memory for UE instance %d (%p)\n",inst,PHY_vars_UE_g[inst]); LOG_I(PHY,"Initializing memory for UE instance %d (%p)\n",inst,PHY_vars_UE_g[inst]);
...@@ -331,7 +331,7 @@ static void *UE_thread_synch(void *arg) ...@@ -331,7 +331,7 @@ static void *UE_thread_synch(void *arg)
// this thread priority must be lower that the main acquisition thread // this thread priority must be lower that the main acquisition thread
sprintf(threadname, "sync UE %d\n", UE->Mod_id); sprintf(threadname, "sync UE %d\n", UE->Mod_id);
init_thread(100000, 500000, FIFO_PRIORITY-1, &cpuset, threadname); init_thread(100000, 500000, FIFO_PRIORITY-1, &cpuset, threadname);
printf("starting UE synch thread (IC %d)\n",UE->proc.instance_cnt_synch); printf("starting UE synch thread (IC %d)\n",UE->proc.instance_cnt_synch);
ind = 0; ind = 0;
found = 0; found = 0;
...@@ -352,7 +352,7 @@ static void *UE_thread_synch(void *arg) ...@@ -352,7 +352,7 @@ static void *UE_thread_synch(void *arg)
ind++; ind++;
} while (ind < sizeof(eutra_bands) / sizeof(eutra_bands[0])); } while (ind < sizeof(eutra_bands) / sizeof(eutra_bands[0]));
if (found == 0) { if (found == 0) {
exit_fun("Can't find EUTRA band for frequency"); exit_fun("Can't find EUTRA band for frequency");
return &UE_thread_synch_retval; return &UE_thread_synch_retval;
...@@ -365,7 +365,7 @@ static void *UE_thread_synch(void *arg) ...@@ -365,7 +365,7 @@ static void *UE_thread_synch(void *arg)
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = UE->frame_parms.dl_CarrierFreq; openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = UE->frame_parms.dl_CarrierFreq;
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = UE->frame_parms.ul_CarrierFreq; openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = UE->frame_parms.ul_CarrierFreq;
openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1; openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
if (uplink_frequency_offset[CC_id][i] != 0) // if (uplink_frequency_offset[CC_id][i] != 0) //
openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_FDD; openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_FDD;
else //FDD else //FDD
openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_TDD; openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_TDD;
...@@ -387,15 +387,15 @@ static void *UE_thread_synch(void *arg) ...@@ -387,15 +387,15 @@ static void *UE_thread_synch(void *arg)
} }
} }
while (sync_var<0) while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex); pthread_cond_wait(&sync_cond, &sync_mutex);
pthread_mutex_unlock(&sync_mutex); pthread_mutex_unlock(&sync_mutex);
printf("Started device, unlocked sync_mutex (UE_sync_thread)\n"); printf("Started device, unlocked sync_mutex (UE_sync_thread)\n");
if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) {
LOG_E(HW,"Could not start the device\n"); LOG_E(HW,"Could not start the device\n");
oai_exit=1; oai_exit=1;
} }
while (oai_exit==0) { while (oai_exit==0) {
...@@ -404,13 +404,13 @@ static void *UE_thread_synch(void *arg) ...@@ -404,13 +404,13 @@ static void *UE_thread_synch(void *arg)
// the thread waits here most of the time // the thread waits here most of the time
pthread_cond_wait( &UE->proc.cond_synch, &UE->proc.mutex_synch ); pthread_cond_wait( &UE->proc.cond_synch, &UE->proc.mutex_synch );
AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), "");
switch (sync_mode) { switch (sync_mode) {
case pss: case pss:
LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset); LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset); lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
current_offset += 20000000; // increase by 20 MHz current_offset += 20000000; // increase by 20 MHz
if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) { if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) {
current_band++; current_band++;
current_offset=0; current_offset=0;
...@@ -434,7 +434,7 @@ static void *UE_thread_synch(void *arg) ...@@ -434,7 +434,7 @@ static void *UE_thread_synch(void *arg)
} }
break; break;
case pbch: case pbch:
#if DISABLE_LOG_X #if DISABLE_LOG_X
...@@ -770,8 +770,8 @@ void ue_stub_rx_handler(unsigned int num_bytes, char *rx_buffer) { ...@@ -770,8 +770,8 @@ void ue_stub_rx_handler(unsigned int num_bytes, char *rx_buffer) {
wakeup_thread(&UE->timer_mutex,&UE->timer_cond,&UE->instance_cnt_timer,"timer_thread"); wakeup_thread(&UE->timer_mutex,&UE->timer_cond,&UE->instance_cnt_timer,"timer_thread");
break; break;
case SLSCH: case SLSCH:
LOG_I(PHY,"Emulator SFN.SF %d.%d, Got SLSCH packet\n",emulator_absSF/10,emulator_absSF%10); LOG_I(PHY,"Emulator SFN.SF %d.%d, Got SLSCH packet\n",emulator_absSF/10,emulator_absSF%10);
LOG_I(PHY,"Received %d bytes on UE-UE link for SFN.SF %d.%d, sending SLSCH payload (%d bytes) to MAC\n",num_bytes, LOG_I(PHY,"Received %d bytes on UE-UE link for SFN.SF %d.%d, sending SLSCH payload (%d bytes) to MAC\n",num_bytes,
pdu->header.absSF/10,pdu->header.absSF%10, pdu->header.absSF/10,pdu->header.absSF%10,
...@@ -779,7 +779,7 @@ void ue_stub_rx_handler(unsigned int num_bytes, char *rx_buffer) { ...@@ -779,7 +779,7 @@ void ue_stub_rx_handler(unsigned int num_bytes, char *rx_buffer) {
printf("SLSCH:"); printf("SLSCH:");
for (int i=0;i<sizeof(SLSCH_t);i++) printf("%x ",((uint8_t*)slsch)[i]); for (int i=0;i<sizeof(SLSCH_t);i++) printf("%x ",((uint8_t*)slsch)[i]);
printf("\n"); printf("\n");
ue_send_sl_sdu(0, ue_send_sl_sdu(0,
0, 0,
pdu->header.absSF/10, pdu->header.absSF/10,
...@@ -980,9 +980,9 @@ static void *UE_phy_stub_thread_rxn_txnp4(void *arg) { ...@@ -980,9 +980,9 @@ static void *UE_phy_stub_thread_rxn_txnp4(void *arg) {
stop_meas(&UE->generic_stat); stop_meas(&UE->generic_stat);
#endif #endif
// Prepare the future Tx data // Prepare the future Tx data
if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) ||
(UE->frame_parms.frame_type == FDD) ) (UE->frame_parms.frame_type == FDD) )
if (UE->mode != loop_through_memory){ if (UE->mode != loop_through_memory){
...@@ -1473,14 +1473,14 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) ...@@ -1473,14 +1473,14 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg)
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
rf_map = &phy_vars_ue[CC_id]->rf_map; rf_map = &phy_vars_ue[CC_id]->rf_map;
AssertFatal( phy_vars_ue[CC_id] !=0, ""); AssertFatal( phy_vars_ue[CC_id] !=0, "");
frame_parms = &(phy_vars_ue[CC_id]->frame_parms); frame_parms = &(phy_vars_ue[CC_id]->frame_parms);
// replace RX signal buffers with mmaped HW versions // replace RX signal buffers with mmaped HW versions
rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) );
txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) ); txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) );
for (i=0; i<frame_parms->nb_antennas_rx; i++) { for (i=0; i<frame_parms->nb_antennas_rx; i++) {
LOG_I(PHY, "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", LOG_I(PHY, "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",
CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i );
...@@ -1488,7 +1488,7 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) ...@@ -1488,7 +1488,7 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg)
rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD
} }
for (i=0; i<frame_parms->nb_antennas_tx; i++) { for (i=0; i<frame_parms->nb_antennas_tx; i++) {
LOG_I(PHY, "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", LOG_I(PHY, "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",
CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i );
...@@ -1496,7 +1496,7 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) ...@@ -1496,7 +1496,7 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg)
txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i]; phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i];
} }
// rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x] // rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x]
// txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x] // txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x]
// be careful when releasing memory! // be careful when releasing memory!
...@@ -1520,7 +1520,7 @@ static void* timer_thread( void* param ) { ...@@ -1520,7 +1520,7 @@ static void* timer_thread( void* param ) {
UE = PHY_vars_UE_g[0][0]; UE = PHY_vars_UE_g[0][0];
double t_diff; double t_diff;
int external_timer = 0; int external_timer = 0;
wait_sync("timer_thread"); wait_sync("timer_thread");
//pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL); //pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL);
...@@ -1582,10 +1582,10 @@ static void* timer_thread( void* param ) { ...@@ -1582,10 +1582,10 @@ static void* timer_thread( void* param ) {
UE_tport_t pdu; UE_tport_t pdu;
pdu.header.packet_type = TTI_SYNC; pdu.header.packet_type = TTI_SYNC;
pdu.header.absSF = (timer_frame*10)+timer_subframe; pdu.header.absSF = (timer_frame*10)+timer_subframe;
multicast_link_write_sock(0, multicast_link_write_sock(0,
&pdu, &pdu,
sizeof(UE_tport_header_t)); sizeof(UE_tport_header_t));
} }
else { else {
wait_on_condition(&UE->timer_mutex,&UE->timer_cond,&UE->instance_cnt_timer,"timer_thread"); wait_on_condition(&UE->timer_mutex,&UE->timer_cond,&UE->instance_cnt_timer,"timer_thread");
...@@ -1640,11 +1640,3 @@ int init_timer_thread(void) { ...@@ -1640,11 +1640,3 @@ int init_timer_thread(void) {
pthread_create(&phy_stub_ticking->pthread_timer, NULL, &timer_thread, NULL); pthread_create(&phy_stub_ticking->pthread_timer, NULL, &timer_thread, NULL);
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment