示例#1
0
class CLI:
    def __init__(self, path: str):
        self._serial = Serial(path)
        self._pexpect = SerialSpawn(self._serial)

    def close(self):
        self._pexpect.close()
        self._serial.close()

    def tx(self, cmd: str) -> str:
        self._pexpect.send('\r')
        self._pexpect.expect('cli>')
        self._pexpect.send(cmd.strip() + '\r')
        self._pexpect.expect(cmd.strip())
        self._pexpect.expect('cli>')
        return self._pexpect.before.decode('utf-8').strip().replace(
            '\r\n', '\n')
def main():
    with serial.Serial('/dev/ttyAMA0', 115200, timeout=0) as ser:
        ss = SerialSpawn(ser)
        # DEBUG
        ss.logfile = sys.stderr.buffer
        total_cnt = 0
        success_cnt = 0
        fail_cnt = 0

        logfile = time.strftime("UBOOT-LOG-%Y-%m-%d.txt", time.localtime())
        f = open(logfile, 'a')

        power_cycle()
        start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

        while True:
            # try:
            #     a = ss.expect('SCHNEIDER2 login:'******'root')
            #     b = ss.expect('root@SCHNEIDER2:')
            #     ss.sendline('poweroff')
            #     power_cycle()
            # except TIMEOUT:
            #     a = ss.expect('SCHNEIDER2 login:'******'root')
            #     b = ss.expect('root@SCHNEIDER2:')
            #     ss.sendline('poweroff')
            # power_cycle()
            # ser_bytes = ser.readline()
            # print(ser_bytes)

            time.sleep(0.1)

            ss.sendline()
            index_login = ss.expect(
                pattern=['CPU  : AM335X-GP rev 2.1', pexpect.TIMEOUT],
                timeout=TIMEOUT_LOGIN)
            if index_login == 1:  # device get stuck
                print("Device get stuck in index_login.")
                f.write("Device get stuck in index_login.\r\n")
                power_cycle()
                continue

            # ser_bytes = ser.readline()
            # print(ser_bytes)

            for i in range(6):
                ss.send('\x03')
                time.sleep(0.3)
            ss.sendline()
            index_shell = ss.expect(pattern=['=>', pexpect.TIMEOUT],
                                    timeout=TIMEOUT_SHELL)
            if index_shell == 0:  # normal
                ss.sendline('poweroff')
            elif index_shell == 1:  # device get stuck
                print("Device get stuck in index_shell.")
                f.write("Device get stuck in index_shell.\r\n")
                power_cycle()
                continue
            '''record log'''
            # ret = chardet.detect(data)
            # print(ret)
            # s = str(data, encoding = "ascii")
            # print(type(data))
            # print(type(s))
            # f.write(s)

            total_cnt = total_cnt + 1
            is_repower = False

            end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            time.sleep(1)
            index_btldr = ss.expect(pattern=['U-Boot ', pexpect.TIMEOUT],
                                    timeout=TIMEOUT_PWROFF)
            if index_btldr == 0:
                fail_cnt = fail_cnt + 1
                print('____________________________________')
                print('****** \033[5;31;43m POWER OFF FAILED \033[0m')
                print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
                f.write("POWEROFF FAILED!\r\n")

            elif index_btldr == 1:  # time out = success
                success_cnt = success_cnt + 1
                is_repower = True
                print('____________________________________')
                print('###### \033[1;42m POWER OFF OK! \033[0m')
                print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
                f.write("POWEROFF OK!\r\n")
            # print(ss.before)

            print("total_cnt   :", total_cnt)
            print("success_cnt :", success_cnt)
            print("fail_cnt    :", fail_cnt)
            print("start time  :", start_time)
            print("end time    :", end_time)
            print("------------------------------------------------------\n")

            f.write("total_cnt   :" + str(total_cnt) + "\r\n")
            f.write("success_cnt :" + str(success_cnt) + "\r\n")
            f.write("fail_cnt    :" + str(fail_cnt) + "\r\n")
            f.write("start time  :" + start_time + "\r\n")
            f.write("end time    :" + end_time + "\r\n")
            f.write(
                "------------------------------------------------------\r\n\r\n"
            )
            f.flush()

            if is_repower:
                power_cycle()

            start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
