7
7
import threading
8
8
import argparse
9
9
10
-
10
+ # TODO: cleanup getkey function
11
11
if sys .platform == "win32" :
12
12
def getkey ():
13
13
import msvcrt
@@ -30,27 +30,22 @@ def getkey():
30
30
return c
31
31
32
32
33
- def character (b ):
34
- return b .decode ('latin1' )
35
-
33
+ sfl_prompt_req = b"F7: boot from serial\n "
34
+ sfl_prompt_ack = b"\x06 "
36
35
37
- sfl_prompt_req = "F7: boot from serial\n "
38
- sfl_prompt_ack = "\x06 "
39
-
40
- sfl_magic_req = "sL5DdSMmkekro\n "
41
- sfl_magic_ack = "z6IHG7cYDID6o\n "
36
+ sfl_magic_req = b"sL5DdSMmkekro\n "
37
+ sfl_magic_ack = b"z6IHG7cYDID6o\n "
42
38
43
39
# General commands
44
- sfl_cmd_abort = 0x00
45
- sfl_cmd_load = 0x01
46
- sfl_cmd_jump = 0x02
47
-
40
+ sfl_cmd_abort = b"\x00 "
41
+ sfl_cmd_load = b"\x01 "
42
+ sfl_cmd_jump = b"\x02 "
48
43
49
44
# Replies
50
- sfl_ack_success = 'K'
51
- sfl_ack_crcerror = 'C'
52
- sfl_ack_unknown = 'U'
53
- sfl_ack_error = 'E'
45
+ sfl_ack_success = b"K"
46
+ sfl_ack_crcerror = b"C"
47
+ sfl_ack_unknown = b"U"
48
+ sfl_ack_error = b"E"
54
49
55
50
56
51
crc16_table = [
@@ -98,40 +93,18 @@ def crc16(l):
98
93
99
94
class SFLFrame :
100
95
def __init__ (self ):
101
- self .length = None
102
- self .cmd = None
103
- self .payload = []
104
- self .crc = None
105
- self .raw = []
96
+ self .cmd = bytes ()
97
+ self .payload = bytes ()
106
98
107
99
def compute_crc (self ):
108
- crc_data = []
109
- crc_data .append (self .cmd )
110
- for d in self .payload :
111
- crc_data .append (d )
112
- self .crc = crc16 (crc_data )
113
- return self .crc
100
+ return crc16 (self .cmd + self .payload )
114
101
115
102
def encode (self ):
116
- self .raw = []
117
- self .raw .append (self .length )
118
- self .compute_crc ()
119
- for d in self .crc .to_bytes (2 , "big" ):
120
- self .raw .append (d )
121
- self .raw .append (self .cmd )
122
- for d in self .payload :
123
- self .raw .append (d )
124
-
125
-
126
- def get_file_data (filename ):
127
- with open (filename , "rb" ) as f :
128
- data = []
129
- while True :
130
- w = f .read (1 )
131
- if not w :
132
- break
133
- data .append (int .from_bytes (w , "big" ))
134
- return data
103
+ packet = bytes ([len (self .payload )])
104
+ packet += self .compute_crc ().to_bytes (2 , "big" )
105
+ packet += self .cmd
106
+ packet += self .payload
107
+ return packet
135
108
136
109
137
110
class Flterm :
@@ -143,39 +116,26 @@ def __init__(self, serial_boot, kernel_image, kernel_address):
143
116
self .reader_alive = False
144
117
self .writer_alive = False
145
118
146
- self .detect_prompt_str = " " * len (sfl_prompt_req )
147
- self .detect_magic_str = " " * len (sfl_magic_req )
148
-
149
- def open (self , port , speed ):
150
- self .serial = serial .serial_for_url (
151
- port ,
152
- baudrate = speed ,
153
- bytesize = 8 ,
154
- parity = "N" ,
155
- stopbits = 1 ,
156
- xonxoff = 0 ,
157
- timeout = 0.25 )
158
- self .serial .flushOutput ()
159
- self .serial .flushInput ()
160
- self .serial .close () # in case port was not correctly closed
161
- self .serial .open ()
119
+ self .promp_detect_buffer = bytes (len (sfl_prompt_req ))
Has a conversation. Original line has a conversation.
120
+ self .magic_detect_buffer = bytes (len (sfl_magic_req ))
162
121
163
- def close (self ):
164
- self .serial .close ()
122
+ def open (self , port , baudrate ):
Has a conversation. Original line has a conversation.
123
+ if hasattr (self , "port" ):
124
+ return
125
+ self .port = serial .serial_for_url (port , baudrate )
165
126
166
- def write_exact (self , data ):
167
- if isinstance ( data , str ):
168
- self . serial . write ( bytes ( data , "utf-8" ))
169
- else :
170
- self .serial . write ( serial . to_bytes ( data ))
127
+ def close (self ):
128
+ if not hasattr ( self , "port" ):
129
+ return
130
+ self . port . close ()
131
+ del self .port
171
132
172
133
def send_frame (self , frame ):
173
- frame .encode ()
174
134
retry = 1
175
135
while retry :
176
- self .write_exact (frame .raw )
136
+ self .port . write (frame .encode () )
177
137
# Get the reply from the device
178
- reply = character ( self .serial .read () )
138
+ reply = self .port .read ()
179
139
if reply == sfl_ack_success :
180
140
retry = 0
181
141
elif reply == sfl_ack_crcerror :
@@ -186,22 +146,20 @@ def send_frame(self, frame):
186
146
return 1
187
147
188
148
def upload (self , filename , address ):
189
- data = get_file_data (filename )
149
+ with open (filename , "rb" ) as f :
150
+ data = f .read ()
190
151
print ("[FLTERM] Uploading {} ({} bytes)..." .format (filename , len (data )))
191
152
current_address = address
192
153
position = 0
193
154
length = len (data )
194
155
start = time .time ()
195
- while len (data ) != 0 :
156
+ while len (data ):
196
157
print ("{}%\r " .format (100 * position // length ), end = "" )
197
158
frame = SFLFrame ()
198
159
frame_data = data [:251 ]
199
- frame .length = len (frame_data ) + 4
200
160
frame .cmd = sfl_cmd_load
201
- for d in current_address .to_bytes (4 , "big" ):
202
- frame .payload .append (d )
203
- for d in frame_data :
204
- frame .payload .append (d )
161
+ frame .payload = current_address .to_bytes (4 , "big" )
162
+ frame .payload += frame_data
205
163
if self .send_frame (frame ) == 0 :
206
164
return
207
165
current_address += len (frame_data )
@@ -218,46 +176,48 @@ def upload(self, filename, address):
218
176
def boot (self ):
219
177
print ("[FLTERM] Booting the device." )
220
178
frame = SFLFrame ()
221
- frame .length = 4
222
179
frame .cmd = sfl_cmd_jump
223
- for d in self .kernel_address .to_bytes (4 , "big" ):
224
- frame .payload .append (d )
180
+ frame .payload = self .kernel_address .to_bytes (4 , "big" )
225
181
self .send_frame (frame )
226
182
227
183
def detect_prompt (self , data ):
228
- if data is not "" :
229
- self .detect_prompt_str = self .detect_prompt_str [1 :] + data
230
- return self .detect_prompt_str == sfl_prompt_req
184
+ if len ( data ) :
185
+ self .promp_detect_buffer = self .promp_detect_buffer [1 :] + data
186
+ return self .promp_detect_buffer == sfl_prompt_req
231
187
else :
232
188
return False
233
189
234
190
def answer_prompt (self ):
235
191
print ("[FLTERM] Received serial boot prompt from the device." )
236
- self .write_exact (sfl_prompt_ack )
192
+ self .port . write (sfl_prompt_ack )
237
193
238
194
def detect_magic (self , data ):
239
- if data is not "" :
240
- self .detect_magic_str = self .detect_magic_str [1 :] + data
241
- return self .detect_magic_str == sfl_magic_req
195
+ if len ( data ) :
196
+ self .magic_detect_buffer = self .magic_detect_buffer [1 :] + data
197
+ return self .magic_detect_buffer == sfl_magic_req
242
198
else :
243
199
return False
244
200
245
201
def answer_magic (self ):
246
202
print ("[FLTERM] Received firmware download request from the device." )
247
203
if os .path .exists (self .kernel_image ):
248
- self .write_exact (sfl_magic_ack )
204
+ self .port . write (sfl_magic_ack )
249
205
self .upload (self .kernel_image , self .kernel_address )
250
206
self .boot ()
251
207
print ("[FLTERM] Done." );
252
208
253
209
def reader (self ):
254
210
try :
255
211
while self .reader_alive :
256
- c = character ( self .serial .read () )
257
- if c == ' \r ' :
258
- sys .stdout .write (' \n ' )
212
+ c = self .port .read ()
213
+ if c == b" \r " :
214
+ sys .stdout .write (b" \n " )
259
215
else :
260
- sys .stdout .write (c )
216
+ try :
217
+ # TODO: cleanup
Has conversations. Original line has conversations.
218
+ sys .stdout .write (c .decode ())
219
+ except :
220
+ pass
261
221
sys .stdout .flush ()
262
222
263
223
if self .kernel_image is not None :
@@ -286,14 +246,13 @@ def writer(self):
286
246
try :
287
247
b = getkey ()
288
248
except KeyboardInterrupt :
289
- b = serial .to_bytes ([3 ])
290
- c = character (b )
291
- if c == chr (0x03 ):
249
+ b = b"\x03 "
250
+ if b == b"\x03 " :
Has conversations. Original line has conversations. 292
251
self .stop ()
293
- elif c == ' \n ' :
294
- self .serial .write (serial . to_bytes ([ 10 ]) )
252
+ elif b == b" \n " :
253
+ self .port .write (b" \x0a " )
295
254
else :
296
- self .serial .write (b )
255
+ self .port .write (b )
297
256
except :
298
257
self .writer_alive = False
299
258
raise
@@ -343,6 +302,7 @@ def main():
343
302
flterm .join (True )
344
303
except KeyboardInterrupt :
345
304
pass
305
+ flterm .close ()
Has conversations. Original line has conversations. 346
306
347
307
348
308
if __name__ == "__main__" :