Skip to content

Commit 75b3ac9

Browse files
committedFeb 27, 2016
flterm: use asyncio (Linux only for now)
1 parent 43b15f9 commit 75b3ac9

File tree

1 file changed

+74
-119
lines changed

1 file changed

+74
-119
lines changed
 

‎misoc/tools/flterm.py

100644100755
+74-119
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/env python3.5
22

33
import sys
44
import os
55
import time
6-
import serial
7-
import threading
6+
import asyncio
7+
from serial import aio as asyncserial
88
import argparse
99

10-
if sys.platform == "win32":
11-
import msvcrt
1210

13-
def init_getkey():
14-
pass
11+
if sys.platform == "win32":
12+
def init_getkey(callback):
13+
raise NotImplementedError
1514

1615
def deinit_getkey():
17-
pass
18-
19-
def getkey():
20-
return msvcrt.getch()
16+
raise NotImplementedError
2117
else:
2218
import termios
2319

24-
def init_getkey():
20+
def init_getkey(callback):
2521
global old_termios
2622

2723
fd = sys.stdin.fileno()
@@ -30,11 +26,12 @@ def init_getkey():
3026
new[3] = new[3] & ~termios.ICANON & ~termios.ECHO
3127
termios.tcsetattr(fd, termios.TCSANOW, new)
3228

29+
loop = asyncio.get_event_loop()
30+
loop.add_reader(sys.stdin.fileno(), callback)
31+
3332
def deinit_getkey():
3433
termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, old_termios)
3534

36-
def getkey():
37-
return os.read(sys.stdin.fileno(), 1)
3835

3936

4037
sfl_magic_req = b"sL5DdSMmkekro\n"
@@ -115,39 +112,21 @@ class Flterm:
115112
def __init__(self, kernel_image, kernel_address):
116113
self.kernel_image = kernel_image
117114
self.kernel_address = kernel_address
115+
self.magic_detect_buffer = b"\x00"*len(sfl_magic_req)
118116

119-
self.reader_alive = False
120-
self.writer_alive = False
121-
122-
self.magic_detect_buffer = bytes(len(sfl_magic_req))
123-
124-
def open(self, port, baudrate):
125-
if hasattr(self, "port"):
126-
return
127-
self.port = serial.serial_for_url(port, baudrate)
128-
129-
def close(self):
130-
if not hasattr(self, "port"):
131-
return
132-
self.port.close()
133-
del self.port
134-
135-
def send_frame(self, frame):
136-
retry = 1
117+
async def send_frame(self, frame):
137118
while retry:
138-
self.port.write(frame.encode())
139-
# Get the reply from the device
140-
reply = self.port.read()
119+
self.writer.write(frame.encode())
120+
reply = await self.reader.read(1)
141121
if reply == sfl_ack_success:
142-
retry = 0
122+
return
143123
elif reply == sfl_ack_crcerror:
144-
retry = 1
124+
pass # retry
145125
else:
146126
print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply))
147-
return 0
148-
return 1
127+
raise ValueError
149128

150-
def upload(self, filename, address):
129+
async def upload(self, filename, address):
151130
with open(filename, "rb") as f:
152131
data = f.read()
153132
print("[FLTERM] Uploading {} ({} bytes)...".format(filename, len(data)))
@@ -162,7 +141,9 @@ def upload(self, filename, address):
162141
frame.cmd = sfl_cmd_load
163142
frame.payload = current_address.to_bytes(4, "big")
164143
frame.payload += frame_data
165-
if self.send_frame(frame) == 0:
144+
try:
145+
await self.send_frame(frame)
146+
except ValueError:
166147
return
167148
current_address += len(frame_data)
168149
position += len(frame_data)
@@ -175,111 +156,85 @@ def upload(self, filename, address):
175156
print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length/(elapsed*1024)))
176157
return length
177158

178-
def boot(self):
159+
async def boot(self):
179160
print("[FLTERM] Booting the device.")
180161
frame = SFLFrame()
181162
frame.cmd = sfl_cmd_jump
182163
frame.payload = self.kernel_address.to_bytes(4, "big")
183-
self.send_frame(frame)
164+
await self.send_frame(frame)
184165

