1
- #!/usr/bin/env python3
1
+ #!/usr/bin/env python3.5
2
2
3
3
import sys
4
4
import os
5
5
import time
6
- import serial
7
- import threading
6
+ import asyncio
7
+ from serial import aio as asyncserial
8
8
import argparse
9
9
10
- if sys .platform == "win32" :
11
- import msvcrt
12
10
13
- def init_getkey ():
14
- pass
11
+ if sys .platform == "win32" :
12
+ def init_getkey (callback ):
13
+ raise NotImplementedError
15
14
16
15
def deinit_getkey ():
17
- pass
18
-
19
- def getkey ():
20
- return msvcrt .getch ()
16
+ raise NotImplementedError
21
17
else :
22
18
import termios
23
19
24
- def init_getkey ():
20
+ def init_getkey (callback ):
25
21
global old_termios
26
22
27
23
fd = sys .stdin .fileno ()
@@ -30,11 +26,12 @@ def init_getkey():
30
26
new [3 ] = new [3 ] & ~ termios .ICANON & ~ termios .ECHO
31
27
termios .tcsetattr (fd , termios .TCSANOW , new )
32
28
29
+ loop = asyncio .get_event_loop ()
30
+ loop .add_reader (sys .stdin .fileno (), callback )
31
+
33
32
def deinit_getkey ():
34
33
termios .tcsetattr (sys .stdin .fileno (), termios .TCSANOW , old_termios )
35
34
36
- def getkey ():
37
- return os .read (sys .stdin .fileno (), 1 )
38
35
39
36
40
37
sfl_magic_req = b"sL5DdSMmkekro\n "
@@ -115,39 +112,21 @@ class Flterm:
115
112
def __init__ (self , kernel_image , kernel_address ):
116
113
self .kernel_image = kernel_image
117
114
self .kernel_address = kernel_address
115
+ self .magic_detect_buffer = b"\x00 " * len (sfl_magic_req )
118
116
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 ):
137
118
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 )
141
121
if reply == sfl_ack_success :
142
- retry = 0
122
+ return
143
123
elif reply == sfl_ack_crcerror :
144
- retry = 1
124
+ pass # retry
145
125
else :
146
126
print ("[FLTERM] Got unknown reply '{}' from the device, aborting." .format (reply ))
147
- return 0
148
- return 1
127
+ raise ValueError
149
128
150
- def upload (self , filename , address ):
129
+ async def upload (self , filename , address ):
151
130
with open (filename , "rb" ) as f :
152
131
data = f .read ()
153
132
print ("[FLTERM] Uploading {} ({} bytes)..." .format (filename , len (data )))
@@ -162,7 +141,9 @@ def upload(self, filename, address):
162
141
frame .cmd = sfl_cmd_load
163
142
frame .payload = current_address .to_bytes (4 , "big" )
164
143
frame .payload += frame_data
165
- if self .send_frame (frame ) == 0 :
144
+ try :
145
+ await self .send_frame (frame )
146
+ except ValueError :
166
147
return
167
148
current_address += len (frame_data )
168
149
position += len (frame_data )
@@ -175,111 +156,85 @@ def upload(self, filename, address):
175
156
print ("[FLTERM] Upload complete ({0:.1f}KB/s)." .format (length / (elapsed * 1024 )))
176
157
return length
177
158
178
- def boot (self ):
159
+ async def boot (self ):
179
160
print ("[FLTERM] Booting the device." )
180
161
frame = SFLFrame ()
181
162
frame .cmd = sfl_cmd_jump
182
163
frame .payload = self .kernel_address .to_bytes (4 , "big" )
183
- self .send_frame (frame )
164
+ await self .send_frame (frame )
184
165
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 ):
193
167
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 )
201
169
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." );
235
176
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 ()
241
185
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 ()
245
190
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 ))
250
193
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 )
254
199
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 ()
259
208
260
209
261
210
def _get_args ():
262
211
parser = argparse .ArgumentParser ()
263
212
parser .add_argument ("port" , help = "serial port" )
264
213
parser .add_argument ("--speed" , default = 115200 , help = "serial baudrate" )
265
214
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" )
267
217
return parser .parse_args ()
268
218
269
219
270
220
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 ()
274
226
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 ))
275
231
try :
276
- flterm .open (args .port , args .speed )
277
- flterm .start ()
278
- flterm .join (True )
232
+ loop .run_forever ()
279
233
finally :
280
- flterm .close ()
234
+ loop .run_until_complete (
235
+ flterm .close ())
281
236
finally :
282
- deinit_getkey ()
237
+ loop . close ()
283
238
284
239
285
240
if __name__ == "__main__" :
0 commit comments