From a4361e329113e228d78532d7ac9446a27a60e319 Mon Sep 17 00:00:00 2001
From: Raphael Defosseux <raphael.defosseux@eurecom.fr>
Date: Mon, 11 Mar 2019 19:23:26 +0100
Subject: [PATCH] CI: adding LTE-M testing support

Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
---
 .../conf_files/enb.band13.tm1.50PRB.emtc.conf |  39 +++--
 ci-scripts/main.py                            | 161 +++++++++++++++++-
 .../xml_files/enb_usrp210_band13_build.xml    |  55 ++++++
 .../enb_usrp210_band13_epc_closure.xml        |  47 +++++
 .../enb_usrp210_band13_test_10mhz_tm1.xml     |  78 +++++++++
 5 files changed, 363 insertions(+), 17 deletions(-)
 create mode 100644 ci-scripts/xml_files/enb_usrp210_band13_build.xml
 create mode 100644 ci-scripts/xml_files/enb_usrp210_band13_epc_closure.xml
 create mode 100644 ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml

diff --git a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
index e3d3402c1c..a3f3df6328 100644
--- a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
+++ b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
@@ -13,9 +13,9 @@ eNBs =
     eNB_name  =  "eNB_Eurecom_LTEBox";
 
     // Tracking area code, 0x0000 and 0xfffe are reserved values
-    tracking_area_code  =  "1";
+    tracking_area_code  = 1;
 
-    plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2;} );
+    plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2;} );
 
     tr_s_preference     = "local_mac"
 
@@ -48,10 +48,10 @@ eNBs =
       prach_zero_correlation                    = 1;
       prach_freq_offset                         = 1;
       pucch_delta_shift                         = 1;
-      pucch_nRB_CQI                             = 1;
+      pucch_nRB_CQI                             = 0;
       pucch_nCS_AN                              = 0;    
-      pucch_n1_AN                               = 32;
-      pdsch_referenceSignalPower                = -27;
+      pucch_n1_AN                               = 0;
+      pdsch_referenceSignalPower                = -24;
       pdsch_p_b                                 = 0;
       pusch_n_SB                                = 1;
       pusch_enable64QAM                         = "DISABLE";
@@ -190,7 +190,7 @@ eNBs =
           prach_freq_offset                         = 1;
 
           #PDSCH Config Common          
-          pdsch_referenceSignalPower                = -27
+          pdsch_referenceSignalPower                = -24
           pdsch_p_b                                 = 0;
 
 
@@ -208,7 +208,7 @@ eNBs =
           pucch_delta_shift                         = 1;
           pucch_nRB_CQI                             = 0;
           pucch_nCS_AN                              = 0;
-          pucch_n1_AN                               = 32;
+          pucch_n1_AN                               = 0;
 
           pusch_p0_Nominal                          = -96;
           pusch_alpha                               = "AL1";
@@ -262,7 +262,7 @@ eNBs =
           n1PUCCH_AN_InfoList_r13 = 
           (
               {
-                  pucch_info_value = 0;
+                  pucch_info_value = 33;
               }
           );
           
@@ -417,12 +417,31 @@ RUs = (
         att_tx         = 0
         att_rx         = 0;
         bands          = [13];
-        max_pdschReferenceSignalPower = -27;
-        max_rxgain                    = 125;
+        max_pdschReferenceSignalPower = -24;
+        max_rxgain                    = 110;
         eNB_instances  = [0];
     }
 );  
 
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+NETWORK_CONTROLLER :
+{
+    FLEXRAN_ENABLED        = "no";
+    FLEXRAN_INTERFACE_NAME = "lo";
+    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_PORT           = 2210;
+    FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
+    FLEXRAN_AWAIT_RECONF   = "no";
+};
+
 log_config :
      {
        global_log_level                      ="info";
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 5e89384ebb..e8172cf9f6 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -123,6 +123,7 @@ class SSHConnection():
 		self.eNBOsVersion = ''
 		self.eNBKernelVersion = ''
 		self.eNBUhdVersion = ''
+		self.eNBUsrpBoard = ''
 		self.eNBCpuNb = ''
 		self.eNBCpuModel = ''
 		self.eNBCpuMHz = ''
@@ -408,6 +409,11 @@ class SSHConnection():
 				self.command('echo $USER; nohup sudo tshark -f "host ' + self.eNBIPAddress +'" -i ' + eth_interface + ' -w /tmp/enb_' + self.testCase_id + '_s1log.pcap > /tmp/tshark.log 2>&1 &', self.EPCUserName, 5)
 			self.close()
 		self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword)
