Commit cf1822be authored by Remi Hardy's avatar Remi Hardy

Integration 2021 wk18 a

MR !1145 NR_FR2_initsync_fixes
-bug fixes that caused failure in PBCH detection after initial sync in FR2

MR !1100 NR_scheduling_request
-per-UE PUCCH F0 resource, CSI, Preamble 
-Scheduling Request 
-MAC scheduler fixes

MR !1150  rh_ci_phy_test_improve
-beautified HTML report for 5G NR phy test

MR !1113 hack-exit-gnb-when-no-enb-nsa
-Exit gNB 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
parents 158c0639 c2acb9e9
#!/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>
......
...@@ -552,7 +552,7 @@ void *UE_thread(void *arg) { ...@@ -552,7 +552,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;
...@@ -692,9 +692,9 @@ void *UE_thread(void *arg) { ...@@ -692,9 +692,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;
......
...@@ -142,7 +142,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, ...@@ -142,7 +142,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
case FAPI_NR_RX_PDU_TYPE_MIB: case FAPI_NR_RX_PDU_TYPE_MIB:
rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.pdu = ue->pbch_vars[gNB_id]->decoded_output; rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.pdu = ue->pbch_vars[gNB_id]->decoded_output;
rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.additional_bits = ue->pbch_vars[gNB_id]->xtra_byte; rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.additional_bits = ue->pbch_vars[gNB_id]->xtra_byte;
rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_index = frame_parms->ssb_index; rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_index = (frame_parms->ssb_index)&0x7;
rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_length = frame_parms->Lmax; rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_length = frame_parms->Lmax;
rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.cell_id = frame_parms->Nid_cell; rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.cell_id = frame_parms->Nid_cell;
break; break;
...@@ -350,7 +350,7 @@ void nr_ue_pbch_procedures(uint8_t gNB_id, ...@@ -350,7 +350,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],
......
...@@ -733,13 +733,7 @@ int main(int argc, char **argv) ...@@ -733,13 +733,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);
......
...@@ -676,13 +676,7 @@ int main(int argc, char **argv) ...@@ -676,13 +676,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,7 +55,7 @@ ...@@ -55,7 +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"
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* MacRLC configuration parameters */ /* MacRLC configuration parameters */
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,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}, \
} }
#define MACRLC_CC_IDX 0 #define MACRLC_CC_IDX 0
#define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1
...@@ -97,5 +98,6 @@ ...@@ -97,5 +98,6 @@
#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
/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
#endif #endif
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
//#include "L1_paramdef.h" //#include "L1_paramdef.h"
#include "L1_nr_paramdef.h" #include "L1_nr_paramdef.h"
#include "MACRLC_paramdef.h" #include "MACRLC_nr_paramdef.h"
#include "common/config/config_userapi.h" #include "common/config/config_userapi.h"
//#include "RRC_config_tools.h" //#include "RRC_config_tools.h"
#include "gnb_paramdef.h" #include "gnb_paramdef.h"
...@@ -698,6 +698,7 @@ void RCconfig_nr_macrlc() { ...@@ -698,6 +698,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
AssertFatal (0,"No " CONFIG_STRING_MACRLC_LIST " configuration found"); AssertFatal (0,"No " CONFIG_STRING_MACRLC_LIST " configuration found");
......
...@@ -372,14 +372,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, ...@@ -372,14 +372,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(MAC,"Configuring common parameters from NR ServingCellConfig\n"); LOG_I(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)
......
...@@ -253,8 +253,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ...@@ -253,8 +253,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){
......
...@@ -118,8 +118,13 @@ int diff_rsrp_ssb_csi_meas_10_1_6_1_2[16] = { ...@@ -118,8 +118,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]) {
...@@ -504,11 +509,11 @@ void nr_csi_meas_reporting(int Mod_idP, ...@@ -504,11 +509,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;
...@@ -1007,14 +1012,6 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, ...@@ -1007,14 +1012,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)
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;
NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon;
const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
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++) {
...@@ -1029,6 +1026,20 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, ...@@ -1029,6 +1026,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,
...@@ -1051,8 +1062,6 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, ...@@ -1051,8 +1062,6 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
30); 30);
sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640; sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640;
NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon;
const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
if ((uci_234->pduBitmap >> 1) & 0x01) { if ((uci_234->pduBitmap >> 1) & 0x01) {
// iterate over received harq bits // iterate over received harq bits
for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) {
...@@ -1104,10 +1113,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1104,10 +1113,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];
AssertFatal(pucch->csi_bits == 0, AssertFatal(pucch->csi_bits == 0,
...@@ -1115,12 +1121,8 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1115,12 +1121,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;
...@@ -1130,7 +1132,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1130,7 +1132,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
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
...@@ -1142,6 +1144,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1142,6 +1144,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;
} }
...@@ -1160,9 +1163,8 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1160,9 +1163,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);
...@@ -1193,18 +1195,14 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1193,18 +1195,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 = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
DevAssert(pucch_Config->resourceToAddModList->list.count > 0);
DevAssert(pucch_Config->resourceSetToAddModList->list.count > 0);
const int n_res = pucch_Config->resourceSetToAddModList->list.array[0]->resourceList.list.count;
int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[sched_ctrl->active_ubwp->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__);
...@@ -1212,27 +1210,11 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1212,27 +1210,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
...@@ -1244,6 +1226,7 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1244,6 +1226,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;
...@@ -1274,29 +1257,19 @@ bool nr_acknack_scheduling(int mod_id, ...@@ -1274,29 +1257,19 @@ bool nr_acknack_scheduling(int mod_id,
pucch->timing_indicator = i; // index in the list of timing indicators pucch->timing_indicator = i; // index in the list of timing indicators
pucch->dai_c++; pucch->dai_c++;
const int pucch_res = pucch_index_used[pucch->ul_slot]; 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!*/
const NR_PUCCH_Resource_t *resource = const NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
pucch_Config->resourceToAddModList->list.array[pucch_res]; const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator];
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;
...@@ -1429,3 +1402,154 @@ uint16_t compute_pucch_prb_size(uint8_t format, ...@@ -1429,3 +1402,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");
}
}
...@@ -745,6 +745,34 @@ long get_K2(const NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) { ...@@ -745,6 +745,34 @@ long get_K2(const NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
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)
...@@ -874,7 +902,6 @@ void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_pusch_semi_static ...@@ -874,7 +902,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,
...@@ -894,12 +921,6 @@ void pf_ul(module_id_t module_id, ...@@ -894,12 +921,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]) {
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];
...@@ -931,11 +952,16 @@ void pf_ul(module_id_t module_id, ...@@ -931,11 +952,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)
continue; if (B == 0 && !do_sched)
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) {
...@@ -1106,7 +1132,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t ...@@ -1106,7 +1132,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t
int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu); int K2 = get_K2(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;
...@@ -1218,6 +1244,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1218,6 +1244,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;
...@@ -1225,6 +1252,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1225,6 +1252,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) {
...@@ -1281,6 +1309,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ...@@ -1281,6 +1309,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(MAC, LOG_D(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",
......
...@@ -414,4 +414,10 @@ bool nr_find_nb_rb(uint16_t Qm, ...@@ -414,4 +414,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__*/
...@@ -522,11 +522,9 @@ typedef struct { ...@@ -522,11 +522,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;
...@@ -547,6 +545,9 @@ typedef struct { ...@@ -547,6 +545,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;
...@@ -563,6 +564,8 @@ typedef struct { ...@@ -563,6 +564,8 @@ typedef struct {
int pucch_snrx10; int pucch_snrx10;
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
...@@ -705,10 +708,6 @@ typedef struct gNB_MAC_INST_s { ...@@ -705,10 +708,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];
...@@ -722,6 +721,9 @@ typedef struct gNB_MAC_INST_s { ...@@ -722,6 +721,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
......
...@@ -73,7 +73,8 @@ void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChann ...@@ -73,7 +73,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,10 +105,6 @@ void handle_nr_uci(NR_UL_IND_t *UL_info) ...@@ -105,10 +105,6 @@ 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 1, to be revised for multiple BWPs
RC.nrmac[mod_id]->pucch_index_used[1][slot] = 0;
} }
......
...@@ -1287,7 +1287,8 @@ uint16_t do_RRCReconfiguration( ...@@ -1287,7 +1287,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));
......
...@@ -149,7 +149,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -149,7 +149,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");
...@@ -184,7 +185,17 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -184,7 +185,17 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
ASN_SEQUENCE_ADD(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig); ASN_SEQUENCE_ADD(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig);
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;
...@@ -251,7 +262,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -251,7 +262,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++;
} }
...@@ -263,8 +274,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -263,8 +274,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;
...@@ -975,7 +986,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -975,7 +986,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;
...@@ -986,7 +997,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -986,7 +997,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;
...@@ -1029,7 +1040,19 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -1029,7 +1040,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));
...@@ -1177,7 +1200,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco ...@@ -1177,7 +1200,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;
...@@ -1241,14 +1264,22 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon ...@@ -1241,14 +1264,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