示例#3
0
class UI():
    """Class Name: UI
  Purpose
    Provides DUT command line user interface and terminal output/logging features.
  """

    log_stream = sys.stdout
    log_terminal_output = True
    end_msg = True
    last_ui = ''
    test_result = 'CHECK'

    def __init__(self, credentials, platform):
        self.__platform = platform
        self.__dut = None
        self.__prompt = ''
        self.__type = credentials[0].lower()
        self.__last_buff = ''
        self.__out_even = True

        if not settings.glb.show_login:
            UI.log_terminal_output = False

        if self.__type == 'host':
            if platform == 'windows':
                self.__EOF = pexpect_for_winpexpect.EOF
                self.__TIMEOUT = pexpect_for_winpexpect.TIMEOUT
            else:
                self.__EOF = pexpect.EOF
                self.__TIMEOUT = pexpect.TIMEOUT

            return
        elif self.__type == 'snmp':
            self.__dut_ip = credentials[1]
            self.__snmp_ver = credentials[2]
            return
        elif self.__type == 'console':
            self.__EOF = pexpect.EOF
            self.__TIMEOUT = pexpect.TIMEOUT
            login_status = self.__initserial__(*credentials[1:])
        elif 'telnet' in self.__type or 'ssh' in self.__type:
            if settings.host_os == 'windows':
                self.__EOF = pexpect_for_winpexpect.EOF
                self.__TIMEOUT = pexpect_for_winpexpect.TIMEOUT
            else:
                self.__EOF = pexpect.EOF
                self.__TIMEOUT = pexpect.TIMEOUT

            if 'telnet' in self.__type:
                login_status = self.__inittelnet__(*credentials[1:])
            elif 'ssh' in self.__type:
                login_status = self.__initssh__(*credentials[1:])

        if login_status == 'PASS':
            if self.__platform == 'simba':
                self.send('terminal length 0\r')
                self.expect(self.__prompt)
                self.send('terminal width ' + str(settings.glb.log_width) +
                          '\r')
                self.expect(self.__prompt)

            self.__last_buff = self.getBuff()
            UI.log_terminal_output = True
            self.__init = True
            return self.__dut

        elif login_status == 'FAIL':
            self.__init = False
            self.__dut = None
            self.__prompt = ''
            self.__type = ''
            return self.__dut

    def __setas__(self, other):
        self.__type = other.__type
        self.__dut = other.__dut
        self.__prompt = other.__prompt
        self.__last_buff = other.__last_buff
        self.__EOF = other.__EOF
        self.__TIMEOUT = other.__TIMEOUT
        self.__init = other.__init

    def __initserial__(self, com_port, speed, user, pwd, prompt):
        m = re.match('COM([0-9]+)', com_port)

        if m and settings.host_os == 'linux':
            com_num = m.group(1)
            com_port = '/dev/ttyS' + com_num

        self.__ui_str = 'console ' + com_port + ' baud rate ' + str(speed)
        UI.log('ACTION', 'Initializing ' + self.__ui_str)

        try:
            ser = serial.Serial(com_port, speed, timeout=0.1)
            self.__dut = SerialSpawn(ser, timeout=10, encoding='utf-8')
        except Exception as e:
            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: Serial spawn session failed to initialize'
                )
                sys.stdout.write(
                    'Please check console login credentials, and verify the COM port is available.'
                )
                sys.stdout.write(e)

            UI.log(
                'CRITICAL ALERT', 'Serial spawn session failed to initialize',
                'Please check console login credentials, and verify the COM port is available.',
                str(e))

            return 'FAIL'

        self.__prompt = prompt
        return self.__login__(user, pwd)

    def __inittelnet__(self, ip, port, user, pwd, prompt):
        if port != '':
            self.__ui_str = 'Telnet ' + ip + ' on port ' + port
        else:
            self.__ui_str = 'Telnet ' + ip

        UI.log('ACTION', 'Initializing ' + self.__ui_str)

        try:
            if settings.host_os == 'windows':
                if port != '':
                    spw = winspawn('bin_win32/plink -telnet ' + ip + ' -P ' +
                                   port)
                else:
                    spw = winspawn('bin_win32/plink -telnet ' + ip)
                    #spw = winspawn('bin_win32/telnet_win.exe '+ip)

            else:
                spw = pexpect.spawn('telnet ' + ip + ' ' + port,
                                    encoding='utf-8')

        except Exception as e:
            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: Telnet spawn session failed to initialize'
                )
                sys.stdout.write(
                    'Please check Telnet login credentials, and verify the IP address is configured '
                    + 'properly.')

                sys.stdout.write(e)

            UI.log(
                'CRITICAL ALERT', 'Telnet spawn session failed to initialize',
                'Please check Telnet login credentials, and verify the IP address is configured properly.',
                str(e))

            return 'FAIL'

        self.__dut = spw
        self.__prompt = prompt
        return self.__login__(user, pwd)

    def __initssh__(self, ip, port, user, pwd, prompt):
        if port != '':
            self.__ui_str = 'SSH ' + user + '@' + ip + ' on port ' + port
        else:
            self.__ui_str = 'SSH ' + user + '@' + ip

        UI.log('ACTION', 'Initializing ' + self.__ui_str)

        try:
            if settings.host_os == 'windows':
                if port != '':
                    spw = winspawn('bin_win32/plink -ssh ' + user + '@' + ip +
                                   ' -P ' + port)
                else:
                    spw = winspawn('bin_win32/plink -ssh ' + user + '@' + ip)

            else:
                spw = pexpect.spawn(
                    'ssh ' + user + '@' + ip + ' -p ' + port +
                    ' -o StrictHostKeyChecking=no -o ServerAliveInterval=60',
                    encoding='utf-8')

        except Exception as e:
            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: SSH spawn session failed to initialize')
                sys.stdout.write(
                    'Please check SSH login credentials, and verify the IP address is configured '
                    + 'properly.')

                sys.stdout.write(e)

            UI.log(
                'CRITICAL ALERT', 'SSH spawn session failed to initialize',
                'Please check SSH login credentials, and verify the IP address is configured properly.',
                str(e))

            return 'FAIL'

        self.__dut = spw
        self.__prompt = prompt
        return self.__login__(user, pwd)

    def __login__(self, user, pwd):
        if 'ssh' in self.__type and settings.host_os == 'windows':
            return_char = '\n'
        else:
            return_char = '\r'

        if not settings.glb.show_login and user != '' and pwd != '':
            UI.log('Logging in with username/password: '******'/' + pwd)

        login_count = 0
        status = ''

        try:
            # if 'telnet' in self.__type:
            #   self.send('')
            # else:
            # self.send('\r')
            self.send('\r')

            while True:
                i = self.expect([
                    '(Username|Login|sonic login|bmc-oob. login: ).*',
                    '(?i)password.*', '(?i)note:', self.__prompt,
                    '(?i)permission denied', 'y/n'
                ],
                                timeout=10)
                if i == 3:
                    status = 'PASS'
                    break
                elif i == 0:
                    self.send(user + return_char)
                elif i == 1:
                    self.send(pwd + return_char)
                    login_count += 1
                elif i == 2:
                    if self.__type == 'console':
                        self.send('\r')
                elif i == 5:
                    self.send('y' + return_char)

                if login_count > 2:
                    if not settings.glb.print_to_stdout:
                        sys.stdout.write(
                            'CRITICAL ALERT: %s Login failed. Permission denied for username/password: %s/%s'
                            % (self.__type.capitalize(), user, pwd))

                    UI.log(
                        'CRITICAL ALERT',
                        '%s Login failed. Permission denied for username/password: %s/%s'
                        % (self.__type.capitalize(), user, pwd))

                    status = 'FAIL'
                    break

            if not settings.glb.show_login:
                UI.log('LOGIN SUCCESS', str(self) + ' is initialized.')

            if status == 'FAIL':
                self.__dut.close()

            return status

        except self.__EOF:
            UI.log_stream.write(self.getBuff())

            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: %s login failed; please check login credentials.'
                    % self.__type.capitalize())

            UI.log(
                'CRITICAL ALERT',
                '%s login failed; please check login credentials.' %
                self.__type.capitalize())

        except self.__TIMEOUT:
            UI.log_stream.write(self.getBuff())

            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: %s login timed out; please check login credentials.'
                    % self.__type.capitalize())

            UI.log(
                'CRITICAL ALERT',
                '%s login timed out; please check login credentials.' %
                self.__type.capitalize())

    def getOutEven(self):
        return self.__out_even

    def init(self):
        return self.__init

    def getPrompt(self):
        return self.__prompt

    def getEOF(self):
        return self.__EOF

    def getTIMEOUT(self):
        return self.__TIMEOUT

    def close(self, close_cmd='exit'):
        if self.__dut is None:
            return

        if not settings.glb.show_login:
            UI.log('LOGGING OUT', 'Closed ' + self.__ui_str)
            UI.log_terminal_output = False

        try:
            self.send(settings.glb.ctrl_c)
            self.expect(self.__prompt, writting=None)
            self.send(close_cmd + '\r')

            while True:
                i = self.expect([
                    self.__EOF, '(?i)(note:|login|exit session).*',
                    self.__prompt
                ],
                                writting=None)

                if i == 0 or i == 1:
                    break
                elif i == 2:
                    self.send(close_cmd + '\r')

        except:
            if self.__dut.isalive():
                self.__dut.terminate()

        if self.__dut != None:
            self.__dut.close()

        if UI.log_terminal_output:
            UI.log('Closed ' + self.__ui_str)

        self.__dut = None
        self.__type = None
        self.__init = False
        UI.log_terminal_output = True
        return None

    def spawn(self, *cmd):
        try:
            if settings.host_os == 'windows':
                self.__ui_str = 'Windows host CMD'
                self.__dut = winspawn(*cmd)
            elif settings.host_os == 'linux':
                self.__ui_str = 'Linux host Bash shell'
                self.__dut = pexpect.spawn(*cmd, encoding='utf-8')

            cmd = ''.join(*cmd)
            UI.log('ACTION', 'Executing command on ' + self.__ui_str,
                   'Command: ' + cmd)
            UI.logTitle('TERMINAL OUTPUT from ' + self.__ui_str)
            UI.last_ui = str(self)
            last_line = self.__last_buff.split('\n')[-1]
            UI.log_stream.write(last_line)

            if settings.glb.print_to_stdout:
                sys.stdout.write(last_line)

            UI.end_msg = False
        except Exception as e:
            if not settings.glb.print_to_stdout:
                sys.stdout.write(
                    'CRITICAL ALERT: Host spawn session failed to initialize')
                sys.stdout.write(str(e))

            UI.log('CRITICAL ALERT', 'Host spawn session failed to initialize',
                   str(e))
            self.__dut = None

    def send(self, *args):
        if self.__dut == None:
            return

        if (UI.end_msg or UI.last_ui != str(self)) and UI.log_terminal_output:
            UI.log_stream.write(settings.glb.change_line)
            UI.logTitle('TERMINAL OUTPUT from ' + self.__ui_str)
            UI.last_ui = str(self)
            last_line = self.__last_buff.split('\n')[-1]
            UI.log_stream.write(last_line)

            if settings.glb.print_to_stdout:
                sys.stdout.write(last_line)

        UI.end_msg = False
        return self.__dut.send(*args)

    def sendWithoutOutput(self, *args):
        if self.__dut == None:
            return
        else:
            return self.__dut.send(*args)

    def expect(self,
               *args,
               timeout=10,
               writting=True,
               before=True,
               after=True):
        self.__out_even = False
        expectError = False

        if self.__dut == None:
            return

        try:
            ret = self.__dut.expect(*args, timeout=timeout)
        except:
            expectError = True
            ret = 1
            pass

        if writting:
            buff = self.getBuff(before=before, after=after)
            if UI.log_terminal_output:
                UI.log_stream.write(buff)

                if settings.glb.print_to_stdout:
                    sys.stdout.write(buff)

            else:
                UI.end_msg = True

            if args[0][ret] == self.__EOF:
                UI.last_ui = ''
                self.__dut = None
                self.__last_buff = ''
            else:
                self.__last_buff = buff

        self.__out_even = True
        if expectError:
            return 100
        else:
            return ret

    def getBuff(self, before=True, after=True):
        if self.__dut == None:
            return ''

        ret_str = ''

        if 'str' in str(type(self.__dut.before)) and before:
            ret_str = self.__dut.before

        if 'str' in str(type(self.__dut.after)) and after:
            ret_str += self.__dut.after

        return ret_str

    def getLastBuff(self):
        return self.__last_buff

    def getBeforeBuff(self):
        if 'str' in str(type(self.__dut.before)):
            return self.__dut.before
        else:
            return "NULL"

    def getAfterBuff(self):
        if 'str' in str(type(self.__dut.after)):
            return self.__dut.after
        else:
            return "NULL"

    def sendCmd(self, cmd, prompt="", writting=True, timeout=10):
        if prompt == "":
            prompt = self.__prompt
        self.send(cmd + '\r')
        ret = self.expect(prompt, writting=writting, timeout=timeout)
        if ret == 0:
            return self.getOutputFromLastBuff(cmd, prompt=prompt)
        else:
            return ""

    def getOutputFromLastBuff(self, cmd, prompt=""):
        if prompt == "":
            prompt = self.__prompt
        relist = self.getBuff().splitlines()
        retstr = ""
        for line in relist:
            if not re.search('^\x1b]0;root.*', line):
                if cmd != line:
                    retstr += line + '\n'
        return retstr

    def snmpGet(self,
                oids,
                credentials='',
                port=161,
                engine=hlapi.SnmpEngine(),
                context=hlapi.ContextData()):
        target = self.__dut_ip

        if self.__snmp_ver.lower() == '2c':
            credentials = hlapi.CommunityData('public')

        handler = hlapi.getCmd(engine, credentials,
                               hlapi.UdpTransportTarget((target, port)),
                               context, *construct_object_types(oids))

        ret = fetch(handler, 1)[0]
        ret_list = []

        for key, value in ret.items():
            temp = key + ': ' + value
            ret_list.append(temp)

        UI.log('SNMP-GET', 'Remote IP: ' + self.__dut_ip, *ret_list)
        return ret

    def snmpSet(self,
                value_pairs,
                credentials='',
                port=161,
                engine=hlapi.SnmpEngine(),
                context=hlapi.ContextData()):
        target = self.__dut_ip

        if self.__snmp_ver.lower() == '2c':
            credentials = hlapi.CommunityData('private')

        handler = hlapi.setCmd(engine, credentials,
                               hlapi.UdpTransportTarget((target, port)),
                               context, *construct_value_pairs(value_pairs))

        ret = fetch(handler, 1)[0]
        ret_list = []

        for key, value in ret.items():
            temp = key + ': ' + value
            ret_list.append(temp)

        UI.log('SNMP-SET', 'Remote IP: ' + self.__dut_ip, *ret_list)
        return ret

    @classmethod
    def openLog(class_object, filename):
        UI.log_stream = open(filename, 'a')

    @classmethod
    def logTitle(class_object, title):
        if not UI.end_msg:
            UI.log_stream.write(settings.glb.change_line)

            if settings.glb.print_to_stdout:
                sys.stdout.write('\n')

        centered_title = '{:=^{w}}'.format(' ' + title + ' ',
                                           w=settings.glb.log_width)
        UI.log_stream.write(centered_title)

        if settings.glb.print_to_stdout:
            sys.stdout.write(centered_title)

        UI.log_stream.write(settings.glb.change_line)
        UI.end_msg = True

        if settings.glb.print_to_stdout:
            sys.stdout.write('\n\n')

        if title == 'PASS' and UI.test_result == 'CHECK':
            UI.test_result = 'PASS'
        elif title == 'FAIL':
            UI.test_result = 'FAIL'

    @classmethod
    def log(class_object, *msg):
        if not UI.end_msg:
            UI.log_stream.write(settings.glb.change_line)

            if settings.glb.print_to_stdout:
                sys.stdout.write('\n')

        if msg[0].isupper():
            title = msg[0]
            msg = msg[1:]
            UI.logTitle(title)
        else:
            divider = '=' * settings.glb.log_width
            UI.log_stream.write(divider)
            UI.log_stream.write(settings.glb.change_line)

            if settings.glb.print_to_stdout:
                sys.stdout.write(divider)
                sys.stdout.write('\n\n')

        first_word = msg[0].split(' ')[0]

        if re.match('(\.|:)', first_word[-1]):
            indent = ' ' * (len(first_word) + 1)
        else:
            indent = ''

        for m in msg:
            # Perform word wrap for each line of message.
            m.strip('\n')
            lines = ''
            word_list = str(m).split(' ')

            for w in word_list:
                last_line = (lines + w).split('\n')[-1]

                if len(last_line) > settings.glb.log_width:
                    lines += '\n' + indent + w + ' '
                else:
                    lines += w + ' '

            UI.log_stream.write(lines + '\n')

            if settings.glb.print_to_stdout:
                sys.stdout.write(lines + '\n')

        if settings.glb.print_to_stdout:
            sys.stdout.write('\n')

        UI.end_msg = True

    @classmethod
    def closeLog(class_object):
        UI.log_stream.write('\n\n')
        UI.log_stream.close()
        f = open(UI.log_stream.name, 'r')
        l_list = f.readlines()
        f.close()
        new_f = open(UI.log_stream.name, 'w')
        empty_line_count = 0

        for l in l_list:
            l = l.replace(']0;root@minipack:~', '')
            if re.search('^[\r\n]+$', l, re.M) or len(l) == 1:
                empty_line_count += 1
            else:
                if empty_line_count > 2:
                    new_f.write('\n')

                new_f.write(l)
                empty_line_count = 0

        new_f.close
