source: rtems-tools/tester/rt/stty.py @ 3bd8def

5
Last change on this file since 3bd8def was 3a867a4, checked in by Chris Johns <chrisj@…>, on 09/21/17 at 08:26:20

Add TFTP as a back end option for testing. Add telnet as a console option.

TFTP runs a local TFTP server on port 69 or another specified port and
serves each test for any requested file.

Telnet is now a console option.

  • Property mode set to 100644
File size: 18.3 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# RTEMS Testing Consoles
33#
34
35import fcntl
36import os
37import sys
38import termios
39
40from rtemstoolkit import error
41from rtemstoolkit import host
42from rtemstoolkit import path
43
44def save():
45    if not host.is_windows:
46        try:
47            sin = termios.tcgetattr(sys.stdin)
48            sout = termios.tcgetattr(sys.stdout)
49            serr = termios.tcgetattr(sys.stderr)
50            return sin, sout, serr
51        except:
52            pass
53    return None
54
55def restore(attributes):
56    if attributes is not None:
57        termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes[0])
58        termios.tcsetattr(sys.stdout, termios.TCSANOW, attributes[1])
59        termios.tcsetattr(sys.stderr, termios.TCSANOW, attributes[2])
60
61class tty:
62
63    raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS'
64
65    def __init__(self, dev):
66        if host.is_windows:
67            raise error.general('termios not support on host')
68        self.dev = dev
69        self.default_attr = None
70        self.fd = None
71        self.if_on = False
72        if host.is_windows:
73            raise error.general('TTY consoles not supported on Windows.')
74        if not path.exists(dev):
75            raise error.general('dev not found: %s' % (dev))
76        try:
77            self.fd = open(dev, 'rw')
78        except IOError as ioe:
79            raise error.general('opening tty dev: %s: %s' % (dev, ioe))
80        except:
81            raise error.general('opening tty dev: %s: unknown' % (dev))
82        try:
83            self.default_attr = termios.tcgetattr(self.fd)
84        except:
85            close(self.fd)
86            raise error.general('cannot get termios attrs: %s' % (dev))
87        try:
88            fcntl.fcntl(self.fd, fcntl.F_SETFL,
89                        fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK)
90        except:
91            close(self.fd)
92            raise error.general('cannot make tty non-blocking: %s' % (dev))
93        self.attr = self.default_attr
94
95    def __del__(self):
96        if self.fd and self.default_attr:
97            try:
98                fcntl.fcntl(self.fd, fcntl.F_SETFL,
99                            fcntl.fcntl(self.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK)
100                self.fd.close()
101            except:
102                pass
103
104    def __str__(self):
105        def _input(attr):
106            s = ''
107            if attr & termios.IGNBRK:
108                s += ' IGNBRK'
109            if attr & termios.BRKINT:
110                s += ' BRKINT'
111            if attr & termios.IGNPAR:
112                s += ' IGNPAR'
113            if attr & termios.PARMRK:
114                s += ' PARMRK'
115            if attr & termios.INPCK:
116                s += ' INPCK'
117            if attr & termios.ISTRIP:
118                s += ' ISTRIP'
119            if attr & termios.INLCR:
120                s += ' INLCR'
121            if attr & termios.IGNCR:
122                s += ' IGNCR'
123            if attr & termios.IXON:
124                s += ' IXON'
125            if attr & termios.IXOFF:
126                s += ' IXOFF'
127            if attr & termios.IXANY:
128                s += ' IXANY'
129            if attr & termios.IMAXBEL:
130                s += ' IMAXBEL'
131            return s
132
133        def _output(attr):
134            s = ''
135            if attr & termios.OPOST:
136                s += ' OPOST'
137            if attr & termios.ONLCR:
138                s += ' ONLCR'
139            if attr & termios.OCRNL:
140                s += ' OCRNL'
141            if attr & termios.TABDLY:
142                s += ' TABDLY'
143            if attr & termios.TAB0:
144                s += ' TAB0'
145            if attr & termios.TAB3:
146                s += ' TAB3'
147            if attr & termios.ONOCR:
148                s += ' ONOCR'
149            if attr & termios.ONLRET:
150                s += ' ONLRET'
151            return s
152
153        def _control(attr):
154            s = ''
155            if (attr & termios.CSIZE) == termios.CS5:
156                s += ' CS5'
157            if (attr & termios.CSIZE) == termios.CS6:
158                s += ' CS6'
159            if (attr & termios.CSIZE) == termios.CS7:
160                s += ' CS7'
161            if (attr & termios.CSIZE) == termios.CS8:
162                s += ' CS8'
163            if attr & termios.CSTOPB:
164                s += ' CSTOPB'
165            if attr & termios.CREAD:
166                s += ' CREAD'
167            if attr & termios.PARENB:
168                s += ' PARENB'
169            if attr & termios.PARODD:
170                s += ' PARODD'
171            if attr & termios.HUPCL:
172                s += ' HUPCL'
173            if attr & termios.CLOCAL:
174                s += ' CLOCAL'
175            if attr & termios.CRTSCTS:
176                s += ' CRTSCTS'
177            return s
178
179        def _local(attr):
180            s = ''
181            if attr & termios.ECHOKE:
182                s += ' ECHOKE'
183            if attr & termios.ECHOE:
184                s += ' ECHOE'
185            if attr & termios.ECHO:
186                s += ' ECHO'
187            if attr & termios.ECHONL:
188                s += ' ECHONL'
189            if attr & termios.ECHOPRT:
190                s += ' ECHOPRT'
191            if attr & termios.ECHOCTL:
192                s += ' ECHOCTL'
193            if attr & termios.ISIG:
194                s += ' ISIG'
195            if attr & termios.ICANON:
196                s += ' ICANON'
197            if attr & termios.IEXTEN:
198                s += ' IEXTEN'
199            if attr & termios.TOSTOP:
200                s += ' TOSTOP'
201            if attr & termios.FLUSHO:
202                s += ' FLUSHO'
203            if attr & termios.PENDIN:
204                s += ' PENDIN'
205            if attr & termios.NOFLSH:
206                s += ' NOFLSH'
207            return s
208
209        def _baudrate(attr):
210            if attr == termios.B0:
211                s = 'B0'
212            elif attr == termios.B50:
213                s = 'B50'
214            elif attr == termios.B75:
215                s = 'B75'
216            elif attr == termios.B110:
217                s = 'B110'
218            elif attr == termios.B134:
219                s = 'B134'
220            elif attr == termios.B150:
221                s = 'B150'
222            elif attr == termios.B200:
223                s = 'B200'
224            elif attr == termios.B300:
225                s = 'B300'
226            elif attr == termios.B600:
227                s = 'B600'
228            elif attr == termios.B1800:
229                s = 'B1800'
230            elif attr == termios.B1200:
231                s = 'B1200'
232            elif attr == termios.B2400:
233                s = 'B2400'
234            elif attr == termios.B4800:
235                s = 'B4800'
236            elif attr == termios.B9600:
237                s = 'B9600'
238            elif attr == termios.B19200:
239                s = 'B19200'
240            elif attr == termios.B38400:
241                s = 'B38400'
242            elif attr == termios.B57600:
243                s = 'B57600'
244            elif attr == termios.B115200:
245                s = 'B115200'
246            elif attr == termios.B230400:
247                s = 'B230400'
248            elif attr == termios.B460800:
249                s = 'B460800'
250            else:
251                s = 'unknown'
252            return s
253
254        if self.attr is None:
255            return 'None'
256        s = 'iflag: %s' % (_input(self.attr[0]))
257        s += os.linesep + 'oflag: %s' % (_output(self.attr[1]))
258        s += os.linesep + 'cflag: %s' % (_control(self.attr[2]))
259        s += os.linesep + 'lflag: %s' % (_local(self.attr[3]))
260        s += os.linesep + 'ispeed: %s' % (_baudrate(self.attr[4]))
261        s += os.linesep + 'ospeed: %s' % (_baudrate(self.attr[5]))
262        return s
263
264    def _update(self):
265        self.off()
266        try:
267            termios.tcflush(self.fd, termios.TCIOFLUSH)
268            #attr = self.attr
269            #attr[0] = termios.IGNPAR;
270            #attr[1] = 0
271            #attr[2] = termios.CRTSCTS | termios.CS8 | termios.CREAD;
272            #attr[3] = 0
273            #attr[6][termios.VMIN] = 1
274            #attr[6][termios.VTIME] = 2
275            #termios.tcsetattr(self.fd, termios.TCSANOW, attr)
276            termios.tcsetattr(self.fd, termios.TCSANOW, self.attr)
277            termios.tcflush(self.fd, termios.TCIOFLUSH)
278        except:
279            raise
280        if self.is_on:
281            self.on()
282
283    def _baudrate_mask(self, flag):
284        if flag == 'B0':
285            mask = termios.B0
286            self.attr[5] = termios.B0
287        elif flag == 'B50':
288            mask = termios.B50
289        elif flag == 'B75':
290            mask = termios.B75
291        elif flag == 'B110':
292            mask = termios.B110
293        elif flag == 'B134':
294            mask = termios.B134
295        elif flag == 'B150':
296            mask = termios.B150
297        elif flag == 'B200':
298            mask = termios.B200
299        elif flag == 'B300':
300            mask = termios.B300
301        elif flag == 'B600':
302            mask = termios.B600
303        elif flag == 'B1800':
304            mask = termios.B1800
305        elif flag == 'B1200':
306            mask = termios.B1200
307        elif flag == 'B2400':
308            mask = termios.B2400
309        elif flag == 'B4800':
310            mask = termios.B4800
311        elif flag == 'B9600':
312            mask = termios.B9600
313        elif flag == 'B19200':
314            mask = termios.B19200
315        elif flag == 'B38400':
316            mask = termios.B38400
317        elif flag == 'B57600':
318            mask = termios.B57600
319        elif flag == 'B115200':
320            mask = termios.B115200
321        elif flag == 'B230400':
322            mask = termios.B230400
323        elif flag == 'B460800':
324            mask = termios.B460800
325        else:
326            mask = None
327        return mask
328
329    def _input_mask(self, flag):
330        if flag == 'IGNBRK':
331            mask = termios.IGNBRK
332        elif flag == 'BRKINT':
333            mask = termios.BRKINT
334        elif flag == 'IGNPAR':
335            mask = termios.IGNPAR
336        elif flag == 'PARMRK':
337            mask = termios.PARMRK
338        elif flag == 'INPCK':
339            mask = termios.INPCK
340        elif flag == 'ISTRIP':
341            mask = termios.ISTRIP
342        elif flag == 'INLCR':
343            mask = termios.INLCR
344        elif flag == 'IGNCR':
345            mask = termios.IGNCR
346        elif flag == 'IXON':
347            mask = termios.IXON
348        elif flag == 'IXOFF':
349            mask = termios.IXOFF
350        elif flag == 'IXANY':
351            mask = termios.IXANY
352        elif flag == 'IMAXBEL':
353            mask = termios.IMAXBEL
354        else:
355            mask = None
356        return mask
357
358    def _output_mask(self, flag):
359        if flag == 'OPOST':
360            mask = termios.OPOST
361        elif flag == 'ONLCR':
362            mask = termios.ONLCR
363        elif flag == 'OCRNL':
364            mask = termios.OCRNL
365        elif flag == 'TABDLY':
366            mask = termios.TABDLY
367        elif flag == 'TAB0':
368            mask = termios.TAB0
369        elif flag == 'TAB3':
370            mask = termios.TAB3
371        elif flag == 'ONOCR':
372            mask = termios.ONOCR
373        elif flag == 'ONLRET':
374            mask = termios.ONLRET
375        else:
376            mask = None
377        return mask
378
379    def _control_mask(self, flag):
380        if flag == 'CSTOPB':
381            mask = termios.CSTOPB
382        elif flag == 'CREAD':
383            mask = termios.CREAD
384        elif flag == 'PARENB':
385            mask = termios.PARENB
386        elif flag == 'PARODD':
387            mask = termios.PARODD
388        elif flag == 'HUPCL':
389            mask = termios.HUPCL
390        elif flag == 'CLOCAL':
391            mask = termios.CLOCAL
392        elif flag == 'CRTSCTS':
393            mask = termios.CRTSCTS
394        else:
395            mask = None
396        return mask
397
398    def _local_mask(self, flag):
399        if flag == 'ECHOKE':
400            mask = termios.ECHOKE
401        elif flag == 'ECHOE':
402            mask = termios.ECHOE
403        elif flag == 'ECHO':
404            mask = termios.ECHO
405        elif flag == 'ECHONL':
406            mask = termios.ECHONL
407        elif flag == 'ECHOPRT':
408            mask = termios.ECHOPRT
409        elif flag == 'ECHOCTL':
410            mask = termios.ECHOCTL
411        elif flag == 'ISIG':
412            mask = termios.ISIG
413        elif flag == 'ICANON':
414            mask = termios.ICANON
415        elif flag == 'IEXTEN':
416            mask = termios.IEXTEN
417        elif flag == 'TOSTOP':
418            mask = termios.TOSTOP
419        elif flag == 'FLUSHO':
420            mask = termios.FLUSHO
421        elif flag == 'PENDIN':
422            mask = termios.PENDIN
423        elif flag == 'NOFLSH':
424            mask = termios.NOFLSH
425        else:
426            mask = None
427        return mask
428
429    def _set(self, index, mask, state):
430        if state:
431            self.attr[index] = self.attr[index] | mask
432        else:
433            self.attr[index] = self.attr[index] & ~mask
434
435    def off(self):
436        if self.fd:
437            try:
438                termios.tcflow(self.fd, termios.TCOOFF)
439            except:
440                pass
441            try:
442                termios.tcflow(self.fd, termios.TCIOFF)
443            except:
444                pass
445            self.is_on = False
446
447    def on(self):
448        if self.fd:
449            try:
450                termios.tcflow(self.fd, termios.TCOON)
451            except:
452                pass
453            try:
454                termios.tcflow(self.fd, termios.TCION)
455            except:
456                pass
457            self.is_on = True
458
459    def baudrate(self, flag):
460        mask = self._baudrate_mask(flag)
461        if mask:
462            self.attr[4] = mask
463            self.attr[5] = mask
464        else:
465            raise error.general('invalid setting: %s' % (flag))
466        self._update()
467
468    def input(self, flag, on):
469        mask = self._input_mask(flag)
470        if mask is None:
471            raise error.general('invalid input flag: %s' % (flag))
472        self._set(0, mask, on)
473        self._update()
474
475    def output(self, flag, on):
476        mask = self._output_mask(flag)
477        if mask is None:
478            raise error.general('invalid output flag: %s' % (flag))
479        self._set(1, mask, on)
480        self._update()
481
482    def control(self, flag, on):
483        mask = self._control_mask(flag)
484        if mask is None:
485            raise error.general('invalid control flag: %s' % (flag))
486        self._set(2, mask, on)
487        self._update()
488
489    def local(self, flag, on):
490        mask = self._local_mask(flag)
491        if mask is None:
492            raise error.general('invalid local flag: %s' % (flag))
493        self._set(3, mask, on)
494        self._update()
495
496    def vmin(self, _vmin):
497        self.attr[6][termios.VMIN] = _vmin
498
499    def vtime(self, _vtime):
500        self.attr[6][termios.VTIME] = _vtime
501
502    def set(self, flags = None):
503        if flags is None:
504            flags = self.raw
505        for f in flags.split(','):
506            if len(f) < 2:
507                raise error.general('invalid flag: %s' % (f))
508            if f[0] == '~':
509                on = False
510                flag = f[1:]
511            else:
512                on = True
513                flag = f
514            if f.startswith('VMIN'):
515                vs = f.split('=')
516                if len(vs) != 2:
517                    raise error.general('invalid vmin flag: %s' % (f))
518                try:
519                    _vmin = int(vs[1])
520                except:
521                    raise error.general('invalid vmin flag: %s' % (f))
522                self.vmin(_vmin)
523                continue
524            if f.startswith('VTIME'):
525                vs = f.split('=')
526                if len(vs) != 2:
527                    raise error.general('invalid vtime flag: %s' % (f))
528                try:
529                    _vtime = int(vs[1])
530                except:
531                    raise error.general('invalid vtime flag: %s' % (f))
532                self.vtime(_vtime)
533                continue
534            mask = self._baudrate_mask(flag)
535            if mask:
536                if not on:
537                    raise error.general('baudrates are not flags: %s' % (f))
538                self.attr[4] = mask
539                self.attr[5] = mask
540                continue
541            mask = self._input_mask(flag)
542            if mask:
543                self._set(0, mask, on)
544                continue
545            mask = self._output_mask(flag)
546            if mask:
547                self._set(1, mask, on)
548                continue
549            mask = self._control_mask(flag)
550            if mask:
551                self._set(2, mask, on)
552                continue
553            mask = self._local_mask(flag)
554            if mask:
555                self._set(3, mask, on)
556                continue
557            raise error.general('unknown tty flag: %s' % (f))
558        self._update()
559
560    def read(self):
561        return self.fs.read()
562
563if __name__ == "__main__":
564    if len(sys.argv) == 2:
565        t = tty(sys.argv[1])
566        t.baudrate('B115200')
567        t.input('BRKINT', False)
568        t.input('IGNBRK', True)
569        t.input('IGNCR', True)
570        t.local('ICANON', False)
571        t.local('ISIG', False)
572        t.local('IEXTEN', False)
573        t.local('ECHO', False)
574        t.control('CLOCAL', True)
575        t.control('CRTSCTS', False)
576        t.vmin(1)
577        t.vtime(2)
578        print(t)
579        t.set('B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS')
580        print(t)
581        t.on()
582        while True:
583            c = t.fd.read(1)
584            sys.stdout.write(c)
Note: See TracBrowser for help on using the repository browser.