sanitycheck: Add serial_pty script command line option
Add option to provide to sanitycheck argument for creating
pseudoterminal. Used with hardware without serial console connected.
A pseudoterminal is used to make a sanitycheck believe that it
interacts with a terminal although it actually interacts with the
script.
E.g "sanitycheck --device-testing --device-serial-pty <script>"
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
diff --git a/scripts/sanity_chk/sanitylib.py b/scripts/sanity_chk/sanitylib.py
index 758da0d..903073a 100644
--- a/scripts/sanity_chk/sanitylib.py
+++ b/scripts/sanity_chk/sanitylib.py
@@ -26,6 +26,7 @@
import concurrent
import xml.etree.ElementTree as ET
import logging
+import pty
from pathlib import Path
from distutils.spawn import find_executable
from colorama import Fore
@@ -522,7 +523,7 @@
for i in self.suite.connected_hardware:
if fixture and fixture not in i.get('fixtures', []):
continue
- if i['platform'] == device and i['available'] and i['serial']:
+ if i['platform'] == device and i['available'] and (i['serial'] or i['serial_pty']):
return True
return False
@@ -530,7 +531,7 @@
def get_available_device(self, instance):
device = instance.platform.name
for i in self.suite.connected_hardware:
- if i['platform'] == device and i['available'] and i['serial']:
+ if i['platform'] == device and i['available'] and (i['serial'] or i['serial_pty']):
i['available'] = False
i['counter'] += 1
return i
@@ -540,7 +541,7 @@
def make_device_available(self, serial):
with hw_map_local:
for i in self.suite.connected_hardware:
- if i['serial'] == serial:
+ if i['serial'] == serial or i['serial_pty']:
i['available'] = True
@staticmethod
@@ -612,7 +613,21 @@
elif runner == "jlink":
command.append("--tool-opt=-SelectEmuBySN %s" % (board_id))
- serial_device = hardware['serial']
+ serial_pty = hardware['serial_pty']
+ if serial_pty:
+ master, slave = pty.openpty()
+
+ try:
+ ser_pty_process = subprocess.Popen(serial_pty, stdout=master, stdin=master, stderr=master)
+ except subprocess.CalledProcessError as error:
+ logger.error("Failed to run subprocess {}, error {}".format(serial_pty, error.output))
+ return
+
+ serial_device = os.ttyname(slave)
+ else:
+ serial_device = hardware['serial']
+
+ logger.debug("Using serial device {}".format(serial_device))
try:
ser = serial.Serial(
@@ -627,6 +642,12 @@
self.set_state("failed", 0)
self.instance.reason = "Failed"
logger.error("Serial device error: %s" % (str(e)))
+
+ if serial_pty:
+ ser_pty_process.terminate()
+ outs, errs = ser_pty_process.communicate()
+ logger.debug("Process {} terminated outs: {} errs {}".format(serial_pty, outs, errs))
+
self.make_device_available(serial_device)
return
@@ -677,7 +698,6 @@
if post_flash_script:
self.run_custom_script(post_flash_script, 30)
-
t.join(self.timeout)
if t.is_alive():
logger.debug("Timed out while monitoring serial output on {}".format(self.instance.platform.name))
@@ -686,6 +706,11 @@
if ser.isOpen():
ser.close()
+ if serial_pty:
+ ser_pty_process.terminate()
+ outs, errs = ser_pty_process.communicate()
+ logger.debug("Process {} terminated outs: {} errs {}".format(serial_pty, outs, errs))
+
os.close(write_pipe)
os.close(read_pipe)
@@ -3427,14 +3452,21 @@
self.detected = []
self.connected_hardware = []
- def load_device_from_cmdline(self, serial, platform):
+ def load_device_from_cmdline(self, serial, platform, is_pty):
device = {
- "serial": serial,
+ "serial": None,
"platform": platform,
+ "serial_pty": None,
"counter": 0,
"available": True,
"connected": True
}
+
+ if is_pty:
+ device['serial_pty'] = serial
+ else:
+ device['serial'] = serial
+
self.connected_hardware.append(device)
def load_hardware_map(self, map_file):