185-
def detect_magic(self, data):
186-
if len(data):
187-
self.magic_detect_buffer = self.magic_detect_buffer[1:] + data
188-
return self.magic_detect_buffer == sfl_magic_req
189-
else:
190-
return False
191-
192-
def answer_magic(self):
166+
async def answer_magic(self):
193167
print("[FLTERM] Received firmware download request from the device.")
194-
if os.path.exists(self.kernel_image):
195-
self.port.write(sfl_magic_ack)
196-
self.upload(self.kernel_image, self.kernel_address)
197-
self.boot()
198-
print("[FLTERM] Done.");
199-
200-
def reader(self):
168+
self.writer.write(sfl_magic_ack)
201169
try:
202-
while self.reader_alive:
203-
c = self.port.read()
204-
if c == b"\r":
205-
sys.stdout.write(b"\n")
206-
else:
207-
sys.stdout.buffer.write(c)
208-
sys.stdout.flush()
209-
210-
if self.kernel_image is not None:
211-
if self.detect_magic(c):
212-
self.answer_magic()
213-
214-
except serial.SerialException:
215-
self.reader_alive = False
216-
raise
217-
218-
def start_reader(self):
219-
self.reader_alive = True
220-
self.reader_thread = threading.Thread(target=self.reader)
221-
self.reader_thread.setDaemon(True)
222-
self.reader_thread.start()
223-
224-
def stop_reader(self):
225-
self.reader_alive = False
226-
self.reader_thread.join()
227-
228-
def writer(self):
229-
try:
230-
while self.writer_alive:
231-
self.port.write(getkey())
232-
except:
233-
self.writer_alive = False
234-
raise
170+
await self.upload(self.kernel_image, self.kernel_address)
171+
except FileNotFoundError:
172+
print("[FLTERM] File not found")
173+
else:
174+
await self.boot()
175+
print("[FLTERM] Done.");
235176

236-
def start_writer(self):
237-
self.writer_alive = True
238-
self.writer_thread = threading.Thread(target=self.writer)
239-
self.writer_thread.setDaemon(True)
240-
self.writer_thread.start()
177+
async def reader_coro(self):
178+
while True:
179+
c = await self.reader.read(1)
180+
if c == b"\r":
181+
sys.stdout.write(b"\n")
182+
else:
183+
sys.stdout.buffer.write(c)
184+
sys.stdout.flush()
241185

242-
def stop_writer(self):
243-
self.writer_alive = False
244-
self.writer_thread.join()
186+
if self.kernel_image is not None:
187+
self.magic_detect_buffer = self.magic_detect_buffer[1:] + c
188+
if self.magic_detect_buffer == sfl_magic_req:
189+
self.answer_magic()
245190

246-
def start(self):
247-
print("[FLTERM] Starting....")
248-
self.start_reader()
249-
self.start_writer()
191+
def getkey_callback(self):
192+
self.writer.write(os.read(sys.stdin.fileno(), 1))
250193

251-
def stop(self):
252-
self.reader_alive = False
253-
self.writer_alive = False
194+
async def open(self, port, baudrate):
195+
self.reader, self.writer = await asyncserial.open_serial_connection(
196+
port, baudrate=baudrate)
197+
self.reader_task = asyncio.ensure_future(self.reader_coro())
198+
init_getkey(self.getkey_callback)
254199

255-
def join(self, writer_only=False):
256-
self.writer_thread.join()
257-
if not writer_only:
258-
self.reader_thread.join()
200+
async def close(self):
201+
self.reader_task.cancel()
202+
try:
203+
await asyncio.wait_for(self.reader_task, None)
204+
except asyncio.CancelledError:
205+
pass
206+
self.writer.close()
207+
deinit_getkey()
259208

260209

261210
def _get_args():
262211
parser = argparse.ArgumentParser()
263212
parser.add_argument("port", help="serial port")
264213
parser.add_argument("--speed", default=115200, help="serial baudrate")
265214
parser.add_argument("--kernel", default=None, help="kernel image")
266-
parser.add_argument("--kernel-adr", type=lambda a: int(a, 0), default=0x40000000, help="kernel address")
215+
parser.add_argument("--kernel-adr", type=lambda a: int(a, 0),
216+
default=0x40000000, help="kernel address")
267217
return parser.parse_args()
268218

269219

270220
def main():
271-
args = _get_args()
272-
flterm = Flterm(args.kernel, args.kernel_adr)
273-
init_getkey()
221+
if os.name == "nt":
222+
loop = asyncio.ProactorEventLoop()
223+
asyncio.set_event_loop(loop)
224+
else:
225+
loop = asyncio.get_event_loop()
274226
try:
227+
args = _get_args()
228+
flterm = Flterm(args.kernel, args.kernel_adr)
229+
loop.run_until_complete(
230+
flterm.open(args.port, args.speed))
275231
try:
276-
flterm.open(args.port, args.speed)
277-
flterm.start()
278-
flterm.join(True)
232+
loop.run_forever()
279233
finally:
280-
flterm.close()
234+
loop.run_until_complete(
235+
flterm.close())
281236
finally:
282-
deinit_getkey()
237+
loop.close()
283238

284239

285240
if __name__ == "__main__":

0 commit comments

Comments
 (0)
Please sign in to comment.