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