示例#4
0
def main():
    with serial.Serial('/dev/ttyAMA0', 115200, timeout=0) as ser:
        ss = SerialSpawn(ser)
        # DEBUG
        ss.logfile = sys.stderr.buffer
        total_cnt = 0
        success_cnt = 0
        fail_cnt = 0
        first = True
        log_first = ""

        logfile = time.strftime("UBOOT-LOG-%Y-%m-%d-%H.txt", time.localtime())
        f = open(logfile, 'a')

        f.write("DC_OFF_SECS      = {}\n".format(DC_OFF_SECS))
        f.write("TIMEOUT_LOGIN    = {}\n".format(TIMEOUT_LOGIN))
        f.write("TIMEOUT_SHELL    = {}\n".format(TIMEOUT_SHELL))
        f.write("TIMEOUT_PWROFF   = {}\n".format(TIMEOUT_PWROFF))

        power_cycle()
        tm_start = time.localtime()

        while True:
            # try:
            #     a = ss.expect('SCHNEIDER2 login:'******'root')
            #     b = ss.expect('root@SCHNEIDER2:')
            #     ss.sendline('poweroff')
            #     power_cycle()
            # except TIMEOUT:
            #     pass
            # power_cycle()
            # ser_bytes = ser.readline()
            # print(ser_bytes)

            time.sleep(0.1)

            if first:
                log_first += decode_all(ss)
            ss.sendline()
            index_login = ss.expect(
                pattern=['CPU  : AM335X-GP rev 2.1', pexpect.TIMEOUT],
                timeout=TIMEOUT_LOGIN)
            if index_login == 1:  # device get stuck
                print("Wait login TIMEOUT!!!")
                f.write("Wait login TIMEOUT!!!\n")
                power_cycle()
                log_first += decode_all(ss)
                f.write("### BOOT LOG ###\n" + log_first)
                f.write("\n\n\n\n\n")
                continue

            # ser_bytes = ser.readline()
            # print(ser_bytes)

            for i in range(6):
                ss.send('\x03')
                time.sleep(0.3)
            ss.sendline()
            if first:
                log_first += decode_all(ss)
            index_shell = ss.expect(pattern=['=>', pexpect.TIMEOUT],
                                    timeout=TIMEOUT_SHELL)
            if index_shell == 0:  # normal
                pass
            elif index_shell == 1:  # device get stuck
                print("Wait shell TIMEOUT!!!")
                f.write("Wait shell TIMEOUT!!!\n")
                power_cycle()
                continue

            ss.sendline('setenv ipaddr 192.168.4.58')
            time.sleep(0.2)
            ss.sendline('ping 192.168.4.2')
            time.sleep(2.0)
            ss.sendline('poweroff')

            total_cnt = total_cnt + 1
            is_repower = False

            time.sleep(1)
            tm_pwrdn = time.localtime()
            if first:
                log_first += decode_all(ss)
            index_btldr = ss.expect(pattern=['U-Boot ', pexpect.TIMEOUT],
                                    timeout=TIMEOUT_PWROFF)
            if first:
                log_first += decode_all(ss)
            if index_btldr == 0:
                fail_cnt = fail_cnt + 1
                print('____________________________________')
                print('****** \033[5;31;43m POWER OFF FAILED \033[0m')
                print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
                f.write("POWEROFF FAILED!\n")

            elif index_btldr == 1:  # time out = success
                success_cnt = success_cnt + 1
                is_repower = True
                print('____________________________________')
                print('###### \033[1;42m POWER OFF OK! \033[0m')
                print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
                f.write("POWEROFF OK!\n")

            fa = "FAIL        : {}\n".format(fail_cnt)
            ot = "OK/TOTAL    : {} / {}\n".format(success_cnt, total_cnt)
            tm_start_str = time.strftime("%Y-%m-%d %H:%M:%S", tm_start)
            st = "START       : {}\n".format(tm_start_str)
            ps = time.mktime(tm_pwrdn) - time.mktime(tm_start)
            cy = "USED        : {} Secs\n".format(ps)
            print(fa + ot + st + cy, end='')
            print("------------------------------------------------------\n")

            if first:
                log_first += decode_all(ss)
                f.write("### BOOT LOG ###\n" + log_first)
                f.write("\n\n\n\n\n")

            f.write(fa + ot + st + cy)
            f.write(
                "------------------------------------------------------\n\n")
            f.flush()

            if is_repower:
                power_cycle()

            tm_start = time.localtime()
            first = False