+		self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 5)
+		result = re.search('type: b200', str(self.ssh.before))
+		if result is not None:
+			logging.debug('Found a B2xx device --> resetting it')
+			self.command('echo ' + self.eNBPassword + ' | sudo -S sudo b2xx_fx3_utils --reset-device', '\$', 5)
 		self.command('cd ' + self.eNBSourceCodePath, '\$', 5)
 		# Initialize_eNB_args usually start with -O and followed by the location in repository
 		full_config_file = self.Initialize_eNB_args.replace('-O ','')
@@ -604,21 +610,150 @@ class SSHConnection():
 		time.sleep(4)
 		# We should check if we register
 		count = 0
-		while count < 3:
+		attach_cnt = 0
+		attach_status = False
+		while count < 5:
 			self.command('AT+CEREG?', 'OK', 5)
-			result = re.search('CEREG: 2,(?P<state>[0-9\-]+)', str(self.ssh.before))
+			result = re.search('CEREG: 2,(?P<state>[0-9\-]+),', str(self.ssh.before))
 			if result is not None:
 				mDataConnectionState = int(result.group('state'))
 				if mDataConnectionState is not None:
-					logging.debug('+CEREG: 2,' + str(mDataConnectionState))
+					if mDataConnectionState == 1:
+						count = 10
+						attach_status = True
+						result = re.search('CEREG: 2,1,"(?P<networky>[0-9A-Z]+)","(?P<networkz>[0-9A-Z]+)"', str(self.ssh.before))
+						if result is not None:
+							networky = result.group('networky')
+							networkz = result.group('networkz')
+							logging.debug('\u001B[1m CAT-M module attached to eNB (' + str(networky) + '/' + str(networkz) + ')\u001B[0m')
+						else:
+							logging.debug('\u001B[1m CAT-M module attached to eNB\u001B[0m')
+					else:
+						logging.debug('+CEREG: 2,' + str(mDataConnectionState))
+						attach_cnt = attach_cnt + 1
 			else:
 				logging.debug(str(self.ssh.before))
+				attach_cnt = attach_cnt + 1
 			count = count + 1
 			time.sleep(1)
+		if attach_status:
+			self.command('AT+CESQ', 'OK', 5)
+			result = re.search('CESQ: 99,99,255,255,(?P<rsrq>[0-9]+),(?P<rsrp>[0-9]+)', str(self.ssh.before))
+			if result is not None:
+				nRSRQ = int(result.group('rsrq'))
+				nRSRP = int(result.group('rsrp'))
+				if (nRSRQ is not None) and (nRSRP is not None):
+					logging.debug('    RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB')
+					logging.debug('    RSRP = ' + str(-140+nRSRP) + ' dBm')
 		self.close()
 		self.picocom_closure = False
-		self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK)
+		html_queue = SimpleQueue()
 		self.checkDevTTYisUnlocked()
