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 | |
---|
35 | from __future__ import print_function |
---|
36 | |
---|
37 | import errno |
---|
38 | import os |
---|
39 | import threading |
---|
40 | import time |
---|
41 | |
---|
42 | # |
---|
43 | # Not available on Windows. Not sure what this means. |
---|
44 | # |
---|
45 | if os.name != 'nt': |
---|
46 | import fcntl |
---|
47 | from . import stty |
---|
48 | else: |
---|
49 | fcntl = None |
---|
50 | stty = None |
---|
51 | |
---|
52 | def save(): |
---|
53 | if stty is not None: |
---|
54 | return stty.save() |
---|
55 | return None |
---|
56 | |
---|
57 | def restore(attributes): |
---|
58 | if attributes is not None and stty is not None: |
---|
59 | stty.restore(attributes) |
---|
60 | |
---|
61 | class console(object): |
---|
62 | '''RTEMS Testing console base.''' |
---|
63 | |
---|
64 | def __init__(self, name, trace): |
---|
65 | self.name = name |
---|
66 | self.trace = trace |
---|
67 | |
---|
68 | def __del__(self): |
---|
69 | pass |
---|
70 | |
---|
71 | def _tracing(self): |
---|
72 | return self.trace |
---|
73 | |
---|
74 | def open(self): |
---|
75 | pass |
---|
76 | |
---|
77 | def close(self): |
---|
78 | pass |
---|
79 | |
---|
80 | class stdio(console): |
---|
81 | '''STDIO console.''' |
---|
82 | |
---|
83 | def __init__(self, trace = False): |
---|
84 | super(stdio, self).__init__('stdio', trace) |
---|
85 | |
---|
86 | class tty(console): |
---|
87 | '''TTY console connects to serial ports.''' |
---|
88 | |
---|
89 | raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS' |
---|
90 | |
---|
91 | def __init__(self, dev, output, setup = None, trace = False): |
---|
92 | self.tty = None |
---|
93 | self.read_thread = None |
---|
94 | self.dev = dev |
---|
95 | self.output = output |
---|
96 | if setup is None: |
---|
97 | self.setup = raw |
---|
98 | else: |
---|
99 | self.setup = setup |
---|
100 | super(tty, self).__init__(dev, trace) |
---|
101 | |
---|
102 | def __del__(self): |
---|
103 | super(tty, self).__del__() |
---|
104 | if self._tracing(): |
---|
105 | print(':: tty close', self.dev) |
---|
106 | if fcntl is not None: |
---|
107 | fcntl.fcntl(me.tty.fd, fcntl.F_SETFL, |
---|
108 | fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK) |
---|
109 | self.close() |
---|
110 | |
---|
111 | def open(self): |
---|
112 | def _readthread(me, x): |
---|
113 | if self._tracing(): |
---|
114 | print(':: tty runner started', self.dev) |
---|
115 | if fcntl is not None: |
---|
116 | fcntl.fcntl(me.tty.fd, fcntl.F_SETFL, |
---|
117 | fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) | os.O_NONBLOCK) |
---|
118 | line = '' |
---|
119 | while me.running: |
---|
120 | time.sleep(0.05) |
---|
121 | try: |
---|
122 | data = me.tty.fd.read() |
---|
123 | except IOError as ioe: |
---|
124 | if ioe.errno == errno.EAGAIN: |
---|
125 | continue |
---|
126 | raise |
---|
127 | except: |
---|
128 | raise |
---|
129 | for c in data: |
---|
130 | if len(c) == 0: |
---|
131 | continue |
---|
132 | if c != chr(0): |
---|
133 | line += c |
---|
134 | if c == '\n': |
---|
135 | me.output(line) |
---|
136 | line = '' |
---|
137 | if self._tracing(): |
---|
138 | print(':: tty runner finished', self.dev) |
---|
139 | if self._tracing(): |
---|
140 | print(':: tty open', self.dev) |
---|
141 | self.tty = stty.tty(self.dev) |
---|
142 | self.tty.set(self.setup) |
---|
143 | self.tty.on() |
---|
144 | self.read_thread = threading.Thread(target = _readthread, |
---|
145 | name = 'tty[%s]' % (self.dev), |
---|
146 | args = (self, 0)) |
---|
147 | self.read_thread.daemon = True |
---|
148 | self.running = True |
---|
149 | self.read_thread.start() |
---|
150 | |
---|
151 | def close(self): |
---|
152 | if self.tty: |
---|
153 | time.sleep(1) |
---|
154 | if self.read_thread: |
---|
155 | self.running = False |
---|
156 | self.read_thread.join(1) |
---|
157 | self.tty = None |
---|