# # RTEMS Tools Project (http://www.rtems.org/) # Copyright 2013-2014 Chris Johns (chrisj@rtems.org) # All rights reserved. # # This file is part of the RTEMS Tools package in 'rtems-tools'. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # # RTEMS Testing Consoles # import fcntl import os import sys import termios from rtemstoolkit import error from rtemstoolkit import host from rtemstoolkit import path def save(): if not host.is_windows: try: sin = termios.tcgetattr(sys.stdin) sout = termios.tcgetattr(sys.stdout) serr = termios.tcgetattr(sys.stderr) return sin, sout, serr except: pass return None def restore(attributes): if attributes is not None: termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes[0]) termios.tcsetattr(sys.stdout, termios.TCSANOW, attributes[1]) termios.tcsetattr(sys.stderr, termios.TCSANOW, attributes[2]) class tty(object): raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS' def __init__(self, dev): if host.is_windows: raise error.general('termios not support on host') self.dev = dev self.default_attr = None self.fd = None self.if_on = False if host.is_windows: raise error.general('TTY consoles not supported on Windows.') if not path.exists(dev): raise error.general('dev not found: %s' % (dev)) try: self.fd = open(dev, 'rw') except IOError as ioe: raise error.general('opening tty dev: %s: %s' % (dev, ioe)) except: raise error.general('opening tty dev: %s: unknown' % (dev)) try: self.default_attr = termios.tcgetattr(self.fd) except: close(self.fd) raise error.general('cannot get termios attrs: %s' % (dev)) try: fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK) except: close(self.fd) raise error.general('cannot make tty non-blocking: %s' % (dev)) self.attr = self.default_attr def __del__(self): if self.fd and self.default_attr: try: fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK) self.fd.close() except: pass def __str__(self): def _input(attr): s = '' if attr & termios.IGNBRK: s += ' IGNBRK' if attr & termios.BRKINT: s += ' BRKINT' if attr & termios.IGNPAR: s += ' IGNPAR' if attr & termios.PARMRK: s += ' PARMRK' if attr & termios.INPCK: s += ' INPCK' if attr & termios.ISTRIP: s += ' ISTRIP' if attr & termios.INLCR: s += ' INLCR' if attr & termios.IGNCR: s += ' IGNCR' if attr & termios.IXON: s += ' IXON' if attr & termios.IXOFF: s += ' IXOFF' if attr & termios.IXANY: s += ' IXANY' if attr & termios.IMAXBEL: s += ' IMAXBEL' return s def _output(attr): s = '' if attr & termios.OPOST: s += ' OPOST' if attr & termios.ONLCR: s += ' ONLCR' if attr & termios.OCRNL: s += ' OCRNL' if attr & termios.TABDLY: s += ' TABDLY' if attr & termios.TAB0: s += ' TAB0' if attr & termios.TAB3: s += ' TAB3' if attr & termios.ONOCR: s += ' ONOCR' if attr & termios.ONLRET: s += ' ONLRET' return s def _control(attr): s = '' if (attr & termios.CSIZE) == termios.CS5: s += ' CS5' if (attr & termios.CSIZE) == termios.CS6: s += ' CS6' if (attr & termios.CSIZE) == termios.CS7: s += ' CS7' if (attr & termios.CSIZE) == termios.CS8: s += ' CS8' if attr & termios.CSTOPB: s += ' CSTOPB' if attr & termios.CREAD: s += ' CREAD' if attr & termios.PARENB: s += ' PARENB' if attr & termios.PARODD: s += ' PARODD' if attr & termios.HUPCL: s += ' HUPCL' if attr & termios.CLOCAL: s += ' CLOCAL' if attr & termios.CRTSCTS: s += ' CRTSCTS' return s def _local(attr): s = '' if attr & termios.ECHOKE: s += ' ECHOKE' if attr & termios.ECHOE: s += ' ECHOE' if attr & termios.ECHO: s += ' ECHO' if attr & termios.ECHONL: s += ' ECHONL' if attr & termios.ECHOPRT: s += ' ECHOPRT' if attr & termios.ECHOCTL: s += ' ECHOCTL' if attr & termios.ISIG: s += ' ISIG' if attr & termios.ICANON: s += ' ICANON' if attr & termios.IEXTEN: s += ' IEXTEN' if attr & termios.TOSTOP: s += ' TOSTOP' if attr & termios.FLUSHO: s += ' FLUSHO' if attr & termios.PENDIN: s += ' PENDIN' if attr & termios.NOFLSH: s += ' NOFLSH' return s def _baudrate(attr): if attr == termios.B0: s = 'B0' elif attr == termios.B50: s = 'B50' elif attr == termios.B75: s = 'B75' elif attr == termios.B110: s = 'B110' elif attr == termios.B134: s = 'B134' elif attr == termios.B150: s = 'B150' elif attr == termios.B200: s = 'B200' elif attr == termios.B300: s = 'B300' elif attr == termios.B600: s = 'B600' elif attr == termios.B1800: s = 'B1800' elif attr == termios.B1200: s = 'B1200' elif attr == termios.B2400: s = 'B2400' elif attr == termios.B4800: s = 'B4800' elif attr == termios.B9600: s = 'B9600' elif attr == termios.B19200: s = 'B19200' elif attr == termios.B38400: s = 'B38400' elif attr == termios.B57600: s = 'B57600' elif attr == termios.B115200: s = 'B115200' elif attr == termios.B230400: s = 'B230400' elif attr == termios.B460800: s = 'B460800' else: s = 'unknown' return s if self.attr is None: return 'None' s = 'iflag: %s' % (_input(self.attr[0])) s += os.linesep + 'oflag: %s' % (_output(self.attr[1])) s += os.linesep + 'cflag: %s' % (_control(self.attr[2])) s += os.linesep + 'lflag: %s' % (_local(self.attr[3])) s += os.linesep + 'ispeed: %s' % (_baudrate(self.attr[4])) s += os.linesep + 'ospeed: %s' % (_baudrate(self.attr[5])) return s def _update(self): self.off() try: termios.tcflush(self.fd, termios.TCIOFLUSH) #attr = self.attr #attr[0] = termios.IGNPAR; #attr[1] = 0 #attr[2] = termios.CRTSCTS | termios.CS8 | termios.CREAD; #attr[3] = 0 #attr[6][termios.VMIN] = 1 #attr[6][termios.VTIME] = 2 #termios.tcsetattr(self.fd, termios.TCSANOW, attr) termios.tcsetattr(self.fd, termios.TCSANOW, self.attr) termios.tcflush(self.fd, termios.TCIOFLUSH) except: raise if self.is_on: self.on() def _baudrate_mask(self, flag): if flag == 'B0': mask = termios.B0 self.attr[5] = termios.B0 elif flag == 'B50': mask = termios.B50 elif flag == 'B75': mask = termios.B75 elif flag == 'B110': mask = termios.B110 elif flag == 'B134': mask = termios.B134 elif flag == 'B150': mask = termios.B150 elif flag == 'B200': mask = termios.B200 elif flag == 'B300': mask = termios.B300 elif flag == 'B600': mask = termios.B600 elif flag == 'B1800': mask = termios.B1800 elif flag == 'B1200': mask = termios.B1200 elif flag == 'B2400': mask = termios.B2400 elif flag == 'B4800': mask = termios.B4800 elif flag == 'B9600': mask = termios.B9600 elif flag == 'B19200': mask = termios.B19200 elif flag == 'B38400': mask = termios.B38400 elif flag == 'B57600': mask = termios.B57600 elif flag == 'B115200': mask = termios.B115200 elif flag == 'B230400': mask = termios.B230400 elif flag == 'B460800': mask = termios.B460800 else: mask = None return mask def _input_mask(self, flag): if flag == 'IGNBRK': mask = termios.IGNBRK elif flag == 'BRKINT': mask = termios.BRKINT elif flag == 'IGNPAR': mask = termios.IGNPAR elif flag == 'PARMRK': mask = termios.PARMRK elif flag == 'INPCK': mask = termios.INPCK elif flag == 'ISTRIP': mask = termios.ISTRIP elif flag == 'INLCR': mask = termios.INLCR elif flag == 'IGNCR': mask = termios.IGNCR elif flag == 'IXON': mask = termios.IXON elif flag == 'IXOFF': mask = termios.IXOFF elif flag == 'IXANY': mask = termios.IXANY elif flag == 'IMAXBEL': mask = termios.IMAXBEL else: mask = None return mask def _output_mask(self, flag): if flag == 'OPOST': mask = termios.OPOST elif flag == 'ONLCR': mask = termios.ONLCR elif flag == 'OCRNL': mask = termios.OCRNL elif flag == 'TABDLY': mask = termios.TABDLY elif flag == 'TAB0': mask = termios.TAB0 elif flag == 'TAB3': mask = termios.TAB3 elif flag == 'ONOCR': mask = termios.ONOCR elif flag == 'ONLRET': mask = termios.ONLRET else: mask = None return mask def _control_mask(self, flag): if flag == 'CSTOPB': mask = termios.CSTOPB elif flag == 'CREAD': mask = termios.CREAD elif flag == 'PARENB': mask = termios.PARENB elif flag == 'PARODD': mask = termios.PARODD elif flag == 'HUPCL': mask = termios.HUPCL elif flag == 'CLOCAL': mask = termios.CLOCAL elif flag == 'CRTSCTS': mask = termios.CRTSCTS else: mask = None return mask def _local_mask(self, flag): if flag == 'ECHOKE': mask = termios.ECHOKE elif flag == 'ECHOE': mask = termios.ECHOE elif flag == 'ECHO': mask = termios.ECHO elif flag == 'ECHONL': mask = termios.ECHONL elif flag == 'ECHOPRT': mask = termios.ECHOPRT elif flag == 'ECHOCTL': mask = termios.ECHOCTL elif flag == 'ISIG': mask = termios.ISIG elif flag == 'ICANON': mask = termios.ICANON elif flag == 'IEXTEN': mask = termios.IEXTEN elif flag == 'TOSTOP': mask = termios.TOSTOP elif flag == 'FLUSHO': mask = termios.FLUSHO elif flag == 'PENDIN': mask = termios.PENDIN elif flag == 'NOFLSH': mask = termios.NOFLSH else: mask = None return mask def _set(self, index, mask, state): if state: self.attr[index] = self.attr[index] | mask else: self.attr[index] = self.attr[index] & ~mask def off(self): if self.fd: try: termios.tcflow(self.fd, termios.TCOOFF) except: pass try: termios.tcflow(self.fd, termios.TCIOFF) except: pass self.is_on = False def on(self): if self.fd: try: termios.tcflow(self.fd, termios.TCOON) except: pass try: termios.tcflow(self.fd, termios.TCION) except: pass self.is_on = True def baudrate(self, flag): mask = self._baudrate_mask(flag) if mask: self.attr[4] = mask self.attr[5] = mask else: raise error.general('invalid setting: %s' % (flag)) self._update() def input(self, flag, on): mask = self._input_mask(flag) if mask is None: raise error.general('invalid input flag: %s' % (flag)) self._set(0, mask, on) self._update() def output(self, flag, on): mask = self._output_mask(flag) if mask is None: raise error.general('invalid output flag: %s' % (flag)) self._set(1, mask, on) self._update() def control(self, flag, on): mask = self._control_mask(flag) if mask is None: raise error.general('invalid control flag: %s' % (flag)) self._set(2, mask, on) self._update() def local(self, flag, on): mask = self._local_mask(flag) if mask is None: raise error.general('invalid local flag: %s' % (flag)) self._set(3, mask, on) self._update() def vmin(self, _vmin): self.attr[6][termios.VMIN] = _vmin def vtime(self, _vtime): self.attr[6][termios.VTIME] = _vtime def set(self, flags = None): if flags is None: flags = self.raw for f in flags.split(','): if len(f) < 2: raise error.general('invalid flag: %s' % (f)) if f[0] == '~': on = False flag = f[1:] else: on = True flag = f if f.startswith('VMIN'): vs = f.split('=') if len(vs) != 2: raise error.general('invalid vmin flag: %s' % (f)) try: _vmin = int(vs[1]) except: raise error.general('invalid vmin flag: %s' % (f)) self.vmin(_vmin) continue if f.startswith('VTIME'): vs = f.split('=') if len(vs) != 2: raise error.general('invalid vtime flag: %s' % (f)) try: _vtime = int(vs[1]) except: raise error.general('invalid vtime flag: %s' % (f)) self.vtime(_vtime) continue mask = self._baudrate_mask(flag) if mask: if not on: raise error.general('baudrates are not flags: %s' % (f)) self.attr[4] = mask self.attr[5] = mask continue mask = self._input_mask(flag) if mask: self._set(0, mask, on) continue mask = self._output_mask(flag) if mask: self._set(1, mask, on) continue mask = self._control_mask(flag) if mask: self._set(2, mask, on) continue mask = self._local_mask(flag) if mask: self._set(3, mask, on) continue raise error.general('unknown tty flag: %s' % (f)) self._update() def read(self): return self.fs.read() if __name__ == "__main__": if len(sys.argv) == 2: t = tty(sys.argv[1]) t.baudrate('B115200') t.input('BRKINT', False) t.input('IGNBRK', True) t.input('IGNCR', True) t.local('ICANON', False) t.local('ISIG', False) t.local('IEXTEN', False) t.local('ECHO', False) t.control('CLOCAL', True) t.control('CRTSCTS', False) t.vmin(1) t.vtime(2) print(t) t.set('B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS') print(t) t.on() while True: c = t.fd.read(1) sys.stdout.write(c)