+		if attach_status:
+			html_cell = '<pre style="background-color:white">CAT-M module\nAttach Attach Completed in ' + str(attach_cnt+4) + ' seconds'
+			if (nRSRQ is not None) and (nRSRP is not None):
+				html_cell += '\n   RSRQ = ' + str(-20+(nRSRQ/2)) + ' dB'
+				html_cell += '\n   RSRP = ' + str(-140+nRSRP) + ' dBm</pre>'
+			else:
+				html_cell += '</pre>'
+			html_queue.put(html_cell)
+			self.CreateHtmlTestRowQueue('N/A', 'OK', 1, html_queue)
+		else:
+			html_cell = '<pre style="background-color:white">CAT-M module\nAttach Failed</pre>'
+			html_queue.put(html_cell)
+			self.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue)
+
+	def PingCatM(self):
+		if self.EPCIPAddress == '' or self.EPCUserName == '' or self.EPCPassword == '' or self.EPCSourceCodePath == '':
+			Usage()
+			sys.exit('Insufficient Parameter')
+		initialize_eNB_flag = False
+		pStatus = self.CheckProcessExist(initialize_eNB_flag)
+		if (pStatus < 0):
+			self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
+			self.CreateHtmlTabFooter(False)
+			sys.exit(1)
+		try:
+			statusQueue = SimpleQueue()
+			lock = Lock()
+			self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword)
+			self.command('cd ' + self.EPCSourceCodePath, '\$', 5)
+			self.command('cd scripts', '\$', 5)
+			if re.match('OAI', self.EPCType, re.IGNORECASE):
+				logging.debug('Using the OAI EPC HSS: not implemented yet')
+				self.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
+				self.CreateHtmlTabFooter(False)
+				sys.exit(1)
+			else:
+				self.command('egrep --color=never "Allocated ipv4 addr" /opt/ltebox/var/log/xGwLog.0', '\$', 5)
+				result = re.search('Allocated ipv4 addr: (?P<ipaddr>[0-9\.]+) from Pool', str(self.ssh.before))
+				if result is not None:
+					moduleIPAddr = result.group('ipaddr')
+				else:
+					return
+			ping_time = re.findall("-c (\d+)",str(self.ping_args))
+			device_id = 'catm'
+			ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee -a ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)
+			# TIMEOUT CASE
+			if ping_status < 0:
+				message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!'
+				logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m')
+				self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message)
+				return
+			result = re.search(', (?P<packetloss>[0-9\.]+)% packet loss, time [0-9\.]+ms', str(self.ssh.before))
+			if result is None:
+				message = 'Packet Loss Not Found!'
+				logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m')
+				self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message)
+				return
+			packetloss = result.group('packetloss')
+			if float(packetloss) == 100:
+				message = 'Packet Loss is 100%'
+				logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m')
+				self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message)
+				return
+			result = re.search('rtt min\/avg\/max\/mdev = (?P<rtt_min>[0-9\.]+)\/(?P<rtt_avg>[0-9\.]+)\/(?P<rtt_max>[0-9\.]+)\/[0-9\.]+ ms', str(self.ssh.before))
+			if result is None:
+				message = 'Ping RTT_Min RTT_Avg RTT_Max Not Found!'
+				logging.debug('\u001B[1;37;41m ' + message + ' \u001B[0m')
+				self.ping_iperf_wrong_exit(lock, moduleIPAddr, device_id, statusQueue, message)
+				return
+			rtt_min = result.group('rtt_min')
+			rtt_avg = result.group('rtt_avg')
+			rtt_max = result.group('rtt_max')
+			pal_msg = 'Packet Loss : ' + packetloss + '%'
+			min_msg = 'RTT(Min)    : ' + rtt_min + ' ms'
+			avg_msg = 'RTT(Avg)    : ' + rtt_avg + ' ms'
+			max_msg = 'RTT(Max)    : ' + rtt_max + ' ms'
+			lock.acquire()
+			logging.debug('\u001B[1;37;44m ping result (' + moduleIPAddr + ') \u001B[0m')
+			logging.debug('\u001B[1;34m    ' + pal_msg + '\u001B[0m')
+			logging.debug('\u001B[1;34m    ' + min_msg + '\u001B[0m')
+			logging.debug('\u001B[1;34m    ' + avg_msg + '\u001B[0m')
+			logging.debug('\u001B[1;34m    ' + max_msg + '\u001B[0m')
+			qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg
+			packetLossOK = True
+			if packetloss is not None:
+				if float(packetloss) > float(self.ping_packetloss_threshold):
+					qMsg += '\nPacket Loss too high'
+					logging.debug('\u001B[1;37;41m Packet Loss too high \u001B[0m')
+					packetLossOK = False
+				elif float(packetloss) > 0:
+					qMsg += '\nPacket Loss is not 0%'
+					logging.debug('\u001B[1;30;43m Packet Loss is not 0% \u001B[0m')
+			lock.release()
+			self.close()
+			html_cell = '<pre style="background-color:white">CAT-M module\nIP Address  : ' + moduleIPAddr + '\n' + qMsg + '</pre>'
+			statusQueue.put(html_cell)
+			if (packetLossOK):
+				self.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue)
+			else:
+				self.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue)
+				self.AutoTerminateUEandeNB()
+				self.CreateHtmlTabFooter(False)
+				sys.exit(1)
+		except:
+			os.kill(os.getppid(),signal.SIGUSR1)
 
 	def AttachUE_common(self, device_id, statusQueue, lock):
 		try:
