Commit 102a76fd authored by rmagueta's avatar rmagueta

Merge remote-tracking branch 'origin/develop' into develop-NR_SA_F1AP_5GRECORDS

# Conflicts:
#	openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
#	openair2/GNB_APP/MACRLC_nr_paramdef.h
#	openair2/LAYER2/NR_MAC_gNB/config.c
#	openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
#	openair2/NR_PHY_INTERFACE/NR_IF_Module.c
parents ad0be5b1 cf1822be
#!/bin/bash
while true
do
echo "gNB will be started automatically..."
sleep 1
sudo .././cmake_targets/ran_build/build/nr-softmodem -E -O ../targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
done
...@@ -230,6 +230,7 @@ MACRLCs = ( ...@@ -230,6 +230,7 @@ MACRLCs = (
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
ulsch_max_slots_inactivity = 1;
} }
); );
......
...@@ -211,6 +211,7 @@ MACRLCs = ( ...@@ -211,6 +211,7 @@ MACRLCs = (
num_cc = 1; num_cc = 1;
tr_s_preference = "local_L1"; tr_s_preference = "local_L1";
tr_n_preference = "local_RRC"; tr_n_preference = "local_RRC";
ulsch_max_slots_inactivity = 1;
} }
); );
......
#this is a configuration file
#used to build real time processing statistics
#for 5G NR phy test (gNB terminate)
Title : Processing Time (us)
ColNames :
- Metric
- Average
- Max
- Average vs Reference Deviation (Reference Value ; Acceptability Threshold)
Ref :
feprx : 60.0
feptx_prec : 8.0
feptx_ofdm : 85.0
feptx_total : 75.0
L1 Tx processing : 300.0
DLSCH encoding : 230.0
L1 Rx processing : 175.0
PUSCH inner-receiver : 100.0
PUSCH decoding : 140.0
DL & UL scheduling timing stats : 15.0
UL Indication : 20.0
Threshold :
feprx : 1.25
feptx_prec : 1.25
feptx_ofdm : 1.25
feptx_total : 1.25
L1 Tx processing : 1.25
DLSCH encoding : 1.25
L1 Rx processing : 1.25
PUSCH inner-receiver : 1.25
PUSCH decoding : 1.25
DL & UL scheduling timing stats : 1.25
UL Indication : 1.25
...@@ -453,6 +453,37 @@ class HTMLManagement(): ...@@ -453,6 +453,37 @@ class HTMLManagement():
self.htmlFile.write(' </tr>\n') self.htmlFile.write(' </tr>\n')
self.htmlFile.close() self.htmlFile.close()
#for the moment it is limited to 4 columns, to be made generic later
def CreateHtmlDataLogTable(self, DataLog):
if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
return
self.htmlFile = open('test_results.html', 'a')
# TabHeader
self.htmlFile.write(' <tr bgcolor = "#F0F0F0" >\n')
self.htmlFile.write(' <td colspan=' + str(5+self.htmlUEConnected) + '><b> ---- ' + DataLog['Title'] + ' ---- </b></td>\n')
self.htmlFile.write(' </tr>\n')
self.htmlFile.write(' <tr bgcolor = "#33CCFF" >\n')
self.htmlFile.write(' <th colspan="3">'+ DataLog['ColNames'][0] +'</th>\n')
self.htmlFile.write(' <th>' + DataLog['ColNames'][1] + '</th>\n')
self.htmlFile.write(' <th>' + DataLog['ColNames'][2] + '</th>\n')
self.htmlFile.write(' <th colspan=' + str(1+self.htmlUEConnected) + '>'+ DataLog['ColNames'][3] +'</th>\n')
self.htmlFile.write(' </tr>\n')
for k in DataLog['Data']:
# TestRow
self.htmlFile.write(' <tr>\n')
self.htmlFile.write(' <td colspan="3" bgcolor = "lightcyan" >' + k + ' </td>\n')
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + DataLog['Data'][k][0] + ' </td>\n')
self.htmlFile.write(' <td bgcolor = "lightcyan" >' + DataLog['Data'][k][1] + ' </td>\n')
if float(DataLog['Data'][k][2])> DataLog['Threshold'][k]:
self.htmlFile.write(' <th bgcolor = "red" >' + DataLog['Data'][k][2] + ' (Ref = ' + str(DataLog['Ref'][k]) + ' ; Thres = ' +str(DataLog['Threshold'][k])+') ' + '</th>\n')
else:
self.htmlFile.write(' <th bgcolor = "green" ><font color="white">' + DataLog['Data'][k][2] + ' (Ref = ' + str(DataLog['Ref'][k]) + ' ; Thres = ' +str(DataLog['Threshold'][k])+') ' + '</th>\n')
self.htmlFile.write(' </tr>\n')
self.htmlFile.close()
def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue): def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue):
if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)): if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)):
self.htmlFile = open('test_results.html', 'a') self.htmlFile = open('test_results.html', 'a')
......
...@@ -37,6 +37,8 @@ import logging ...@@ -37,6 +37,8 @@ import logging
import os import os
import time import time
from multiprocessing import Process, Lock, SimpleQueue from multiprocessing import Process, Lock, SimpleQueue
import yaml
#----------------------------------------------------------- #-----------------------------------------------------------
# OAI Testing modules # OAI Testing modules
...@@ -90,6 +92,7 @@ class RANManagement(): ...@@ -90,6 +92,7 @@ class RANManagement():
self.testCase_id = '' self.testCase_id = ''
self.epcPcapFile = '' self.epcPcapFile = ''
self.runtime_stats= '' self.runtime_stats= ''
self.datalog_rt_stats={}
...@@ -633,6 +636,8 @@ class RANManagement(): ...@@ -633,6 +636,8 @@ class RANManagement():
HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
else: else:
HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
if len(self.datalog_rt_stats)!=0:
HTML.CreateHtmlDataLogTable(self.datalog_rt_stats)
self.eNBmbmsEnables[int(self.eNB_instance)] = False self.eNBmbmsEnables[int(self.eNB_instance)] = False
self.eNBstatuses[int(self.eNB_instance)] = -1 self.eNBstatuses[int(self.eNB_instance)] = -1
...@@ -699,6 +704,21 @@ class RANManagement(): ...@@ -699,6 +704,21 @@ class RANManagement():
#count "problem receiving samples" msg #count "problem receiving samples" msg
pb_receiving_samples_cnt = 0 pb_receiving_samples_cnt = 0
#the datalog config file has to be loaded
datalog_rt_stats_file='datalog_rt_stats.yaml'
if (os.path.isfile(datalog_rt_stats_file)):
yaml_file=datalog_rt_stats_file
elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
yaml_file='ci-scripts/'+datalog_rt_stats_file
else:
logging.error("Datalog RT stats yaml file cannot be found")
sys.exit("Datalog RT stats yaml file cannot be found")
with open(yaml_file,'r') as f:
datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
for line in enb_log_file.readlines(): for line in enb_log_file.readlines():
# Runtime statistics # Runtime statistics
result = re.search('Run time:' ,str(line)) result = re.search('Run time:' ,str(line))
...@@ -857,21 +877,21 @@ class RANManagement(): ...@@ -857,21 +877,21 @@ class RANManagement():
#keys below are the markers we are loooking for, loop over this keys list #keys below are the markers we are loooking for, loop over this keys list
#everytime these markers are found in the log file, the previous ones are overwritten in the dict #everytime these markers are found in the log file, the previous ones are overwritten in the dict
#eventually we record and print only the last occurence #eventually we record and print only the last occurence
keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled', 'scheduling timing stats'} keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled'}
for k in keys: for k in keys:
result = re.search(k, line) result = re.search(k, line)
if result is not None: if result is not None:
#remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char #remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char
dlsch_ulsch_stats[k]=re.sub(r'^.*\]\s+', r'' , line.rstrip()) dlsch_ulsch_stats[k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
#real time statistics #real time statistics for gNB
#same method as above for k in rt_keys:
keys = {'feprx','feptx_prec','feptx_ofdm','feptx_total','L1 Tx processing','DLSCH encoding','L1 Rx processing','PUSCH inner-receiver','PUSCH decoding'}
for k in keys:
result = re.search(k, line) result = re.search(k, line)
if result is not None: if result is not None:
#remove 1- all useless char before relevant info 2- trailing char #remove 1- all useless char before relevant info 2- trailing char
line=line.replace('[0m','')
tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
real_time_stats[k]=tmp.group(1) real_time_stats[k]=tmp.group(1)
#count "problem receiving samples" msg #count "problem receiving samples" msg
result = re.search('\[PHY\]\s+problem receiving samples', str(line)) result = re.search('\[PHY\]\s+problem receiving samples', str(line))
if result is not None: if result is not None:
...@@ -920,13 +940,23 @@ class RANManagement(): ...@@ -920,13 +940,23 @@ class RANManagement():
logging.debug(dlsch_ulsch_stats[key]) logging.debug(dlsch_ulsch_stats[key])
htmleNBFailureMsg += statMsg htmleNBFailureMsg += statMsg
#real time statistics statistics #real time statistics
datalog_rt_stats['Data']={}
if len(real_time_stats)!=0: #check if dictionary is not empty if len(real_time_stats)!=0: #check if dictionary is not empty
statMsg='' for k in real_time_stats:
for key in real_time_stats: #for each dictionary key tmp=re.match(r'^(?P<metric>.*):\s+(?P<avg>\d+\.\d+) us;\s+\d+;\s+(?P<max>\d+\.\d+) us;',real_time_stats[k])
statMsg += real_time_stats[key] + '\n' if tmp is not None:
logging.debug(real_time_stats[key]) metric=tmp.group('metric')
htmleNBFailureMsg += statMsg avg=float(tmp.group('avg'))
max=float(tmp.group('max'))
datalog_rt_stats['Data'][metric]=["{:.0f}".format(avg),"{:.0f}".format(max),"{:.2f}".format(avg/datalog_rt_stats['Ref'][metric])]
#once all metrics are collected, store the data as a class attribute to build a dedicated HTML table afterward
self.datalog_rt_stats=datalog_rt_stats
#check if there is a fail => will render the test as failed
for k in datalog_rt_stats['Data']:
if float(datalog_rt_stats['Data'][k][2])> datalog_rt_stats['Threshold'][k]: #condition for fail : avg/ref is greater than the fixed threshold
#setting prematureExit is ok although not the best option
self.prematureExit=True
else: else:
statMsg = 'No real time stats found in the log file\n' statMsg = 'No real time stats found in the log file\n'
logging.debug('No real time stats found in the log file') logging.debug('No real time stats found in the log file')
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<htmlTabRef>gNB-PHY-Test</htmlTabRef> <htmlTabRef>gNB-PHY-Test</htmlTabRef>
<htmlTabName>Run-gNB-PHY-Test</htmlTabName> <htmlTabName>Run-gNB-PHY-Test</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon> <htmlTabIcon>tasks</htmlTabIcon>
<repeatCount>2</repeatCount> <repeatCount>3</repeatCount>
<TestCaseRequestedList> <TestCaseRequestedList>
090101 000001 090109 090101 000001 090109
</TestCaseRequestedList> </TestCaseRequestedList>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<testCase id="000001"> <testCase id="000001">
<class>IdleSleep</class> <class>IdleSleep</class>
<desc>Sleep</desc> <desc>Sleep</desc>
<idle_sleep_time_in_sec>180</idle_sleep_time_in_sec> <idle_sleep_time_in_sec>300</idle_sleep_time_in_sec>
</testCase> </testCase>
......
...@@ -553,7 +553,7 @@ void *UE_thread(void *arg) { ...@@ -553,7 +553,7 @@ void *UE_thread(void *arg) {
if (UE->is_synchronized) { if (UE->is_synchronized) {
decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx); decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
// shift the frame index with all the frames we trashed meanwhile we perform the synch search // shift the frame index with all the frames we trashed meanwhile we perform the synch search
decoded_frame_rx=(decoded_frame_rx + (!UE->init_sync_frame) + trashed_frames) % MAX_FRAME_NUMBER; decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
} }
delNotifiedFIFO_elt(res); delNotifiedFIFO_elt(res);
start_rx_stream=0; start_rx_stream=0;
...@@ -693,9 +693,9 @@ void *UE_thread(void *arg) { ...@@ -693,9 +693,9 @@ void *UE_thread(void *arg) {
pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
} }
if ( decoded_frame_rx>0 && decoded_frame_rx != curMsg->proc.frame_rx) if (decoded_frame_rx>0 && decoded_frame_rx != curMsg->proc.frame_rx)
LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n", LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
decoded_frame_rx, curMsg->proc.frame_rx ); decoded_frame_rx, curMsg->proc.frame_rx);
// use previous timing_advance value to compute writeTimestamp // use previous timing_advance value to compute writeTimestamp
writeTimestamp = timestamp+ writeTimestamp = timestamp+
......
...@@ -308,12 +308,15 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, int n_frames) ...@@ -308,12 +308,15 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, int n_frames)
// every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1) // every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
int n_symb_prefix0 = (ue->symbol_offset/(7*(1<<mu)))+1; int n_symb_prefix0 = (ue->symbol_offset/(7*(1<<mu)))+1;
sync_pos_frame = n_symb_prefix0*(fp->ofdm_symbol_size + fp->nb_prefix_samples0)+(ue->symbol_offset-n_symb_prefix0)*(fp->ofdm_symbol_size + fp->nb_prefix_samples); sync_pos_frame = n_symb_prefix0*(fp->ofdm_symbol_size + fp->nb_prefix_samples0)+(ue->symbol_offset-n_symb_prefix0)*(fp->ofdm_symbol_size + fp->nb_prefix_samples);
if (ue->ssb_offset < sync_pos_frame) // for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of the n_frames we got sync
ue->init_sync_frame = n_frames - 1 - is;
// we also need to take into account the shift by samples_per_frame in case the if is true
if (ue->ssb_offset < sync_pos_frame){
ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset; ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset;
ue->init_sync_frame += 1;
}
else else
ue->rx_offset = ue->ssb_offset - sync_pos_frame; ue->rx_offset = ue->ssb_offset - sync_pos_frame;
ue->init_sync_frame = is;
} }
/* /*
......
...@@ -589,7 +589,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue, ...@@ -589,7 +589,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
frame_parms->ssb_index += (((nr_ue_pbch_vars->xtra_byte>>(7-i))&0x01)<<(3+i)); frame_parms->ssb_index += (((nr_ue_pbch_vars->xtra_byte>>(7-i))&0x01)<<(3+i));
} }
ue->symbol_offset = nr_get_ssb_start_symbol(frame_parms,i_ssb); ue->symbol_offset = nr_get_ssb_start_symbol(frame_parms,frame_parms->ssb_index);
if (frame_parms->half_frame_bit) if (frame_parms->half_frame_bit)
ue->symbol_offset += (frame_parms->slots_per_frame>>1)*frame_parms->symbols_per_slot; ue->symbol_offset += (frame_parms->slots_per_frame>>1)*frame_parms->symbols_per_slot;
......
...@@ -351,7 +351,7 @@ void nr_ue_pbch_procedures(uint8_t gNB_id, ...@@ -351,7 +351,7 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);
LOG_D(PHY,"[UE %d] Frame %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,ue->frame_parms.Nid_cell,gNB_id); LOG_D(PHY,"[UE %d] Frame %d Slot %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,nr_slot_rx,ue->frame_parms.Nid_cell,gNB_id);
ret = nr_rx_pbch(ue, proc, ret = nr_rx_pbch(ue, proc,
ue->pbch_vars[gNB_id], ue->pbch_vars[gNB_id],
......
...@@ -742,13 +742,7 @@ int main(int argc, char **argv) ...@@ -742,13 +742,7 @@ int main(int argc, char **argv)
prepare_scd(scd); prepare_scd(scd);
fill_default_secondaryCellGroup(scc, fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0);
scd,
secondaryCellGroup,
0,
1,
n_tx,
0);
/* RRC parameter validation for secondaryCellGroup */ /* RRC parameter validation for secondaryCellGroup */
fix_scd(scd); fix_scd(scd);
......
...@@ -686,13 +686,7 @@ int main(int argc, char **argv) ...@@ -686,13 +686,7 @@ int main(int argc, char **argv)
prepare_scd(scd); prepare_scd(scd);
fill_default_secondaryCellGroup(scc, fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0);
scd,
secondaryCellGroup,
0,
1,
n_tx,
0);
// xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc"
#define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd"
#define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd"
#define CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY "ulsch_max_slots_inactivity"
#define CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10 "pusch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10 "pusch_TargetSNRx10"
#define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10"
#define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres" #define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres"
...@@ -82,6 +83,7 @@ ...@@ -82,6 +83,7 @@
{CONFIG_STRING_MACRLC_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \
{CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \
{CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \
{CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY, "Maximum number of slots before a UE is scheduled ULSCH due to inactivity", 0, uptr:NULL, defintval:200, TYPE_UINT, 0}, \
{CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \
...@@ -104,6 +106,7 @@ ...@@ -104,6 +106,7 @@
#define MACRLC_REMOTE_S_PORTC_IDX 14 #define MACRLC_REMOTE_S_PORTC_IDX 14
#define MACRLC_LOCAL_S_PORTD_IDX 15 #define MACRLC_LOCAL_S_PORTD_IDX 15
#define MACRLC_REMOTE_S_PORTD_IDX 16 #define MACRLC_REMOTE_S_PORTD_IDX 16
#define MACRLC_ULSCH_MAX_SLOTS_INACTIVITY 17
#define MACRLC_PUSCHTARGETSNRX10_IDX 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 17
#define MACRLC_PUCCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 18
#define MACRLC_PUCCHFAILURETHRES_IDX 19 #define MACRLC_PUCCHFAILURETHRES_IDX 19
......
...@@ -723,6 +723,7 @@ void RCconfig_nr_macrlc() { ...@@ -723,6 +723,7 @@ void RCconfig_nr_macrlc() {
}else { // other midhaul }else { // other midhaul
AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
} }
RC.nrmac[j]->ulsch_max_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_INACTIVITY].uptr);
}// for (j=0;j<RC.nb_nr_macrlc_inst;j++) }// for (j=0;j<RC.nb_nr_macrlc_inst;j++)
}else {// MacRLC_ParamList.numelt > 0 }else {// MacRLC_ParamList.numelt > 0
printf("No %s configuration found \n", CONFIG_STRING_MACRLC_LIST); printf("No %s configuration found \n", CONFIG_STRING_MACRLC_LIST);
......
...@@ -370,14 +370,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, ...@@ -370,14 +370,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL, AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL,
"could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n"); "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n");
for (int i = 0; i < MAX_NUM_BWP; ++i) {
RC.nrmac[Mod_idP]->pucch_index_used[i] =
calloc(n, sizeof(*RC.nrmac[Mod_idP]->pucch_index_used));
AssertFatal(RC.nrmac[Mod_idP]->pucch_index_used[i],
"could not allocate memory for RC.nrmac[]->pucch_index_used[%d]\n",
i);
}
LOG_I(NR_MAC,"Configuring common parameters from NR ServingCellConfig\n"); LOG_I(NR_MAC,"Configuring common parameters from NR ServingCellConfig\n");
config_common(Mod_idP, config_common(Mod_idP,
......
...@@ -402,7 +402,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, ...@@ -402,7 +402,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
} }
// This schedule SR // This schedule SR
// TODO nr_sr_reporting(module_idP, frame, slot);
// Schedule CSI measurement reporting: check in slot 0 for the whole frame // Schedule CSI measurement reporting: check in slot 0 for the whole frame
if (slot == 0) if (slot == 0)
......
...@@ -252,8 +252,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ...@@ -252,8 +252,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
case 3: case 3:
// long bitmap FR2 max 64 SSBs // long bitmap FR2 max 64 SSBs
num_ssb = 0; num_ssb = 0;
for (int i_ssb=0; i_ssb<63; i_ssb++) { for (int i_ssb=0; i_ssb<64; i_ssb++) {
if ((longBitmap->buf[i_ssb/8]>>(7-i_ssb))&0x01) { if ((longBitmap->buf[i_ssb/8]>>(7-(i_ssb%8)))&0x01) {
ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb);
// if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters
if ((ssb_start_symbol/14) == rel_slot){ if ((ssb_start_symbol/14) == rel_slot){
......
...@@ -120,8 +120,13 @@ int diff_rsrp_ssb_csi_meas_10_1_6_1_2[16] = { ...@@ -120,8 +120,13 @@ int diff_rsrp_ssb_csi_meas_10_1_6_1_2[16] = {
void nr_schedule_pucch(int Mod_idP, void nr_schedule_pucch(int Mod_idP,
frame_t frameP, frame_t frameP,
sub_frame_t slotP) { sub_frame_t slotP)
NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; {
gNB_MAC_INST *nrmac = RC.nrmac[Mod_idP];
if (!is_xlsch_in_slot(nrmac->ulsch_slot_bitmap[slotP / 64], slotP))
return;
NR_UE_info_t *UE_info = &nrmac->UE_info;
const NR_list_t *UE_list = &UE_info->list; const NR_list_t *UE_list = &UE_info->list;
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
...@@ -508,11 +513,11 @@ void nr_csi_meas_reporting(int Mod_idP, ...@@ -508,11 +513,11 @@ void nr_csi_meas_reporting(int Mod_idP,
// find free PUCCH that is in order with possibly existing PUCCH // find free PUCCH that is in order with possibly existing PUCCH
// schedulings (other CSI, SR) // schedulings (other CSI, SR)
NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[2]; NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[1];
AssertFatal(curr_pucch->csi_bits == 0 AssertFatal(curr_pucch->csi_bits == 0
&& !curr_pucch->sr_flag && !curr_pucch->sr_flag
&& curr_pucch->dai_c == 0, && curr_pucch->dai_c == 0,
"PUCCH not free at index 2 for UE %04x\n", "PUCCH not free at index 1 for UE %04x\n",
UE_info->rnti[UE_id]); UE_info->rnti[UE_id]);
curr_pucch->frame = frame; curr_pucch->frame = frame;
curr_pucch->ul_slot = sched_slot; curr_pucch->ul_slot = sched_slot;
...@@ -1011,15 +1016,6 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, ...@@ -1011,15 +1016,6 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
// tpc (power control)
if (uci_01->harq->harq_confidence_level == 0)
sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10,
uci_01->ul_cqi,
30);
LOG_D(NR_MAC,"pucch tpc %d\n",sched_ctrl->tpc1);
sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640;
if (((uci_01->pduBitmap >> 1) & 0x01)) { if (((uci_01->pduBitmap >> 1) & 0x01)) {
// iterate over received harq bits // iterate over received harq bits
for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) {
...@@ -1034,6 +1030,20 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, ...@@ -1034,6 +1030,20 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0); handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0);
} }
} }
// check scheduling request result, confidence_level == 0 is good
if (uci_01->pduBitmap & 0x1 && uci_01->sr->sr_indication && uci_01->sr->sr_confidence_level == 0 && uci_01->ul_cqi >= 148) {
// SR detected with SNR >= 10dB
sched_ctrl->SR |= true;
LOG_D(MAC, "SR UE %04x ul_cqi %d\n", uci_01->rnti, uci_01->ul_cqi);
}
// tpc (power control) only if we received AckNack or positive SR. For a
// negative SR, the UE won't have sent anything, and the SNR is not valid
if (((uci_01->pduBitmap >> 1) & 0x1) || sched_ctrl->SR) {
sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, uci_01->ul_cqi, 30);
sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640;
}
} }
void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
...@@ -1113,10 +1123,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1113,10 +1123,7 @@ bool nr_acknack_scheduling(int mod_id,
* * we do not multiplex with CSI, which is always in pucch_sched[2] * * we do not multiplex with CSI, which is always in pucch_sched[2]
* * SR uses format 0 and is allocated in the first UL (mixed) slot (and not * * SR uses format 0 and is allocated in the first UL (mixed) slot (and not
* later) * later)
* * that the PUCCH resource set 0 (for up to 2 bits) points to the first N * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */
* PUCCH resources, where N is the number of resources in the PUCCH
* resource set. This is used in pucch_index_used, which counts the used
* resources by index, and not by their ID! */
NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id]; NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id];
NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0];
pucch->r_pucch=r_pucch; pucch->r_pucch=r_pucch;
...@@ -1125,12 +1132,8 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1125,12 +1132,8 @@ bool nr_acknack_scheduling(int mod_id,
__func__, __func__,
pucch->csi_bits); pucch->csi_bits);
const int max_acknacks = 2;
AssertFatal(pucch->dai_c + pucch->sr_flag <= max_acknacks,
"illegal number of bits in PUCCH of UE %d\n",
UE_id);
/* if the currently allocated PUCCH of this UE is full, allocate it */ /* if the currently allocated PUCCH of this UE is full, allocate it */
if (pucch->sr_flag + pucch->dai_c == max_acknacks) { if (pucch->dai_c == 2) {
/* advance the UL slot information in PUCCH by one so we won't schedule in /* advance the UL slot information in PUCCH by one so we won't schedule in
* the same slot again */ * the same slot again */
const int f = pucch->frame; const int f = pucch->frame;
...@@ -1140,7 +1143,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1140,7 +1143,7 @@ bool nr_acknack_scheduling(int mod_id,
pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f;
pucch->ul_slot = (s + 1) % n_slots_frame; pucch->ul_slot = (s + 1) % n_slots_frame;
// we assume that only two indices over the array sched_pucch exist // we assume that only two indices over the array sched_pucch exist
NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[2]; NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[1];
// skip the CSI PUCCH if it is present and if in the next frame/slot // skip the CSI PUCCH if it is present and if in the next frame/slot
csi_pucch->r_pucch=-1; csi_pucch->r_pucch=-1;
if (csi_pucch->csi_bits > 0 if (csi_pucch->csi_bits > 0
...@@ -1153,6 +1156,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1153,6 +1156,7 @@ bool nr_acknack_scheduling(int mod_id,
pucch->ul_slot, pucch->ul_slot,
UE_id); UE_id);
nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id); nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id);
memset(csi_pucch, 0, sizeof(*csi_pucch));
pucch->frame = s >= n_slots_frame - 2 ? (f + 1) % 1024 : f; pucch->frame = s >= n_slots_frame - 2 ? (f + 1) % 1024 : f;
pucch->ul_slot = (s + 2) % n_slots_frame; pucch->ul_slot = (s + 2) % n_slots_frame;
} }
...@@ -1172,9 +1176,8 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1172,9 +1176,8 @@ bool nr_acknack_scheduling(int mod_id,
uint8_t pdsch_to_harq_feedback[8]; uint8_t pdsch_to_harq_feedback[8];
get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback); get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback);
/* there is a scheduled SR or HARQ. Check whether we can use it for this /* there is a HARQ. Check whether we can use it for this ACKNACK */
* ACKNACK */ if (pucch->dai_c > 0) {
if (pucch->sr_flag + pucch->dai_c > 0) {
/* this UE already has a PUCCH occasion */ /* this UE already has a PUCCH occasion */
DevAssert(pucch->frame == frame); DevAssert(pucch->frame == frame);
...@@ -1205,34 +1208,14 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1205,34 +1208,14 @@ bool nr_acknack_scheduling(int mod_id,
/* we need to find a new PUCCH occasion */ /* we need to find a new PUCCH occasion */
NR_PUCCH_Config_t *pucch_Config=NULL;
int bwp_Id=0;
if (sched_ctrl->active_ubwp) {
pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
bwp_Id= sched_ctrl->active_ubwp->bwp_Id;
}
else if (RC.nrmac[mod_id]->UE_info.CellGroup[UE_id] &&
RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig &&
RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated &&
RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig &&
RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP &&
RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup)
pucch_Config = RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup;
if (pucch_Config) {
DevAssert(pucch_Config->resourceToAddModList->list.count > 0);
DevAssert(pucch_Config->resourceSetToAddModList->list.count > 0);
}
int n_res = (pucch_Config) ?
pucch_Config->resourceSetToAddModList->list.array[0]->resourceList.list.count :
nr_get_default_pucch_res(*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon);
int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[bwp_Id];
/* if time information is outdated (e.g., last PUCCH occasion in last frame), /* if time information is outdated (e.g., last PUCCH occasion in last frame),
* set to first possible UL occasion in this frame. Note that if such UE is * set to first possible UL occasion in this frame. Note that if such UE is
* scheduled a lot and used all AckNacks, pucch->frame might have been * scheduled a lot and used all AckNacks, pucch->frame might have been
* wrapped around to next frame */ * wrapped around to next frame */
if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) { if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) {
DevAssert(pucch->sr_flag + pucch->dai_c == 0); AssertFatal(pucch->sr_flag + pucch->dai_c == 0,
"expected no SR/AckNack for UE %d in %4d.%2d, but has %d/%d for %4d.%2d\n",
UE_id, frame, slot, pucch->sr_flag, pucch->dai_c, pucch->frame, pucch->ul_slot);
AssertFatal(frame + 1 != pucch->frame, AssertFatal(frame + 1 != pucch->frame,
"frame wrap around not handled in %s() yet\n", "frame wrap around not handled in %s() yet\n",
__func__); __func__);
...@@ -1240,27 +1223,11 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1240,27 +1223,11 @@ bool nr_acknack_scheduling(int mod_id,
pucch->ul_slot = first_ul_slot_tdd; pucch->ul_slot = first_ul_slot_tdd;
} }
// increase to first slot in which PUCCH resources are available
while (pucch_index_used[pucch->ul_slot] >= n_res) {
pucch->ul_slot++;
/* if there is no free resource anymore, abort search */
if ((pucch->frame == frame
&& pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots)
|| (pucch->frame == frame + 1)) {
LOG_E(MAC,
"%4d.%2d no free PUCCH resources anymore while searching for UE %d\n",
frame,
slot,
UE_id);
return false;
}
}
// advance ul_slot if it is not reachable by UE // advance ul_slot if it is not reachable by UE
pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]); pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]);
// is there already CSI in this slot? // is there already CSI in this slot?
const NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[2]; NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[1];
// skip the CSI PUCCH if it is present and if in the next frame/slot // skip the CSI PUCCH if it is present and if in the next frame/slot
if (csi_pucch->csi_bits > 0 if (csi_pucch->csi_bits > 0
&& csi_pucch->frame == pucch->frame && csi_pucch->frame == pucch->frame
...@@ -1272,6 +1239,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1272,6 +1239,7 @@ bool nr_acknack_scheduling(int mod_id,
pucch->ul_slot, pucch->ul_slot,
UE_id); UE_id);
nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id); nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id);
memset(csi_pucch, 0, sizeof(*csi_pucch));
/* advance the UL slot information in PUCCH by one so we won't schedule in /* advance the UL slot information in PUCCH by one so we won't schedule in
* the same slot again */ * the same slot again */
const int f = pucch->frame; const int f = pucch->frame;
...@@ -1306,33 +1274,21 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1306,33 +1274,21 @@ bool nr_acknack_scheduling(int mod_id,
LOG_D(MAC,"2. DL slot %d, UL_ACK %d (index %d)\n",slot,pucch->ul_slot,i); LOG_D(MAC,"2. DL slot %d, UL_ACK %d (index %d)\n",slot,pucch->ul_slot,i);
pucch->dai_c++; pucch->dai_c++;
const int pucch_res = r_pucch<0 ? pucch_index_used[pucch->ul_slot] : r_pucch; pucch->resource_indicator = 0; // each UE has dedicated PUCCH resources
pucch->resource_indicator = pucch_res;
pucch_index_used[pucch->ul_slot] += 1;
AssertFatal(pucch_index_used[pucch->ul_slot] <= n_res,
"UE %d in %4d.%2d: pucch_index_used is %d (%d available)\n",
UE_id,
pucch->frame,
pucch->ul_slot,
pucch_index_used[pucch->ul_slot],
n_res);
/* verify that at that slot and symbol, resources are free. We only do this /* verify that at that slot and symbol, resources are free. We only do this
* for initialCyclicShift 0 (we assume it always has that one), so other * for initialCyclicShift 0 (we assume it always has that one), so other
* initialCyclicShifts can overlap with ICS 0!*/ * initialCyclicShifts can overlap with ICS 0!*/
if (pucch_Config) { const NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
const NR_PUCCH_Resource_t *resource = const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator];
pucch_Config->resourceToAddModList->list.array[pucch_res];
DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0);
if (resource->format.choice.format0->initialCyclicShift == 0) { if (resource->format.choice.format0->initialCyclicShift == 0) {
uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE]; uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE];
const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex; const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex;
AssertFatal((vrb_map_UL[resource->startingPRB] & symb) == 0, if ((vrb_map_UL[resource->startingPRB] & symb) != 0)
"symbol %x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d\n", LOG_W(MAC, "symbol 0x%x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d.%d\n", symb, resource->startingPRB, pucch->frame, pucch->ul_slot);
symb, resource->startingPRB, pucch->ul_slot);
vrb_map_UL[resource->startingPRB] |= symb; vrb_map_UL[resource->startingPRB] |= symb;
} }
}
return true; return true;
} }
...@@ -1463,3 +1419,154 @@ uint16_t compute_pucch_prb_size(uint8_t format, ...@@ -1463,3 +1419,154 @@ uint16_t compute_pucch_prb_size(uint8_t format,
AssertFatal(1==0,"Not yet implemented"); AssertFatal(1==0,"Not yet implemented");
} }
} }
void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot)
{
gNB_MAC_INST *nrmac = RC.nrmac[Mod_idP];
if (!is_xlsch_in_slot(nrmac->ulsch_slot_bitmap[slot / 64], slot))
return;
NR_ServingCellConfigCommon_t *scc = nrmac->common_channels->ServingCellConfigCommon;
const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
NR_UE_info_t *UE_info = &nrmac->UE_info;
NR_list_t *UE_list = &UE_info->list;
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
AssertFatal(pucch_Config->schedulingRequestResourceToAddModList->list.count>0,"NO SR configuration available");
for (int SR_resource_id =0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) {
NR_SchedulingRequestResourceConfig_t *SchedulingRequestResourceConfig = pucch_Config->schedulingRequestResourceToAddModList->list.array[SR_resource_id];
int SR_period; int SR_offset;
periodicity__SRR(SchedulingRequestResourceConfig,&SR_period,&SR_offset);
// convert to int to avoid underflow of uint
int sfn_sf = SFN * n_slots_frame + slot;
if ((sfn_sf - SR_offset) % SR_period != 0)
continue;
LOG_D(MAC, "%4d.%2d Scheduling Request identified\n", SFN, slot);
NR_PUCCH_ResourceId_t *PucchResourceId = SchedulingRequestResourceConfig->resource;
int found = -1;
NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[0]; // set with formats 0,1
int n_list = pucchresset->resourceList.list.count;
for (int i=0; i<n_list; i++) {
if (*pucchresset->resourceList.list.array[i] == *PucchResourceId )
found = i;
}
AssertFatal(found>-1,"SR resource not found among PUCCH resources");
/* loop through nFAPI PUCCH messages: if the UEs is in there in this slot
* with the resource_indicator, it means we already allocated that PUCCH
* resource for AckNack (e.g., the UE has been scheduled often), and we
* just need to add the SR_flag. Otherwise, just allocate in the internal
* PUCCH resource, and nr_schedule_pucch() will handle the rest */
NR_PUCCH_Resource_t *pucch_res = pucch_Config->resourceToAddModList->list.array[found];
/* for the moment, can only handle SR on PUCCH Format 0 */
DevAssert(pucch_res->format.present == NR_PUCCH_Resource__format_PR_format0);
nfapi_nr_ul_tti_request_t *ul_tti_req = &nrmac->UL_tti_req_ahead[0][slot];
bool nfapi_allocated = false;
for (int i = 0; i < ul_tti_req->n_pdus; ++i) {
if (ul_tti_req->pdus_list[i].pdu_type != NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE)
continue;
nfapi_nr_pucch_pdu_t *pdu = &ul_tti_req->pdus_list[i].pucch_pdu;
/* check that it is our PUCCH F0. Assuming there can be only one */
if (pdu->rnti == UE_info->rnti[UE_id]
&& pdu->format_type == 0 // does not use NR_PUCCH_Resource__format_PR_format0
&& pdu->initial_cyclic_shift == pucch_res->format.choice.format0->initialCyclicShift
&& pdu->nr_of_symbols == pucch_res->format.choice.format0->nrofSymbols
&& pdu->start_symbol_index == pucch_res->format.choice.format0->startingSymbolIndex) {
LOG_D(MAC,"%4d.%2d adding SR_flag 1 to PUCCH nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti);
pdu->sr_flag = 1;
nfapi_allocated = true;
break;
}
}
if (nfapi_allocated) // break scheduling resource loop, continue next UE
break;
/* we did not find it: check if current PUCCH is for the current slot, in
* which case we add the SR to it; otherwise, allocate SR separately */
NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[0];
if (curr_pucch->frame == SFN && curr_pucch->ul_slot == slot) {
if (curr_pucch->resource_indicator != found) {
LOG_W(MAC, "%4d.%2d expected PUCCH in this slot to have resource indicator of SR (%d), skipping SR\n", SFN, slot, found);
continue;
}
curr_pucch->sr_flag = true;
} else {
NR_sched_pucch_t sched_sr;
memset(&sched_sr, 0, sizeof(sched_sr));
sched_sr.frame = SFN;
sched_sr.ul_slot = slot;
sched_sr.resource_indicator = found;
sched_sr.sr_flag = true;
nr_fill_nfapi_pucch(Mod_idP, SFN, slot, &sched_sr, UE_id);
}
}
}
}
void periodicity__SRR (NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset)
{
NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR P_O = SchedulingReqRec->periodicityAndOffset->present;
switch (P_O){
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl1:
*period = 1;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl1;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl2:
*period = 2;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl2;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl4:
*period = 4;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl4;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl5:
*period = 5;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl5;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl8:
*period = 8;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl8;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10:
*period = 10;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl10;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl16:
*period = 16;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl16;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl20:
*period = 20;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl20;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40:
*period = 40;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl40;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl80:
*period = 80;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl80;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl160:
*period = 160;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl160;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl320:
*period = 320;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl320;
break;
case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl640:
*period = 640;
*offset = SchedulingReqRec->periodicityAndOffset->choice.sl640;
break;
default:
AssertFatal(1==0,"No periodicityAndOffset resources found in schedulingrequestresourceconfig");
}
}
...@@ -789,6 +789,34 @@ long get_K2(NR_ServingCellConfigCommon_t *scc,NR_BWP_Uplink_t *ubwp, int time_do ...@@ -789,6 +789,34 @@ long get_K2(NR_ServingCellConfigCommon_t *scc,NR_BWP_Uplink_t *ubwp, int time_do
return 3; return 3;
} }
bool nr_UE_is_to_be_scheduled(module_id_t mod_id, int CC_id, int UE_id, frame_t frame, sub_frame_t slot)
{
const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon;
const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
const int n = slots_per_frame[*scc->ssbSubcarrierSpacing];
const int now = frame * n + slot;
const struct gNB_MAC_INST_s *nrmac = RC.nrmac[mod_id];
const NR_UE_sched_ctrl_t *sched_ctrl = &nrmac->UE_info.UE_sched_ctrl[UE_id];
const int last_ul_sched = sched_ctrl->last_ul_frame * n + sched_ctrl->last_ul_slot;
const int diff = (now - last_ul_sched + 1024 * n) % (1024 * n);
/* UE is to be scheduled if
* (1) we think the UE has more bytes awaiting than what we scheduled
* (2) there is a scheduling request
* (3) or we did not schedule it in more than 10 frames */
const bool has_data = sched_ctrl->estimated_ul_buffer > sched_ctrl->sched_ul_bytes;
const bool high_inactivity = diff >= nrmac->ulsch_max_slots_inactivity;
LOG_D(MAC,
"%4d.%2d UL inactivity %d slots has_data %d SR %d\n",
frame,
slot,
diff,
has_data,
sched_ctrl->SR);
return has_data || sched_ctrl->SR || high_inactivity;
}
int next_list_entry_looped(NR_list_t *list, int UE_id) int next_list_entry_looped(NR_list_t *list, int UE_id)
{ {
if (UE_id < 0) if (UE_id < 0)
...@@ -920,7 +948,6 @@ void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_pusch_semi_static ...@@ -920,7 +948,6 @@ void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_pusch_semi_static
float ul_thr_ue[MAX_MOBILES_PER_GNB]; float ul_thr_ue[MAX_MOBILES_PER_GNB];
uint32_t ul_pf_tbs[3][28]; // pre-computed, approximate TBS values for PF coefficient uint32_t ul_pf_tbs[3][28]; // pre-computed, approximate TBS values for PF coefficient
int bsr0ue = -1;
void pf_ul(module_id_t module_id, void pf_ul(module_id_t module_id,
frame_t frame, frame_t frame,
sub_frame_t slot, sub_frame_t slot,
...@@ -939,12 +966,6 @@ void pf_ul(module_id_t module_id, ...@@ -939,12 +966,6 @@ void pf_ul(module_id_t module_id,
int ue_array[MAX_MOBILES_PER_GNB]; int ue_array[MAX_MOBILES_PER_GNB];
NR_list_t UE_sched = { .head = -1, .next = ue_array, .tail = -1, .len = MAX_MOBILES_PER_GNB }; NR_list_t UE_sched = { .head = -1, .next = ue_array, .tail = -1, .len = MAX_MOBILES_PER_GNB };
/* Hack: currently, we do not have SR, and need to schedule UEs continuously.
* To keep the wasted resources low, we switch UEs to be scheduled in a
* round-robin fashion below, and only schedule a UE with BSR=0 if it is the
* selected one */
bsr0ue = next_list_entry_looped(UE_list, bsr0ue);
/* Loop UE_list to calculate throughput and coeff */ /* Loop UE_list to calculate throughput and coeff */
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
...@@ -979,11 +1000,16 @@ void pf_ul(module_id_t module_id, ...@@ -979,11 +1000,16 @@ void pf_ul(module_id_t module_id,
continue; continue;
} }
/* Check BSR and schedule UE if it is zero to avoid starvation, since we do const int B = max(0, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes);
* not have SR (yet) */ /* preprocessor computed sched_frame/sched_slot */
if (sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes <= 0) { const bool do_sched = nr_UE_is_to_be_scheduled(module_id, 0, UE_id, sched_pusch->frame, sched_pusch->slot);
if (UE_id != bsr0ue)
if (B == 0 && !do_sched)
continue; continue;
/* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled
* based on data to transmit) */
if (B == 0 && do_sched) {
/* if no data, pre-allocate 5RB */ /* if no data, pre-allocate 5RB */
bool freeCCE = find_free_CCE(module_id, slot, UE_id); bool freeCCE = find_free_CCE(module_id, slot, UE_id);
if (!freeCCE) { if (!freeCCE) {
...@@ -1162,7 +1188,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t ...@@ -1162,7 +1188,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t
int K2 = get_K2(scc, sched_ctrl->active_ubwp, tda, mu); int K2 = get_K2(scc, sched_ctrl->active_ubwp, tda, mu);
const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]);
const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu];
if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[slot / 64], sched_slot)) if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot))
return false; return false;
sched_ctrl->sched_pusch.slot = sched_slot; sched_ctrl->sched_pusch.slot = sched_slot;
...@@ -1281,6 +1307,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1281,6 +1307,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
UE_info->mac_stats[UE_id].ulsch_current_bytes = 0; UE_info->mac_stats[UE_id].ulsch_current_bytes = 0;
/* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in
* every TTI are pre-populated by the preprocessor and used below */ * every TTI are pre-populated by the preprocessor and used below */
NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
...@@ -1289,6 +1316,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1289,6 +1316,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
continue; continue;
uint16_t rnti = UE_info->rnti[UE_id]; uint16_t rnti = UE_info->rnti[UE_id];
sched_ctrl->SR = false;
int8_t harq_id = sched_pusch->ul_harq_pid; int8_t harq_id = sched_pusch->ul_harq_pid;
if (harq_id < 0) { if (harq_id < 0) {
...@@ -1345,6 +1373,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1345,6 +1373,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
cur_harq->ndi); cur_harq->ndi);
} }
UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size; UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size;
sched_ctrl->last_ul_frame = sched_pusch->frame;
sched_ctrl->last_ul_slot = sched_pusch->slot;
LOG_D(NR_MAC, LOG_D(NR_MAC,
"%4d.%2d RNTI %04x UL sched %4d.%2d start %2d RBS %3d startSymbol %2d nb_symbol %2d MCS %2d TBS %4d HARQ PID %2d round %d NDI %d est %6d sched %6d est BSR %6d\n", "%4d.%2d RNTI %04x UL sched %4d.%2d start %2d RBS %3d startSymbol %2d nb_symbol %2d MCS %2d TBS %4d HARQ PID %2d round %d NDI %d est %6d sched %6d est BSR %6d\n",
......
...@@ -423,4 +423,10 @@ bool nr_find_nb_rb(uint16_t Qm, ...@@ -423,4 +423,10 @@ bool nr_find_nb_rb(uint16_t Qm,
uint32_t *tbs, uint32_t *tbs,
uint16_t *nb_rb); uint16_t *nb_rb);
void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP);
void periodicity__SRR (NR_SchedulingRequestResourceConfig_t *SchedulingReqRecconf,
int *period,
int *offset);
#endif /*__LAYER2_NR_MAC_PROTO_H__*/ #endif /*__LAYER2_NR_MAC_PROTO_H__*/
...@@ -524,11 +524,9 @@ typedef struct { ...@@ -524,11 +524,9 @@ typedef struct {
int cce_index; int cce_index;
uint8_t aggregation_level; uint8_t aggregation_level;
/// PUCCH scheduling information. Array of three, we assume for the moment: /// PUCCH scheduling information. Array of two: HARQ+SR in the first field,
/// HARQ in the first field, SR in second, CSI in third (as fixed by RRC /// CSI in second. This order is important for nr_acknack_scheduling()!
/// conf., i.e. if actually present). The order is important for NR_sched_pucch_t sched_pucch[2];
/// nr_acknack_scheduling()!
NR_sched_pucch_t sched_pucch[3];
/// PUSCH semi-static configuration: is not cleared across TTIs /// PUSCH semi-static configuration: is not cleared across TTIs
NR_pusch_semi_static_t pusch_semi_static; NR_pusch_semi_static_t pusch_semi_static;
...@@ -549,6 +547,9 @@ typedef struct { ...@@ -549,6 +547,9 @@ typedef struct {
NR_pdsch_semi_static_t pdsch_semi_static; NR_pdsch_semi_static_t pdsch_semi_static;
/// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI /// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI
NR_sched_pdsch_t sched_pdsch; NR_sched_pdsch_t sched_pdsch;
/// For UL synchronization: store last UL scheduling grant
frame_t last_ul_frame;
sub_frame_t last_ul_slot;
/// total amount of data awaiting for this UE /// total amount of data awaiting for this UE
uint32_t num_total_bytes; uint32_t num_total_bytes;
...@@ -569,6 +570,8 @@ typedef struct { ...@@ -569,6 +570,8 @@ typedef struct {
int pucch_consecutive_dtx_cnt; int pucch_consecutive_dtx_cnt;
int ul_failure; int ul_failure;
struct CSI_Report CSI_report[MAX_CSI_REPORTS]; struct CSI_Report CSI_report[MAX_CSI_REPORTS];
bool SR;
/// information about every HARQ process /// information about every HARQ process
NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
/// HARQ processes that are free /// HARQ processes that are free
...@@ -716,10 +719,6 @@ typedef struct gNB_MAC_INST_s { ...@@ -716,10 +719,6 @@ typedef struct gNB_MAC_INST_s {
int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE]; int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE];
/// list of allocated beams per period /// list of allocated beams per period
int16_t *tdd_beam_association; int16_t *tdd_beam_association;
/// PUCCH: keep track of the resources has already been used by saving the
/// highest index not yet been used in a given slot. Dynamically allocated
/// so we can have it for every slot as a function of the numerology
int *pucch_index_used[MAX_NUM_BWP];
/// bitmap of DLSCH slots, can hold up to 160 slots /// bitmap of DLSCH slots, can hold up to 160 slots
uint64_t dlsch_slot_bitmap[3]; uint64_t dlsch_slot_bitmap[3];
...@@ -733,6 +732,9 @@ typedef struct gNB_MAC_INST_s { ...@@ -733,6 +732,9 @@ typedef struct gNB_MAC_INST_s {
/// points to the right UL slot /// points to the right UL slot
int *preferred_ul_tda[MAX_NUM_BWP]; int *preferred_ul_tda[MAX_NUM_BWP];
/// maximum number of slots before a UE will be scheduled ULSCH automatically
uint32_t ulsch_max_slots_inactivity;
/// DL preprocessor for differentiated scheduling /// DL preprocessor for differentiated scheduling
nr_pp_impl_dl pre_processor_dl; nr_pp_impl_dl pre_processor_dl;
/// UL preprocessor for differentiated scheduling /// UL preprocessor for differentiated scheduling
......
...@@ -90,7 +90,8 @@ void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChann ...@@ -90,7 +90,8 @@ void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChann
mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = calloc(1,sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup)); mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = calloc(1,sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup));
*mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = 1; *mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = 1;
mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID = NULL; mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID = calloc(1,sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID));
*mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0;
mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = false; mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = false;
mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false; mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer = NULL; mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer = NULL;
......
...@@ -105,14 +105,8 @@ void handle_nr_uci(NR_UL_IND_t *UL_info) ...@@ -105,14 +105,8 @@ void handle_nr_uci(NR_UL_IND_t *UL_info)
} }
UL_info->uci_ind.num_ucis = 0; UL_info->uci_ind.num_ucis = 0;
// mark corresponding PUCCH resources as free
// NOTE: we just assume it is BWP ID 0 and 1, to be revised for multiple BWPs
RC.nrmac[mod_id]->pucch_index_used[0][slot] = 0;
RC.nrmac[mod_id]->pucch_index_used[1][slot] = 0;
} }
void handle_nr_ulsch(NR_UL_IND_t *UL_info) void handle_nr_ulsch(NR_UL_IND_t *UL_info)
{ {
if (UL_info->rx_ind.number_of_pdus > 0 && UL_info->crc_ind.number_crcs > 0) { if (UL_info->rx_ind.number_of_pdus > 0 && UL_info->crc_ind.number_crcs > 0) {
......
...@@ -1644,7 +1644,8 @@ uint16_t do_RRCReconfiguration( ...@@ -1644,7 +1644,8 @@ uint16_t do_RRCReconfiguration(
// 1, // 1,
// 1, // 1,
// carrier->pdsch_AntennaPorts, // carrier->pdsch_AntennaPorts,
// carrier->initial_csi_index[gnb_rrc_inst->Nb_ue]); // carrier->initial_csi_index[ue_context_p->local_uid + 1],
// ue_context_pP->local_uid);
/******************** Meas Config ********************/ /******************** Meas Config ********************/
// measConfig // measConfig
......
...@@ -85,14 +85,16 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -85,14 +85,16 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
int scg_id, int scg_id,
int servCellIndex, int servCellIndex,
int n_physical_antenna_ports, int n_physical_antenna_ports,
int initial_csi_index); int initial_csi_index,
int uid);
void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon, void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon,
NR_ServingCellConfig_t *servingcellconfigdedicated, NR_ServingCellConfig_t *servingcellconfigdedicated,
NR_RRCReconfiguration_IEs_t *reconfig, NR_RRCReconfiguration_IEs_t *reconfig,
NR_CellGroupConfig_t *secondaryCellGroup, NR_CellGroupConfig_t *secondaryCellGroup,
int n_physical_antenna_ports, int n_physical_antenna_ports,
int initial_csi_index); int initial_csi_index,
int uid);
void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig, void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig,
int eps_bearer_id, int rb_id, int eps_bearer_id, int rb_id,
......
...@@ -152,7 +152,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ...@@ -152,7 +152,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
ue_context_p->ue_context.reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; ue_context_p->ue_context.reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
NR_RRCReconfiguration_IEs_t *reconfig_ies=calloc(1,sizeof(NR_RRCReconfiguration_IEs_t)); NR_RRCReconfiguration_IEs_t *reconfig_ies=calloc(1,sizeof(NR_RRCReconfiguration_IEs_t));
ue_context_p->ue_context.reconfig->criticalExtensions.choice.rrcReconfiguration = reconfig_ies; ue_context_p->ue_context.reconfig->criticalExtensions.choice.rrcReconfiguration = reconfig_ies;
carrier->initial_csi_index[rrc->Nb_ue] = 0; carrier->initial_csi_index[ue_context_p->local_uid + 1] = 0;
ue_context_p->ue_context.rb_config = calloc(1,sizeof(NR_RRCReconfiguration_t)); ue_context_p->ue_context.rb_config = calloc(1,sizeof(NR_RRCReconfiguration_t));
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1 || get_softmodem_params()->sa == 1){ if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1 || get_softmodem_params()->sa == 1){
fill_default_rbconfig(ue_context_p->ue_context.rb_config, fill_default_rbconfig(ue_context_p->ue_context.rb_config,
...@@ -245,14 +245,16 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ...@@ -245,14 +245,16 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
reconfig_ies, reconfig_ies,
ue_context_p->ue_context.secondaryCellGroup, ue_context_p->ue_context.secondaryCellGroup,
carrier->pdsch_AntennaPorts, carrier->pdsch_AntennaPorts,
carrier->initial_csi_index[rrc->Nb_ue]); carrier->initial_csi_index[ue_context_p->local_uid + 1],
ue_context_p->local_uid);
} else { } else {
fill_default_reconfig(carrier->servingcellconfigcommon, fill_default_reconfig(carrier->servingcellconfigcommon,
NULL, NULL,
reconfig_ies, reconfig_ies,
ue_context_p->ue_context.secondaryCellGroup, ue_context_p->ue_context.secondaryCellGroup,
carrier->pdsch_AntennaPorts, carrier->pdsch_AntennaPorts,
carrier->initial_csi_index[rrc->Nb_ue]); carrier->initial_csi_index[ue_context_p->local_uid + 1],
ue_context_p->local_uid);
} }
ue_context_p->ue_id_rnti = ue_context_p->ue_context.secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity; ue_context_p->ue_id_rnti = ue_context_p->ue_context.secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
NR_CG_Config_t *CG_Config = calloc(1,sizeof(*CG_Config)); NR_CG_Config_t *CG_Config = calloc(1,sizeof(*CG_Config));
......
...@@ -129,7 +129,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -129,7 +129,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
int scg_id, int scg_id,
int servCellIndex, int servCellIndex,
int n_physical_antenna_ports, int n_physical_antenna_ports,
int initial_csi_index) { int initial_csi_index,
int uid) {
AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n"); AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n"); AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
...@@ -172,7 +173,17 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -172,7 +173,17 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig)); secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig));
secondaryCellGroup->mac_CellGroupConfig->drx_Config = NULL; secondaryCellGroup->mac_CellGroupConfig->drx_Config = NULL;
secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = NULL;
secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig));
secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList));
NR_SchedulingRequestToAddMod_t *SchedulingRequestConf = calloc(1,sizeof(*SchedulingRequestConf));
SchedulingRequestConf->schedulingRequestId = 0; //Could be changed
SchedulingRequestConf->sr_ProhibitTimer = calloc(1,sizeof(*SchedulingRequestConf->sr_ProhibitTimer));
*SchedulingRequestConf->sr_ProhibitTimer = NR_SchedulingRequestToAddMod__sr_ProhibitTimer_ms16;
SchedulingRequestConf->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n32;
ASN_SEQUENCE_ADD(&secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list,SchedulingRequestConf);
secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToReleaseList = NULL;
secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config)); secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config));
secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10;
secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf160; secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf160;
...@@ -239,7 +250,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -239,7 +250,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
if ((bitmap>>(63-i))&0x01){ if ((bitmap>>(63-i))&0x01){
ssbElem[n_ssb] = calloc(1,sizeof(struct NR_CFRA_SSB_Resource)); ssbElem[n_ssb] = calloc(1,sizeof(struct NR_CFRA_SSB_Resource));
ssbElem[n_ssb]->ssb = i; ssbElem[n_ssb]->ssb = i;
ssbElem[n_ssb]->ra_PreambleIndex = 63; ssbElem[n_ssb]->ra_PreambleIndex = 63 - (uid % 64);
ASN_SEQUENCE_ADD(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list,ssbElem[n_ssb]); ASN_SEQUENCE_ADD(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list,ssbElem[n_ssb]);
n_ssb++; n_ssb++;
} }
...@@ -251,8 +262,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -251,8 +262,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants)); secondaryCellGroup->spCellConfig->rlf_TimersAndConstants = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants));
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->present = NR_SetupRelease_RLF_TimersAndConstants_PR_setup; secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->present = NR_SetupRelease_RLF_TimersAndConstants_PR_setup;
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup)); secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup));
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->t310 = NR_RLF_TimersAndConstants__t310_ms2000; secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->t310 = NR_RLF_TimersAndConstants__t310_ms4000;
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n310 = NR_RLF_TimersAndConstants__n310_n10; secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n310 = NR_RLF_TimersAndConstants__n310_n20;
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n311 = NR_RLF_TimersAndConstants__n311_n1; secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n311 = NR_RLF_TimersAndConstants__n311_n1;
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1 = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1)); secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1 = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1));
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1->t311 = NR_RLF_TimersAndConstants__ext1__t311_ms30000; secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1->t311 = NR_RLF_TimersAndConstants__ext1__t311_ms30000;
...@@ -963,7 +974,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -963,7 +974,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2));
NR_PUCCH_Resource_t *pucchres3=calloc(1,sizeof(*pucchres3)); NR_PUCCH_Resource_t *pucchres3=calloc(1,sizeof(*pucchres3));
pucchres0->pucch_ResourceId=1; pucchres0->pucch_ResourceId=1;
pucchres0->startingPRB=8; pucchres0->startingPRB= (8 + uid) % curr_bwp;
pucchres0->intraSlotFrequencyHopping=NULL; pucchres0->intraSlotFrequencyHopping=NULL;
pucchres0->secondHopPRB=NULL; pucchres0->secondHopPRB=NULL;
pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0;
...@@ -974,7 +985,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -974,7 +985,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0);
pucchres1->pucch_ResourceId=2; pucchres1->pucch_ResourceId=2;
pucchres1->startingPRB=8; pucchres1->startingPRB= (8 + uid) % curr_bwp;
pucchres1->intraSlotFrequencyHopping=NULL; pucchres1->intraSlotFrequencyHopping=NULL;
pucchres1->secondHopPRB=NULL; pucchres1->secondHopPRB=NULL;
pucchres1->format.present= NR_PUCCH_Resource__format_PR_format0; pucchres1->format.present= NR_PUCCH_Resource__format_PR_format0;
...@@ -1017,7 +1028,19 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -1017,7 +1028,19 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
pucchfmt2->nrofSlots=NULL; pucchfmt2->nrofSlots=NULL;
pucchfmt2->pi2BPSK=NULL; pucchfmt2->pi2BPSK=NULL;
pucchfmt2->simultaneousHARQ_ACK_CSI=NULL; pucchfmt2->simultaneousHARQ_ACK_CSI=NULL;
pucch_Config->schedulingRequestResourceToAddModList=NULL;
// for scheduling requestresource
pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList));
NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig));
schedulingRequestResourceConfig->schedulingRequestResourceId = 1;
schedulingRequestResourceConfig->schedulingRequestID = 0;
schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset));
schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10;
schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7;
schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource));
*schedulingRequestResourceConfig->resource = 1;
ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig);
pucch_Config->schedulingRequestResourceToReleaseList=NULL; pucch_Config->schedulingRequestResourceToReleaseList=NULL;
pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; pucch_Config->multi_CSI_PUCCH_ResourceList=NULL;
pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK));
...@@ -1165,7 +1188,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -1165,7 +1188,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic;
csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic)); csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic));
csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320;
csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 49; csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 9 + (10 * uid) % 320;
NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1,sizeof(*pucchcsires1)); NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1,sizeof(*pucchcsires1));
pucchcsires1->uplinkBandwidthPartId=1; pucchcsires1->uplinkBandwidthPartId=1;
pucchcsires1->pucch_Resource=3; pucchcsires1->pucch_Resource=3;
...@@ -1229,14 +1252,22 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon ...@@ -1229,14 +1252,22 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon
NR_RRCReconfiguration_IEs_t *reconfig, NR_RRCReconfiguration_IEs_t *reconfig,
NR_CellGroupConfig_t *secondaryCellGroup, NR_CellGroupConfig_t *secondaryCellGroup,
int n_physical_antenna_ports, int n_physical_antenna_ports,
int initial_csi_index) { int initial_csi_index,
int uid) {
AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n"); AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
AssertFatal(reconfig!=NULL,"reconfig is null\n"); AssertFatal(reconfig!=NULL,"reconfig is null\n");
AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n"); AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
// radioBearerConfig // radioBearerConfig
reconfig->radioBearerConfig=NULL; reconfig->radioBearerConfig=NULL;
// secondaryCellGroup // secondaryCellGroup
fill_default_secondaryCellGroup(servingcellconfigcommon,servingcellconfigdedicated,secondaryCellGroup,1,1,n_physical_antenna_ports,initial_csi_index); fill_default_secondaryCellGroup(servingcellconfigcommon,
servingcellconfigdedicated,
secondaryCellGroup,
1,
1,
n_physical_antenna_ports,
initial_csi_index,
uid);
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
char scg_buffer[1024]; char scg_buffer[1024];
......
...@@ -130,6 +130,18 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa ...@@ -130,6 +130,18 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa
DevAssert(x2ap_enb_data_p != NULL); DevAssert(x2ap_enb_data_p != NULL);
dump_trees(); dump_trees();
/* gNB: exit if connection to eNB failed - to be modified if needed.
* We may want to try to connect over and over again until we succeed
* but the modifications to the code to get this behavior are complex.
* Exit on error is a simple solution that can be caught by a script
* for example.
*/
if (instance_p->cell_type == CELL_MACRO_GNB
&& sctp_new_association_resp->sctp_state == SCTP_STATE_UNREACHABLE) {
X2AP_ERROR("association with eNB failed, is it running? If no, run it first. If yes, check IP addresses in your configuration file.\n");
exit(1);
}
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
X2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n", X2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
sctp_new_association_resp->sctp_state, sctp_new_association_resp->sctp_state,
......
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