示例#5
0
def main():

    global logfile

    AP_ESCAPE       = "Escape character is '^]'."
    AP_USERNAME     = "******"
    AP_PASSWORD     = "******"
    AP_EN           = "en"
    AP_MORE         = "--More--"
    AP_EXIT         = "exit"
    LF_PROMPT       = "$"
    CR = "\r\n"

    
    parser = argparse.ArgumentParser(description="Cisco AP Control Script")
    parser.add_argument("-a", "--prompt",  type=str, help="ap prompt")
    parser.add_argument("-d", "--dest",    type=str, help="address of the AP  172.19.27.55")
    parser.add_argument("-o", "--port",    type=int, help="control port on the AP, 2008")
    parser.add_argument("-u", "--user",    type=str, help="credential login/username, admin")
    parser.add_argument("-p", "--passwd",  type=str, help="credential password Wnbulab@123")
    parser.add_argument("-s", "--scheme",  type=str, choices=["serial", "ssh", "telnet"], help="Connect via serial, ssh or telnet")
    parser.add_argument("-t", "--tty",     type=str, help="tty serial device for connecting to AP")
    parser.add_argument("-l", "--log",     type=str, help="logfile for messages, stdout means output to console",default="stdout")
    parser.add_argument("-z", "--action",  type=str, help="action,  current action is powercfg")
    parser.add_argument("-b", "--baud",    type=str, help="action,  baud rate lanforge: 115200  cisco: 9600")

    args = None
    try:
        args = parser.parse_args()
        host = args.dest
        scheme = args.scheme
        port = (default_ports[scheme], args.port)[args.port != None]
        user = args.user
        if (args.log != None):
            logfile = args.log
    except Exception as e:
        logging.exception(e)
        usage()
        exit(2)
    console_handler = logging.StreamHandler()
    formatter = logging.Formatter(FORMAT)
    logg = logging.getLogger(__name__)
    logg.setLevel(logging.DEBUG)
    file_handler = None
    if (logfile is not None):
        if (logfile != "stdout"):
            file_handler = logging.FileHandler(logfile, "w")
            file_handler.setLevel(logging.DEBUG)
            file_handler.setFormatter(formatter)
            logg.addHandler(file_handler)
            logging.basicConfig(format=FORMAT, handlers=[file_handler])
        else:
            # stdout logging
            logging.basicConfig(format=FORMAT, handlers=[console_handler])
    egg = None # think "eggpect"
    ser = None
    try:
        if (scheme == "serial"):
            #eggspect = pexpect.fdpexpect.fdspan(telcon, logfile=sys.stdout.buffer)
            ser = serial.Serial(args.tty, int(args.baud), timeout=5)
            print("Created serial connection on %s, open: %s"%(args.tty, ser.is_open))
            egg = SerialSpawn(ser)
            egg.logfile = FileAdapter(logg)
            time.sleep(1)
            egg.sendline(CR)
            time.sleep(1)

        elif (scheme == "ssh"):
            if (port is None):
                port = 22
            cmd = "ssh -p%d %s@%s"%(port, user, host)
            logg.info("Spawn: "+cmd+NL)
            egg = pexpect.spawn(cmd)
            #egg.logfile_read = sys.stdout.buffer
            egg.logfile = FileAdapter(logg)
        elif (scheme == "telnet"):
            if (port is None):
                port = 23
            cmd = "telnet {} {}".format(host, port)
            logg.info("Spawn: "+cmd+NL)
            egg = pexpect.spawn(cmd)
            egg.logfile = FileAdapter(logg)
            # Will login below as needed.
        else:
            usage()
            exit(1)
    except Exception as e:
        logging.exception(e)
    
    AP_PROMPT       = "{}>".format(args.prompt)
    AP_HASH         = "{}#".format(args.prompt)
    time.sleep(0.1)
    logged_in  = False
    loop_count = 0
    while (loop_count <= 8 and logged_in == False):
        loop_count += 1
        i = egg.expect_exact([AP_ESCAPE,AP_PROMPT,AP_HASH,AP_USERNAME,AP_PASSWORD,AP_MORE,LF_PROMPT,pexpect.TIMEOUT],timeout=5)
        if i == 0:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_ESCAPE,i,egg.before,egg.after))
            egg.sendline(CR) # Needed after Escape or should just do timeout and then a CR?
            sleep(1)
        if i == 1:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_PROMPT,i,egg.before,egg.after))
            egg.sendline(AP_EN) 
            sleep(1)
            j = egg.expect_exact([AP_PASSWORD,pexpect.TIMEOUT],timeout=5)
            if j == 0:
                logg.info("Expect: {} i: {} j: {} before: {} after: {}".format(AP_PASSWORD,i,j,egg.before,egg.after))
                egg.sendline(args.passwd) 
                sleep(1)
                k = egg.expect_exact([AP_HASH,pexpect.TIMEOUT],timeout=5)
                if k == 0:
                    logg.info("Expect: {} i: {} j: {} k: {} before: {} after: {}".format(AP_PASSWORD,i,j,k,egg.before,egg.after))
                    logged_in = True
                if k == 1:
                    logg.info("Expect: {} i: {} j: {} k: {} before: {} after: {}".format("Timeout",i,j,k,egg.before,egg.after))
            if j == 1:
                logg.info("Expect: {} i: {} j: {} before: {} after: {}".format("Timeout",i,j,egg.before,egg.after))

        if i == 2:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_HASH,i,egg.before,egg.after))
            logged_in = True 
            sleep(1)
        if i == 3:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_USERNAME,i,egg.before,egg.after))
            egg.sendline(args.user) 
            sleep(1)
        if i == 4:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_PASSWORD,i,egg.before,egg.after))
            egg.sendline(args.passwd) 
            sleep(1)
        if i == 5:
            logg.info("Expect: {} i: {} before: {} after: {}".format(AP_MORE,i,egg.before,egg.after))
            if (scheme == "serial"):
                egg.sendline("r")
            else:
                egg.sendcontrol('c')
            sleep(1)
        # for Testing serial connection using Lanforge
        if i == 6:
            logg.info("Expect: {} i: {} before: {} after: {}".format(LF_PROMPT,i,egg.before.decode('utf-8', 'ignore'),egg.after.decode('utf-8', 'ignore')))
            if (loop_count < 3):
                egg.send("ls -lrt")
                sleep(1)
            if (loop_count > 4):
                logged_in = True # basically a test mode using lanforge serial
        if i == 7:
            logg.info("Expect: {} i: {} before: {} after: {}".format("Timeout",i,egg.before,egg.after))
            egg.sendline(CR) 
            sleep(1)


    if (args.action == "powercfg"):
        logg.info("execute: show controllers dot11Radio 1 powercfg | g T1")
        egg.sendline('show controllers dot11Radio 1 powercfg | g T1')
        egg.expect([pexpect.TIMEOUT], timeout=3)  # do not delete this for it allows for subprocess to see output
        print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        i = egg.expect_exact([AP_MORE,pexpect.TIMEOUT],timeout=5)
        if i == 0:
            egg.sendcontrol('c')
        if i == 1:
            logg.info("send cntl c anyway")
            egg.sendcontrol('c')

    elif (args.action == "clear_log"):
        logg.info("execute: clear log")
        egg.sendline('clear log')
        sleep(0.4)
        egg.sendline('show log')
        egg.expect([pexpect.TIMEOUT], timeout=2)  # do not delete this for it allows for subprocess to see output
        print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        # allow for normal logout below

    elif (args.action == "show_log"):
        logg.info("execute: show log")
        egg.sendline('show log')
        sleep(0.4)
        egg.expect([pexpect.TIMEOUT], timeout=2)  # do not delete this for it allows for subprocess to see output
        print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        i = egg.expect_exact([AP_MORE,pexpect.TIMEOUT],timeout=4)
        if i == 0:
            egg.sendline('r')
            egg.expect([pexpect.TIMEOUT], timeout=4)  # do not delete this for it allows for subprocess to see output
            print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        if i == 1:
            print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        # allow for normal logout below
        # show log | g DOT11_DRV

    # CAC_EXPIRY_EVT: CAC finished on DFS channel 52
    elif (args.action == "cac_expiry_evt"):
        logg.info("execute: show log | g CAC_EXPIRY_EVT")    
        egg.sendline('show log | g CAC_EXPIRY_EVT')
        sleep(0.4)
        egg.expect([pexpect.TIMEOUT], timeout=2)  # do not delete this for it allows for subprocess to see output
        print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        i = egg.expect_exact([AP_MORE,pexpect.TIMEOUT],timeout=4)
        if i == 0:
            egg.sendline('r')
            egg.expect([pexpect.TIMEOUT], timeout=4)  # do not delete this for it allows for subprocess to see output
            print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output
        if i == 1:
            print(egg.before.decode('utf-8', 'ignore')) # do not delete this for it  allows for subprocess to see output

    elif (args.action == "ds_data_5ghz"):
        logg.info("execute: wl -i wl1 bs_data")
        egg.sendline('wl -i wl1 bs_data')
        egg.expect([pexpect.TIMEOUT], timeout=4) # do not detete this for it allow for subprocess to read
        print(egg.before.decode('utf-8','ignore')) # do not delete this for it  allows for subprocess to see output


    elif (args.action == "ds_data_24ghz"):
        logg.info("execute: wl -i wl0 bs_data")
        egg.sendline('wl -i wl1 bs_data')
        egg.expect([pexpect.TIMEOUT], timeout=4) # do not detete this for it allow for subprocess to read
        print(egg.before.decode('utf-8','ignore')) # do not delete this for it  allows for subprocess to see output


    else: # no other command at this time so send the same power command
        #logg.info("no action so execute: show controllers dot11Radio 1 powercfg | g T1")
        logg.info("no action")

    i = egg.expect_exact([AP_PROMPT,AP_HASH,pexpect.TIMEOUT],timeout=1)
    if i == 0:
        logg.info("received {} we are done send exit".format(AP_PROMPT))
        egg.sendline(AP_EXIT)
    if i == 1:
        logg.info("received {} send exit".format(AP_HASH))
        egg.sendline(AP_EXIT)
    if i == 2:
        logg.info("timed out waiting for {} or {}".format(AP_PROMPT,AP_HASH))