@@ -1969,6 +2104,7 @@ class SSHConnection():
 			self.eNBOsVersion = 'Ubuntu 16.04.5 LTS'
 			self.eNBKernelVersion = '4.15.0-45-generic'
 			self.eNBUhdVersion = '3.13.0.1-0'
+			self.eNBUsrpBoard = 'B210'
 			self.eNBCpuNb = '4'
 			self.eNBCpuModel = 'Intel(R) Core(TM) i5-6200U'
 			self.eNBCpuMHz = '2399.996 MHz'
@@ -1992,6 +2128,11 @@ class SSHConnection():
 		if result is not None:
 			self.eNBUhdVersion = result.group('uhd_version')
 			logging.debug('UHD Version is: ' + self.eNBUhdVersion)
+		self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 5)
+		result = re.search('product: (?P<usrp_board>[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before))
+		if result is not None:
+			self.eNBUsrpBoard = result.group('usrp_board')
+			logging.debug('USRP Board  is: ' + self.eNBUsrpBoard)
 		self.command('lscpu', '\$', 5)
 		result = re.search('CPU\(s\): *(?P<nb_cpus>[0-9]+).*Model name: *(?P<model>[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P<cpu_mhz>[0-9\.]+)', str(self.ssh.before))
 		if result is not None:
@@ -2169,7 +2310,7 @@ class SSHConnection():
 			self.htmlFile.write('  <p></p>\n')
 			self.htmlFile.write('  <table class="table table-condensed">\n')
 			self.htmlFile.write('      <tr>\n')
-			self.htmlFile.write('        <th colspan=6>eNB Server Characteristics</th>\n')
+			self.htmlFile.write('        <th colspan=8>eNB Server Characteristics</th>\n')
 			self.htmlFile.write('      </tr>\n')
 			self.htmlFile.write('      <tr>\n')
 			self.htmlFile.write('        <td>OS Version</td>\n')
@@ -2178,6 +2319,8 @@ class SSHConnection():
 			self.htmlFile.write('        <td><span class="label label-default">' + self.eNBKernelVersion + '</span></td>\n')
 			self.htmlFile.write('        <td>UHD Version</td>\n')
 			self.htmlFile.write('        <td><span class="label label-default">' + self.eNBUhdVersion + '</span></td>\n')
+			self.htmlFile.write('        <td>USRP Board</td>\n')
+			self.htmlFile.write('        <td><span class="label label-default">' + self.eNBUsrpBoard + '</span></td>\n')
 			self.htmlFile.write('      </tr>\n')
 			self.htmlFile.write('      <tr>\n')
 			self.htmlFile.write('        <td>Nb CPUs</td>\n')
@@ -2186,6 +2329,8 @@ class SSHConnection():
 			self.htmlFile.write('        <td><span class="label label-default">' + self.eNBCpuModel + '</span></td>\n')
 			self.htmlFile.write('        <td>CPU Frequency</td>\n')
 			self.htmlFile.write('        <td><span class="label label-default">' + self.eNBCpuMHz + '</span></td>\n')
+			self.htmlFile.write('        <td></td>\n')
+			self.htmlFile.write('        <td></td>\n')
 			self.htmlFile.write('      </tr>\n')
 			self.htmlFile.write('      <tr>\n')
 			self.htmlFile.write('        <th colspan=4 bgcolor = "#33CCFF">Final Status</th>\n')
@@ -2326,7 +2471,7 @@ def Usage():
 	print('------------------------------------------------------------')
 
 def CheckClassValidity(action,id):
-	if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW'  and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'IdleSleep':
+	if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW'  and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep':
 		logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action)
 		return False
 	return True
@@ -2353,7 +2498,7 @@ def GetParametersFromXML(action):
 		else:
 			SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach)
 
-	if action == 'Ping':
+	if action == 'Ping' or action == 'Ping_CatM_module':
 		SSH.ping_args = test.findtext('ping_args')
 		SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold')
 
@@ -2651,6 +2796,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE):
 				SSH.AttachCatM()
 			elif action == 'Detach_CatM_module':
 				SSH.TerminateCatM()
