Commit 2e8e9b7d authored by cig's avatar cig

UE power measurements fixes

- RA preamble power computation review
- RSRP review
- PCmax computation
- Pathloss computation
- cleanup of reference to LTE
- minor fixes
parent cd36314d
......@@ -89,6 +89,7 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
uint8_t slot);
void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
uint8_t gNB_index,
UE_nr_rxtx_proc_t *proc,
uint8_t slot,
uint8_t abstraction_flag);
......
......@@ -30,7 +30,7 @@
* \warning
*/
#include "nr-softmodem-common.h"
#include "executables/softmodem-common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/phy_extern_nr_ue.h"
#include "common/utils/LOG/log.h"
......@@ -45,25 +45,41 @@
//#define DEBUG_MEAS_UE
//#define DEBUG_RANK_EST
// Returns the pathloss in dBm for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
// Assumptions:
// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE
// Measurement units:
// - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm)
int16_t get_nr_PL(uint8_t Mod_id, uint8_t CC_id, uint8_t gNB_index){
PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
int16_t pathloss;
/*
if (ue->frame_parms.mode1_flag == 1)
RSoffset = 6;
else
RSoffset = 3;
*/
if (get_softmodem_params()->do_ra){
long referenceSignalPower = ue->nrUE_config.ssb_config.ss_pbch_power;
double rsrp_dBm = 10*log10(ue->measurements.rsrp[gNB_index]) + 30 - ue->rx_total_gain_dB;
pathloss = (int16_t)(10*log10(pow(10, (double)(referenceSignalPower)/10) - pow(10, (double)(rsrp_dBm)/10)));
LOG_D(MAC, "In %s: pathloss %d dBm, UE RX total gain %d dB, referenceSignalPower %ld dBm (%f mW), RSRP %f dBm (%f mW)\n",
__FUNCTION__,
pathloss,
ue->rx_total_gain_dB,
referenceSignalPower,
pow(10, referenceSignalPower/10),
rsrp_dBm,
pow(10, rsrp_dBm/10));
} else {
/* LOG_D(PHY,"get_nr_PL : rsrp %f dBm/RE (%f), eNB power %d dBm/RE\n",
(1.0*dB_fixed_times10(ue->measurements.rsrp[eNB_index])-(10.0*ue->rx_total_gain_dB))/10.0,
10*log10((double)ue->measurements.rsrp[eNB_index]),
ue->frame_parms.pdsch_config_common.referenceSignalPower);*/
pathloss = ((int16_t)(((10*ue->rx_total_gain_dB) - dB_fixed_times10(ue->measurements.rsrp[gNB_index]))/10));
}
return pathloss;
return((int16_t)(((10*ue->rx_total_gain_dB) - dB_fixed_times10(ue->measurements.rsrp[gNB_index]))/10));
// dB_fixed_times10(RSoffset*12*ue_g[Mod_id][CC_id]->frame_parms.N_RB_DL) +
//(ue->frame_parms.pdsch_config_common.referenceSignalPower*10))/10));
}
uint32_t get_nr_rx_total_gain_dB (module_id_t Mod_id,uint8_t CC_id)
......@@ -180,74 +196,74 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
#endif
}
// This function implements:
// - SS reference signal received power (SS-RSRP) as per clause 5.1.1 of 3GPP TS 38.215 version 16.3.0 Release 16
// - no Layer 3 filtering implemented (no filterCoefficient provided from RRC)
// Todo:
// - Layer 3 filtering according to clause 5.5.3.2 of 3GPP TS 38.331 version 16.2.0 Release 16
// Measurement units:
// - RSRP: W (dBW)
// - RX Gain dB
void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
uint8_t gNB_id,
UE_nr_rxtx_proc_t *proc,
uint8_t slot,
uint8_t abstraction_flag)
{
int aarx,rb, symbol_offset;
int16_t *rxF;
uint16_t Nid_cell = ue->frame_parms.Nid_cell;
uint8_t eNB_offset=0,l,nushift;
uint16_t off,nb_rb;
// NR_UE_MAC_INST_t *mac = get_mac_inst(0);
int **rxdataF=ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF;
nushift = ue->frame_parms.Nid_cell%4;
ue->frame_parms.nushift = nushift;
int aarx;
int nb_re;
int k_start = 55;
int k_end = 183;
unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
uint8_t l_sss = ue->symbol_offset + 2;
symbol_offset = ue->frame_parms.ofdm_symbol_size*((ue->symbol_offset+1)%(ue->frame_parms.symbols_per_slot));
if (ssb_offset>= ue->frame_parms.ofdm_symbol_size){
ue->measurements.rsrp[eNB_offset] = 0;
ssb_offset -= ue->frame_parms.ofdm_symbol_size;
//if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){
nb_rb = 20;
//} else{
// LOG_E(PHY,"report quantity not supported \n");
//}
}
ue->measurements.rsrp[gNB_id] = 0;
if (abstraction_flag == 0) {
for (l=0; l<1; l++) {
LOG_D(PHY, "In %s: [UE %d] slot %d l_sss %d ssb_offset %d\n", __FUNCTION__, ue->Mod_id, slot, l_sss, ssb_offset);
LOG_D(PHY,"[UE %d] slot %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, l %d)\n",ue->Mod_id,slot,Nid_cell,nushift,
eNB_offset,l);
nb_re = 0;
for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+ssb_offset+nushift)];
off = 0;
for (aarx = 0; aarx < ue->frame_parms.nb_antennas_rx; aarx++) {
if (l==0) {
for (rb=0; rb<nb_rb; rb++) {
int16_t *rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aarx][(l_sss*ue->frame_parms.ofdm_symbol_size) + ssb_offset];
ue->measurements.rsrp[eNB_offset] += (((int32_t)(rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1]));
//printf("rb %d, off %d : %d\n",rb,off,((((int32_t)rxF[off])*rxF[off])+((int32_t)(rxF[off+1])*rxF[off+1])));
for(int k = k_start; k < k_end; k++){
#ifdef DEBUG_MEAS_UE
LOG_I(PHY, "In %s rxF_sss %d %d\n", __FUNCTION__, rxF_sss[k*2], rxF_sss[k*2 + 1]);
#endif
ue->measurements.rsrp[gNB_id] += (((int32_t)rxF_sss[k*2]*rxF_sss[k*2]) + ((int32_t)rxF_sss[k*2 + 1]*rxF_sss[k*2 + 1]));
nb_re++;
off = (off+4) % ue->frame_parms.ofdm_symbol_size;
}
}
}
}
ue->measurements.rsrp[eNB_offset]/=nb_rb;
ue->measurements.rsrp[gNB_id] /= nb_re;
} else {
ue->measurements.rsrp[eNB_offset] = -93 ;
}
ue->measurements.rsrp[gNB_id] = -93;
}
if (eNB_offset == 0)
ue->measurements.rsrp_filtered[gNB_id] = ue->measurements.rsrp[gNB_id];
LOG_D(PHY,"[UE %d] slot %d RSRP Measurements (idx %d, Cell id %d) => rsrp: %3.1f dBm/RE (%d)\n",
LOG_D(PHY, "In %s: [UE %d] slot %d SS-RSRP: %3.1f dBm/RE (%d W)\n",
__FUNCTION__,
ue->Mod_id,
slot,eNB_offset,
(eNB_offset>0) ? ue->measurements.adj_cell_id[eNB_offset-1] : ue->frame_parms.Nid_cell,
10*log10(ue->measurements.rsrp[eNB_offset])-ue->rx_total_gain_dB,
ue->measurements.rsrp[eNB_offset]);
slot,
10*log10(ue->measurements.rsrp[gNB_id]) + 30 - ue->rx_total_gain_dB,
ue->measurements.rsrp[gNB_id]);
}
......
This diff is collapsed.
......@@ -232,8 +232,8 @@ typedef struct {
uint8_t RA_SCALING_FACTOR_BI;
/// Indicating whether it is 2-step or 4-step RA
uint8_t RA_TYPE;
///
uint8_t RA_PCMAX;
/// UE configured maximum output power
int RA_PCMAX;
/// Corresponding RA-RNTI for UL-grant
uint16_t ra_RNTI;
/// Pointer to Msg3 payload for UL-grant
......
......@@ -1754,9 +1754,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
#endif
}
//if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){
nr_ue_rsrp_measurements(ue,proc,nr_slot_rx,0);
//}
nr_ue_rsrp_measurements(ue, gNB_id, proc, nr_slot_rx, 0);
if ((ue->decode_MIB == 1) && slot_pbch) {
......@@ -2139,7 +2137,8 @@ uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue,
void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) {
int frame_tx = proc->frame_tx, nr_slot_tx = proc->nr_slot_tx, prach_power; // tx_amp
uint16_t pathloss;
int16_t pathloss;
int16_t ra_preamble_rx_power;
uint8_t mod_id = ue->Mod_id;
UE_MODE_t UE_mode = get_nrUE_mode(mod_id, ue->CC_id, gNB_id);
NR_PRACH_RESOURCES_t * prach_resources = ue->prach_resources[gNB_id];
......@@ -2165,17 +2164,14 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
if (ue->prach_resources[gNB_id] != NULL && nr_prach == 1 && prach_resources->init_msg1) {
pathloss = get_nr_PL(mod_id, ue->CC_id, gNB_id);
ue->tx_power_dBm[nr_slot_tx] = prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER + pathloss;
LOG_I(PHY,"[UE %d][RAPROC] Frame %d, nr_slot_tx %d : Generating PRACH, preamble %d, PL %d, P0_PRACH %d, TARGET_RECEIVED_POWER %d dBm, RA-RNTI %x\n",
ra_preamble_rx_power = (int16_t)(10*log10(pow(10, (double)(prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER)/10) + pow(10, (double)(pathloss)/10)));
ue->tx_power_dBm[nr_slot_tx] = min(nr_get_Pcmax(ue->Mod_id), ra_preamble_rx_power);
LOG_I(PHY,"[UE %d][RAPROC][%d.%d]: Generating PRACH Msg1 (preamble index %d, TX power PRACH %d dBm, RA-RNTI %x)\n",
ue->Mod_id,
frame_tx,
nr_slot_tx,
prach_resources->ra_PreambleIndex,
pathloss,
ue->tx_power_dBm[nr_slot_tx],
prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER,
prach_resources->ra_RNTI);
//ue->tx_total_RE[nr_slot_tx] = 96; // todo
......@@ -2195,28 +2191,20 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT);
LOG_D(PHY, "[UE %d][RAPROC][%d.%d]: PRACH PL %d dB, TX power %d dBm, digital power %d dB (amp %d)\n",
LOG_D(PHY, "In %s: [UE %d][RAPROC][%d.%d]: Generated PRACH Msg1 (PL %d dBm, ra_PREAMBLE_RECEIVED_TARGET_POWER %d dBm, TX power PRACH %d dBm, digital power %d dBW (amp %d) prach_cnt %d)\n",
__FUNCTION__,
ue->Mod_id,
proc->frame_rx,
proc->nr_slot_tx,
pathloss,
prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER,
ue->tx_power_dBm[nr_slot_tx],
dB_fixed(prach_power),
ue->prach_vars[gNB_id]->amp);
ue->prach_vars[gNB_id]->amp,
ue->prach_cnt);
nr_Msg1_transmitted(ue->Mod_id, ue->CC_id, frame_tx, gNB_id);
LOG_I(PHY,"[UE %d][RAPROC] Frame %d, nr_slot_tx %d: Generated PRACH Msg1 (gNB %d) preamble index %d for UL, TX power %d dBm (PL %d dB) \n",
ue->Mod_id,
frame_tx,
nr_slot_tx,
gNB_id,
prach_resources->ra_PreambleIndex,
ue->tx_power_dBm[nr_slot_tx],
pathloss);
LOG_D(PHY,"[UE %d] frame %d nr_slot_tx %d : prach_cnt %d\n", ue->Mod_id, frame_tx, nr_slot_tx, ue->prach_cnt);
ue->prach_cnt++;
if (ue->prach_cnt == 3)
......
......@@ -189,6 +189,11 @@ int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t m
*/
int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_format);
/** \brief Function to compute configured maximum output power according to clause 6.2.4 of 3GPP TS 38.101-1 version 16.5.0 Release 16
@param Mod_id Module id of UE
*/
long nr_get_Pcmax(module_id_t mod_id);
/* Random Access */
/* \brief This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211 tables 6.3.3.2.x
......
......@@ -30,10 +30,12 @@
*/
#include "PHY/defs_nr_common.h"
//#include "PHY/impl_defs_top.h"
#include "mac_defs.h"
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
#include "LAYER2/NR_MAC_UE/mac_proto.h"
#include "NR_P-Max.h"
/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */
int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_format){
......@@ -133,7 +135,13 @@ int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_forma
return 0;
}
/* TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration */
// TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration
// Measurement units:
// - preambleReceivedTargetPower dBm (-202..-60, 2 dBm granularity)
// - delta_preamble dB
// - RA_PREAMBLE_POWER_RAMPING_STEP dB
// - POWER_OFFSET_2STEP_RA dB
// returns receivedTargerPower in dBm
int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t mod_id, uint8_t CC_id){
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
......@@ -153,6 +161,8 @@ int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t m
receivedTargerPower = preambleReceivedTargetPower + delta_preamble + (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP + prach_resources->POWER_OFFSET_2STEP_RA;
LOG_D(MAC, "In %s: receivedTargerPower is %d dBm \n", __FUNCTION__, receivedTargerPower);
return receivedTargerPower;
}
......@@ -175,3 +185,81 @@ void get_num_re_dmrs(nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
*nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data;
}
// Implementation of 6.2.4 Configured ransmitted power
// 3GPP TS 38.101-1 version 16.5.0 Release 16
// -
// The UE is allowed to set its configured maximum output power PCMAX,f,c for carrier f of serving cell c in each slot.
// The configured maximum output power PCMAX,f,c is set within the following bounds: PCMAX_L,f,c <= PCMAX,f,c <= PCMAX_H,f,c
// -
// Measurement units:
// - p_max: dBm
// - delta_TC_c: dB
// - P_powerclass: dBm
// - delta_P_powerclass: dB
// - MPR_c: dB
// - delta_MPR_c: dB
// - delta_T_IB_c dB
// - delta_rx_SRS dB
// note:
// - Assuming:
// -- Powerclass 3 capable UE (which is default power class unless otherwise stated)
// -- Maximum power reduction (MPR_c) for power class 3, QPSK, inner RB allocations
// -- no additional MPR (A_MPR_c)
// todo:
// - in current implementation delta_P_powerclass is not handling power classes different from 3
long nr_get_Pcmax(module_id_t mod_id){
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
uint32_t band = *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
NR_P_Max_t p_max = 0;
uint8_t P_powerclass = 23;
uint8_t delta_P_powerclass = 0;
uint8_t MPR_c = 1.5;
uint8_t delta_MPR_c = 0;
uint8_t A_MPR_c = 0;
uint8_t delta_T_IB_c = 0;
uint8_t delta_TC_c = 0;
uint8_t delta_rx_SRS = 0;
uint8_t P_MPR_c = 0;
long P_cmax_l = 0;
long P_cmax_h = 0;
long P_cmax = 0;
if (band == 28 && mac->phy_config.config_req.carrier_config.uplink_bandwidth == 30){
delta_MPR_c = 0.5;
}
if (mac->scg->spCellConfig->spCellConfigDedicated->uplinkConfig->ext1){
if (*mac->scg->spCellConfig->spCellConfigDedicated->uplinkConfig->ext1->powerBoostPi2BPSK == 1){
// TbD: assuming power class 3 capable UE operating in TDD bands n40, n41, n77, n78, and n79 with Pi/2 BPSK modulation
delta_P_powerclass = -3;
p_max += 3;
}
}
if (mac->scc->uplinkConfigCommon->frequencyInfoUL->p_Max){
p_max += *mac->scc->uplinkConfigCommon->frequencyInfoUL->p_Max;
LOG_D(MAC, "In %s maximum UL transmission power p_max is %ld dBm \n", __FUNCTION__, p_max);
P_cmax_l = min(p_max - delta_TC_c, (P_powerclass - delta_P_powerclass) - max(max(MPR_c + delta_MPR_c, A_MPR_c) + delta_T_IB_c + delta_TC_c + delta_rx_SRS, P_MPR_c));
P_cmax_h = min(p_max, P_powerclass - delta_P_powerclass);
} else {
P_cmax_l = (P_powerclass - delta_P_powerclass) - max(max(MPR_c + delta_MPR_c, A_MPR_c) + delta_T_IB_c + delta_TC_c + delta_rx_SRS, P_MPR_c);
P_cmax_h = P_powerclass - delta_P_powerclass;
}
P_cmax = (P_cmax_h + P_cmax_l) / 2;
LOG_D(MAC, "In %s configured maximum output power: %ld dBm <= PCMAX %ld dBm <= %ld dBm \n", __FUNCTION__, P_cmax_l, P_cmax, P_cmax_h);
return P_cmax;
}
\ No newline at end of file
......@@ -68,13 +68,14 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac);
// to Random Access type as specified in clause 5.1.1a (3GPP TS 38.321 version 16.2.1 Release 16)
// todo:
// - check if carrier to use is explicitly signalled then do (1) RA CARRIER SELECTION (SUL, NUL) (2) set PCMAX (currently hardcoded to 0)
void init_RA(NR_PRACH_RESOURCES_t *prach_resources,
void init_RA(module_id_t mod_id,
NR_PRACH_RESOURCES_t *prach_resources,
NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon,
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric,
NR_RACH_ConfigDedicated_t *rach_ConfigDedicated) {
prach_resources->RA_PREAMBLE_BACKOFF = 0;
prach_resources->RA_PCMAX = 0;
prach_resources->RA_PCMAX = nr_get_Pcmax(mod_id);
prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1;
prach_resources->POWER_OFFSET_2STEP_RA = 0;
......@@ -252,7 +253,7 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t
if (prach_resources->RA_TYPE == RA_4STEP){
if (scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble){
deltaPreamble_Msg3 = *scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble;
deltaPreamble_Msg3 = (*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble) * 2; // dB
LOG_D(MAC, "In %s: deltaPreamble_Msg3 set to %ld\n", __FUNCTION__, deltaPreamble_Msg3);
}
......@@ -543,7 +544,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
RA_backoff_cnt = 0;
Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
init_RA(prach_resources, setup, rach_ConfigGeneric, rach_ConfigDedicated);
init_RA(mod_id, prach_resources, setup, rach_ConfigGeneric, rach_ConfigDedicated);
prach_resources->Msg3 = payload;
nr_get_RA_window(mac);
......@@ -614,7 +615,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
RA_backoff_cnt = rand() % (prach_resources->RA_PREAMBLE_BACKOFF + 1);
prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP << 1; // 2 dB increment
prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += 2; // 2 dB increment
prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(prach_resources, mod_id, CC_id);
} else {
......
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