示例#6
0
import sys

# pip3 install pyserial
# sudo apt-get install python3-serial
import serial

# pip3 install pexpect-serial
from pexpect_serial import SerialSpawn
# If pexpect-serial is not available, use pexpect + picocom.

with serial.Serial('/dev/ttyACM0', baudrate = 115200, bytesize = 8, \
        parity = 'N', stopbits = 1) as ser:
    p = SerialSpawn(ser)
    p.logfile_read = sys.stdout.buffer
    p.expect('U-Boot ')
    p.expect('Hit any key to stop autoboot: ')
    p.send("s")
    p.expect('> ')
    p.logfile_read = None
    p.interact()  # press CTRL-] to contine python execution

# python3 -c "
# import pexpect, sys
# c = pexpect.spawn('$VPN_CMD')
# c.logfile_read = sys.stdout.buffer
# c.expect('Password:'******'$VPN_PASSWORD')
# c.interact()
# "
def main():
    global prompt

    parser = argparse.ArgumentParser(description="OpenWrt AP Control Script")
    parser.add_argument("-d",
                        "--dest",
                        type=str,
                        help="address of the cisco controller")
    parser.add_argument("-o",
                        "--port",
                        type=int,
                        help="control port on the controller")
    parser.add_argument("-u",
                        "--user",
                        type=str,
                        help="credential login/username")
    parser.add_argument("-p", "--passwd", type=str, help="credential password")
    parser.add_argument("-P", "--prompt", type=str, help="Prompt to look for")
    parser.add_argument("-s",
                        "--scheme",
                        type=str,
                        choices=["serial", "ssh", "telnet"],
                        help="Connect via serial, ssh or telnet")
    parser.add_argument("-t", "--tty", type=str, help="tty serial device")
    parser.add_argument(
        "-l",
        "--log",
        type=str,
        help="logfile for messages, stdout means output to console")
    parser.add_argument("--action",
                        type=str,
                        help="perform action",
                        choices=[
                            "logread", "journalctl", "lurk", "sysupgrade",
                            "download", "upload", "reboot", "cmd"
                        ])
    parser.add_argument("--value", type=str, help="set value")
    parser.add_argument("--value2", type=str, help="set value2")
    tty = None

    args = None
    try:
        args = parser.parse_args()
        host = args.dest
        scheme = args.scheme
        port = args.port
        #port = (default_ports[scheme], args.port)[args.port != None]
        user = args.user
        passwd = args.passwd
        logfile = args.log
        tty = args.tty
        if (args.prompt != None):
            prompt = args.prompt
        filehandler = None
    except Exception as e:
        logging.exception(e)
        usage()
        exit(2)

    console_handler = logging.StreamHandler()
    formatter = logging.Formatter(FORMAT)
    logg = logging.getLogger(__name__)
    logg.setLevel(logging.DEBUG)
    file_handler = None
    if (logfile is not None):
        if (logfile != "stdout"):
            file_handler = logging.FileHandler(logfile, "w")
            file_handler.setLevel(logging.DEBUG)
            file_handler.setFormatter(formatter)
            logg.addHandler(file_handler)
            logging.basicConfig(format=FORMAT, handlers=[file_handler])
        else:
            # stdout logging
            logging.basicConfig(format=FORMAT, handlers=[console_handler])

    CCPROMPT = prompt

    ser = None
    egg = None  # think "eggpect"
    try:
        if (scheme == "serial"):
            #eggspect = pexpect.fdpexpect.fdspan(telcon, logfile=sys.stdout.buffer)
            import serial
            from pexpect_serial import SerialSpawn
            ser = serial.Serial(tty, 115200, timeout=5)

            egg = SerialSpawn(ser)
            egg.logfile = FileAdapter(logg)
            egg.sendline(NL)
            try:
                i = egg.expect(
                    [prompt, "Please press Enter to activate", "login:"******"Password:"******"ssh"):
            # Not implemented/tested currently. --Ben
            if (port is None):
                port = 22
            cmd = "ssh -p%d %s@%s" % (port, user, host)
            logg.info("Spawn: " + cmd + NL)
            egg = pexpect.spawn(cmd)
            #egg.logfile_read = sys.stdout.buffer
            egg.logfile = FileAdapter(logg)
            i = egg.expect(["password:"******"continue connecting (yes/no)?"],
                           timeout=3)
            time.sleep(0.1)
            if i == 1:
                egg.sendline('yes')
                egg.expect('password:'******' ')
            egg.expect('User\:')
            egg.sendline(user)
            egg.expect('Password\:')
            egg.sendline(passwd)
            egg.sendline('config paging disable')
        else:
            usage()
            exit(1)
    except Exception as e:
        logging.exception(e)

    command = None

    CLOSEDBYREMOTE = "closed by remote host."
    CLOSEDCX = "Connection to .* closed."

    try:
        egg.expect(CCPROMPT)
    except Exception as e:
        egg.sendline(NL)

    TO = 10
    wait_forever = False

    # Clean pending output
    egg.sendline("echo __hello__")
    egg.expect("__hello__")
    egg.expect(CCPROMPT)

    logg.info("Action[%s] Value[%s] Value2[%s]" %
              (args.action, args.value, args.value2))

    if (args.action == "reboot"):
        command = "reboot"
        TO = 60

    if (args.action == "cmd"):
        if (args.value is None):
            raise Exception("cmd requires value to be set.")
        command = "%s" % (args.value)

    if (args.action == "logread"):
        command = "logread -f"
        TO = 1
        wait_forever = True

    if (args.action == "journalctl"):
        command = "journalctl -f"
        TO = 1
        wait_forever = True

    if (args.action == "lurk"):
        command = "date"
        TO = 1
        wait_forever = True

    if (args.action == "sysupgrade"):
        command = "scp %s /tmp/new_img.bin" % (args.value)
        logg.info("Command[%s]" % command)
        egg.sendline(command)

        i = egg.expect(["password:"******"Do you want to continue connecting"],
                       timeout=5)
        if i == 1:
            egg.sendline("y")
            egg.expect("password:"******"lanforge")
        egg.expect(CCPROMPT, timeout=20)
        egg.sendline("sysupgrade /tmp/new_img.bin")
        egg.expect("link becomes ready", timeout=100)
        return

    if (args.action == "download"):
        command = "scp %s /tmp/%s" % (args.value, args.value2)
        logg.info("Command[%s]" % command)
        egg.sendline(command)

        i = egg.expect([
            "password:"******"Do you want to continue connecting",
            "Network unreachable"
        ],
                       timeout=5)
        if i == 2:
            print("Network unreachable, wait 15 seconds and try again.")
            time.sleep(15)
            command = "scp %s /tmp/%s" % (args.value, args.value2)
            logg.info("Command[%s]" % command)
            egg.sendline(command)

            i = egg.expect([
                "password:"******"Do you want to continue connecting",
                "Network unreachable"
            ],
                           timeout=5)
        if i == 2:
            print("ERROR:  Could not connect to LANforge to get download file")
            exit(2)
        if i == 1:
            egg.sendline("y")
            egg.expect("password:"******"lanforge")
        egg.expect(CCPROMPT, timeout=20)
        return

    if (args.action == "upload"):
        command = "scp %s %s" % (args.value, args.value2)
        logg.info("Command[%s]" % command)
        egg.sendline(command)

        i = egg.expect([
            "password:"******"Do you want to continue connecting",
            "Network unreachable"
        ],
                       timeout=5)
        if i == 2:
            print("Network unreachable, wait 15 seconds and try again.")
            time.sleep(15)
            command = "scp /tmp/%s %s" % (args.value, args.value2)
            logg.info("Command[%s]" % command)
            egg.sendline(command)

            i = egg.expect([
                "password:"******"Do you want to continue connecting",
                "Network unreachable"
            ],
                           timeout=5)
        if i == 2:
            print("ERROR:  Could not connect to LANforge to put upload file")
            exit(2)
        if i == 1:
            egg.sendline("y")
            egg.expect("password:"******"lanforge")
        egg.expect(CCPROMPT, timeout=20)
        return

    if (command is None):
        logg.info("No command specified, going to log out.")
    else:
        logg.info("Command[%s]" % command)
        egg.sendline(command)
        while True:
            try:
                i = egg.expect(
                    [CCPROMPT, "kmodloader: done loading kernel", "\n"],
                    timeout=TO)
                print(egg.before.decode('utf-8', 'ignore'))
                if i == 1:
                    egg.sendline(' ')
                    egg.expect(CCPROMPT, timeout=20)
                    print(egg.before.decode('utf-8', 'ignore'))
                if i == 2:  # new line of text, just print and continue
                    continue

                if not wait_forever:
                    break

            except Exception as e:
                # Some commands take a long time (logread -f)
                if not wait_forever:
                    logging.exception(e)
                    break
示例#8
0
class PipeSerial:
    """The PipeSerial class."""

    __version__ = __version__

    def __init__(
        self,
        serialport: str,
        baudrate: int = 115200,
        bytesize: int = 8,
        parity: str = "N",
        stopbits: float = 1,
        rtscts: bool = False,
        xonxoff: bool = False,
        rts: typing.Optional[int] = None,
        dtr: typing.Optional[int] = None,
    ) -> None:
        """Initialise pyserial object and configure the serial port.

        Args:
            serialport: The serial port device to use, like "/dev/cuaU0"
            baudrate: The serial port speed, default: 115200
            bytesize: Serial port bytesize, one of {5 6 7 8}, default: 8
            parity: Serial port parity, one of {N E O S M}, default: N
            stopbits: Serial port stopbits, one of {1 1.5 2}, default: 1
            rtscts: Enable serial port RTS/CTS hardware flow control, default: False
            xonxoff: Enable serial port software flow control, default: False
            rts: Set initial RTS line state, one of {0, 1}, default: None
            dtr: Set initial DTR line state, one of {0, 1}, default: None

        Returns:
            Nothing
        """
        logger.debug(f"Configuring serial port {serialport} ...")
        self.ser = serial.serial_for_url(serialport, do_not_open=True)
        self.ser.baudrate = baudrate
        self.ser.bytesize = bytesize
        self.ser.parity = parity
        self.ser.stopbits = stopbits
        self.ser.rtscts = rtscts
        self.ser.xonxoff = xonxoff
        if rts is not None:
            self.ser.rts = rts
        if dtr is not None:
            self.ser.dtr = dtr

    def open(self) -> bool:
        """Open the serial port and initialise the pexpect_serial object.

        Args: None
        Returns: None
        """
        # open serial port
        try:
            logger.debug("Opening serial port...")
            self.ser.open()
        except serial.SerialException:
            logger.exception(f"Could not open serial port {self.ser.name}")
            return False
        # and init pexpect_serial object
        self.ss = SerialSpawn(self.ser)
        logger.debug("Serial port opened OK!")
        return True

    def run(
        self,
        payload: str,
        expect: typing.List[str],
        delay: float = 0.9,
        expectcount: int = 1,
        timeout: int = 30,
    ) -> typing.List[str]:
        """Send the payload to serial device.

        Args:
            payload: The payload to send to the serial device.
            expect: A list of regex to expect as the end of output.

        Returns:
            The output from the serial device as list of string, one for each line.
        """
        # send the input to serial, line by line, with \r\n newlines
        for line in payload.split("\n"):
            if not line:
                # skip empty lines
                continue
            logger.debug(f"Sending payload line: {line}")
            self.ss.send(line.strip() + "\r\n")
            time.sleep(delay)

        # Wait for some matching output
        output = b""
        logger.debug(
            f"Collecting output, looking for one of these regular expressions: {expect}"
        )
        logger.debug(f"Will stop collecting after {expectcount} matches")
        for i in range(1, expectcount + 1):
            match = self.ss.expect(expect, timeout=timeout)
            logger.debug(
                f"Found match: '{expect[match].strip()}' (match number {i} of {expectcount})"
            )
            # we want all the output, before and including the expected string
            output += self.ss.before + self.ss.after

        # decode, strip and return the lines of output
        logger.debug(
            f"Done! Returning {len(output)} bytes of output from serial device"
        )
        return [line.strip() for line in output.decode("LATIN1").split("\n")]

    def close(self) -> None:
        """Close the serial port."""
        logger.debug("Closing serial port...")
        self.ss.ser.close()
        logger.debug("Serial port closed")