+			elif action == 'Ping_CatM_module':
+				SSH.PingCatM()
 			elif action == 'Ping':
 				SSH.Ping()
 			elif action == 'Iperf':
diff --git a/ci-scripts/xml_files/enb_usrp210_band13_build.xml b/ci-scripts/xml_files/enb_usrp210_band13_build.xml
new file mode 100644
index 0000000000..24283a52d0
--- /dev/null
+++ b/ci-scripts/xml_files/enb_usrp210_band13_build.xml
@@ -0,0 +1,55 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>build-tab</htmlTabRef>
+	<htmlTabName>Build</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 010101
+ 050101 060101 070101
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="010101">
+		<class>Build_eNB</class>
+		<desc>Build eNB (USRP)</desc>
+		<Build_eNB_args>-w USRP -c --eNB</Build_eNB_args>
+	</testCase>
+
+        <testCase id="050101">
+		<class>Initialize_HSS</class>
+		<desc>Initialize HSS</desc>
+        </testCase>
+
+	<testCase id="060101">
+		<class>Initialize_MME</class>
+		<desc>Initialize MME</desc>
+	</testCase>
+
+	<testCase id="070101">
+		<class>Initialize_SPGW</class>
+		<desc>Initialize SPGW</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/enb_usrp210_band13_epc_closure.xml b/ci-scripts/xml_files/enb_usrp210_band13_epc_closure.xml
new file mode 100644
index 0000000000..07fb6951f8
--- /dev/null
+++ b/ci-scripts/xml_files/enb_usrp210_band13_epc_closure.xml
@@ -0,0 +1,47 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-closure</htmlTabRef>
+	<htmlTabName>EPC-Closure</htmlTabName>
+	<htmlTabIcon>log-out</htmlTabIcon>
+	<TestCaseRequestedList>
+ 050201 060201 070201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="050201">
+		<class>Terminate_HSS</class>
+		<desc>Terminate HSS</desc>
+	</testCase>
+
+	<testCase id="060201">
+		<class>Terminate_MME</class>
+		<desc>Terminate MME</desc>
+	</testCase>
+
+	<testCase id="070201">
+		<class>Terminate_SPGW</class>
+		<desc>Terminate SPGW</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml
new file mode 100644
index 0000000000..ad543403d6
--- /dev/null
+++ b/ci-scripts/xml_files/enb_usrp210_band13_test_10mhz_tm1.xml
@@ -0,0 +1,78 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>test-10-tm1</htmlTabRef>
+	<htmlTabName>Test-10MHz-TM1</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<TestCaseRequestedList>
+ 040102
+ 030121 000001 040302 000001 040502 000001 040402 040202 000001 030201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+        <testCase id="000001">
+                <class>IdleSleep</class>
+                <desc>Waiting for a moment...</desc>
+                <idle_sleep_time_in_sec>15</idle_sleep_time_in_sec>
+        </testCase>
+
+	<testCase id="030121">
+		<class>Initialize_eNB</class>
+		<desc>Initialize eNB (FDD/Band13/10MHz)</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf</Initialize_eNB_args>
+	</testCase>
+
+	<testCase id="030201">
+		<class>Terminate_eNB</class>
+		<desc>Terminate eNB</desc>
+	</testCase>
+
+        <testCase id="040102">
+                <class>Initialize_CatM_module</class>
+                <desc>Initialize CAT-M Module</desc>
+        </testCase>
+
+        <testCase id="040202">
+                <class>Terminate_CatM_module</class>
+                <desc>Terminate CAT-M Module</desc>
+        </testCase>
+
+        <testCase id="040302">
+                <class>Attach_CatM_module</class>
+                <desc>Attach CAT-M Module</desc>
+        </testCase>
+
+        <testCase id="040402">
+                <class>Detach_CatM_module</class>
+                <desc>Detach CAT-M Module</desc>
+        </testCase>
+
+        <testCase id="040502">
+                <class>Ping_CatM_module</class>
+                <desc>ping (10MHz - 20 sec)</desc>
+                <ping_args>-c 20</ping_args>
+                <ping_packetloss_threshold>5</ping_packetloss_threshold>
+        </testCase>
+
+</testCaseList>
-- 
2.26.2