2 import sys
, os
, time
, serial
, threading
, argparse
3 from serial
.tools
.miniterm
import console
, character
, LF
6 sfl_magic_req
= "sL5DdSMmkekro\n"
7 sfl_magic_ack
= "z6IHG7cYDID6o\n"
16 sfl_ack_crcerror
= 'C'
20 # XXX : can we get CRC16 from a standard Python library as it's done
21 # for CRC32 with binascii?
23 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
24 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
25 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
26 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
27 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
28 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
29 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
30 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
31 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
32 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
33 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
34 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
35 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
36 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
37 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
38 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
39 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
40 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
41 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
42 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
43 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
44 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
45 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
46 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
47 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
48 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
49 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
50 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
51 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
52 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
53 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
54 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
61 crc
= crc16_table
[((crc
>> 8) ^ d
) & 0xff] ^
(crc
<< 8)
73 def compute_crc(self
):
75 crc_data
.append(self
.cmd
)
76 for d
in self
.payload
:
78 self
.crc
= crc16(crc_data
)
83 self
.raw
.append(self
.length
)
85 self
.raw
.append((self
.crc
& 0xff00) >> 8)
86 self
.raw
.append(self
.crc
& 0x00ff)
87 self
.raw
.append(self
.cmd
)
88 for d
in self
.payload
:
92 def get_file_data(filename
):
93 with
open(filename
, "rb") as f
:
99 data
.append(int.from_bytes(w
, "big"))
104 def __init__(self
, kernel_image
, kernel_address
):
105 self
.kernel_image
= kernel_image
106 self
.kernel_address
= kernel_address
108 self
.reader_alive
= False
109 self
.writer_alive
= False
111 self
.detect_magic_str
= " "*len(sfl_magic_req
)
113 def open(self
, port
, speed
):
114 port
= port
if not port
.isdigit() else int(port
)
115 self
.serial
= serial
.Serial(port
, speed
, timeout
=0.25)
116 self
.serial
.flushOutput()
117 self
.serial
.flushInput()
118 self
.serial
.close() # in case port was not correctly closed
124 def write_exact(self
, data
):
125 if isinstance(data
, str):
126 self
.serial
.write(bytes(data
, "utf-8"))
128 self
.serial
.write(serial
.to_bytes(data
))
130 def send_frame(self
, frame
):
134 self
.write_exact(frame
.raw
)
135 # Get the reply from the device
136 reply
= character(self
.serial
.read())
137 if reply
== sfl_ack_success
:
139 elif reply
== sfl_ack_crcerror
:
142 print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply
))
146 def upload(self
, filename
, address
):
147 data
= get_file_data(filename
)
148 print("[FLTERM] Uploading {} ({} bytes)...".format(filename
, len(data
)))
149 current_address
= address
153 while len(data
) != 0:
154 print("{}%\r".format(100*position
//length
), end
="")
157 frame_data
= data
[:251]
158 frame
.length
= len(frame_data
)+4
159 frame
.cmd
= sfl_cmd_load
160 frame
.payload
.append((current_address
& 0xff000000) >> 24)
161 frame
.payload
.append((current_address
& 0x00ff0000) >> 16)
162 frame
.payload
.append((current_address
& 0x0000ff00) >> 8)
163 frame
.payload
.append((current_address
& 0x000000ff) >> 0)
165 frame
.payload
.append(d
)
166 if self
.send_frame(frame
) == 0:
168 current_address
+= len(frame_data
)
169 position
+= len(frame_data
)
175 elapsed
= end
- start
176 print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length
/(elapsed
*1024)))
180 print("[FLTERM] Booting the device.")
183 frame
.cmd
= sfl_cmd_jump
184 frame
.payload
.append((self
.kernel_address
& 0xff000000) >> 24)
185 frame
.payload
.append((self
.kernel_address
& 0x00ff0000) >> 16)
186 frame
.payload
.append((self
.kernel_address
& 0x0000ff00) >> 8)
187 frame
.payload
.append((self
.kernel_address
& 0x000000ff) >> 0)
188 self
.send_frame(frame
)
190 def detect_magic(self
, data
):
192 self
.detect_magic_str
= self
.detect_magic_str
[1:] + data
193 return self
.detect_magic_str
== sfl_magic_req
197 def answer_magic(self
):
198 print("[FLTERM] Received firmware download request from the device.")
199 if os
.path
.exists(self
.kernel_image
):
200 self
.write_exact(sfl_magic_ack
)
201 self
.upload(self
.kernel_image
, self
.kernel_address
)
203 print("[FLTERM] Done.");
207 while self
.reader_alive
:
208 c
= character(self
.serial
.read())
210 sys
.stdout
.write('\n')
215 if self
.kernel_image
is not None:
216 if self
.detect_magic(c
):
219 except serial
.SerialException
:
220 self
.reader_alive
= False
223 def start_reader(self
):
224 self
.reader_alive
= True
225 self
.reader_thread
= threading
.Thread(target
=self
.reader
)
226 self
.reader_thread
.setDaemon(True)
227 self
.reader_thread
.start()
229 def stop_reader(self
):
230 self
.reader_alive
= False
231 self
.reader_thread
.join()
235 while self
.writer_alive
:
238 except KeyboardInterrupt:
239 b
= serial
.to_bytes([3])
244 self
.serial
.write(LF
)
248 self
.writer_alive
= False
251 def start_writer(self
):
252 self
.writer_alive
= True
253 self
.writer_thread
= threading
.Thread(target
=self
.writer
)
254 self
.writer_thread
.setDaemon(True)
255 self
.writer_thread
.start()
257 def stop_writer(self
):
258 self
.writer_alive
= False
259 self
.writer_thread
.join()
262 print("[FLTERM] Starting....")
267 self
.reader_alive
= False
268 self
.writer_alive
= False
270 def join(self
, writer_only
=False):
271 self
.writer_thread
.join()
273 self
.reader_thread
.join()
277 parser
= argparse
.ArgumentParser()
278 parser
.add_argument("--port", default
="2", help="serial port")
279 parser
.add_argument("--speed", default
=115200, help="serial baudrate")
280 parser
.add_argument("--kernel", default
=None, help="kernel image")
281 parser
.add_argument("--kernel_adr", default
=0x40000000, help="kernel address")
282 return parser
.parse_args()
284 if __name__
== "__main__":
286 flterm
= Flterm(args
.kernel
, args
.kernel_adr
)
287 flterm
.open(args
.port
, args
.speed
)
291 except KeyboardInterrupt: