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
60 crc
= crc16_table
[((crc
>> 8) ^ d
) & 0xff] ^
(crc
<< 8)
71 def compute_crc(self
):
73 crc_data
.append(self
.cmd
)
74 for d
in self
.payload
:
76 self
.crc
= crc16(crc_data
)
81 self
.raw
.append(self
.length
)
83 self
.raw
.append((self
.crc
& 0xff00) >> 8)
84 self
.raw
.append(self
.crc
& 0x00ff)
85 self
.raw
.append(self
.cmd
)
86 for d
in self
.payload
:
89 def get_file_data(filename
):
90 with
open(filename
, "rb") as f
:
96 data
.append(int.from_bytes(w
, "big"))
100 def __init__(self
, kernel_image
, kernel_address
):
101 self
.kernel_image
= kernel_image
102 self
.kernel_address
= kernel_address
104 self
.reader_alive
= False
105 self
.writer_alive
= False
107 self
.detect_magic_str
= " "*len(sfl_magic_req
)
109 def open(self
, port
, speed
):
110 port
= port
if not port
.isdigit() else int(port
)
111 self
.serial
= serial
.Serial(port
, speed
, timeout
=0.25)
112 self
.serial
.flushOutput()
113 self
.serial
.flushInput()
114 self
.serial
.close() # in case port was not correctly closed
120 def write_exact(self
, data
):
121 if isinstance(data
, str):
122 self
.serial
.write(bytes(data
, "utf-8"))
124 self
.serial
.write(serial
.to_bytes(data
))
126 def send_frame(self
, frame
):
130 self
.write_exact(frame
.raw
)
131 # Get the reply from the device
132 reply
= character(self
.serial
.read())
133 if reply
== sfl_ack_success
:
135 elif reply
== sfl_ack_crcerror
:
138 print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply
))
142 def upload(self
, filename
, address
):
143 data
= get_file_data(filename
)
144 print("[FLTERM] Uploading {} ({} bytes)...".format(filename
, len(data
)))
145 current_address
= address
149 while len(data
) != 0:
150 print("{}%\r".format(100*position
//length
), end
="")
153 frame_data
= data
[:251]
154 frame
.length
= len(frame_data
)+4
155 frame
.cmd
= sfl_cmd_load
156 frame
.payload
.append((current_address
& 0xff000000) >> 24)
157 frame
.payload
.append((current_address
& 0x00ff0000) >> 16)
158 frame
.payload
.append((current_address
& 0x0000ff00) >> 8)
159 frame
.payload
.append((current_address
& 0x000000ff) >> 0)
161 frame
.payload
.append(d
)
162 if self
.send_frame(frame
) == 0:
164 current_address
+= len(frame_data
)
165 position
+= len(frame_data
)
171 elapsed
= end
- start
172 print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length
/(elapsed
*1024)))
176 print("[FLTERM] Booting the device.")
179 frame
.cmd
= sfl_cmd_jump
180 frame
.payload
.append((self
.kernel_address
& 0xff000000) >> 24)
181 frame
.payload
.append((self
.kernel_address
& 0x00ff0000) >> 16)
182 frame
.payload
.append((self
.kernel_address
& 0x0000ff00) >> 8)
183 frame
.payload
.append((self
.kernel_address
& 0x000000ff) >> 0)
184 self
.send_frame(frame
)
186 def detect_magic(self
, data
):
188 self
.detect_magic_str
= self
.detect_magic_str
[1:] + data
189 return self
.detect_magic_str
== sfl_magic_req
193 def answer_magic(self
):
194 print("[FLTERM] Received firmware download request from the device.")
195 if os
.path
.exists(self
.kernel_image
):
196 self
.write_exact(sfl_magic_ack
)
197 self
.upload(self
.kernel_image
, self
.kernel_address
)
199 print("[FLTERM] Done.");
203 while self
.reader_alive
:
204 c
= character(self
.serial
.read())
206 sys
.stdout
.write('\n')
211 if self
.kernel_image
is not None:
212 if self
.detect_magic(c
):
215 except serial
.SerialException
:
216 self
.reader_alive
= False
219 def start_reader(self
):
220 self
.reader_alive
= True
221 self
.reader_thread
= threading
.Thread(target
=self
.reader
)
222 self
.reader_thread
.setDaemon(True)
223 self
.reader_thread
.start()
225 def stop_reader(self
):
226 self
.reader_alive
= False
227 self
.reader_thread
.join()
231 while self
.writer_alive
:
234 except KeyboardInterrupt:
235 b
= serial
.to_bytes([3])
240 self
.serial
.write(LF
)
244 self
.writer_alive
= False
247 def start_writer(self
):
248 self
.writer_alive
= True
249 self
.writer_thread
= threading
.Thread(target
=self
.writer
)
250 self
.writer_thread
.setDaemon(True)
251 self
.writer_thread
.start()
253 def stop_writer(self
):
254 self
.writer_alive
= False
255 self
.writer_thread
.join()
258 print("[FLTERM] Starting....")
263 self
.reader_alive
= False
264 self
.writer_alive
= False
266 def join(self
, writer_only
=False):
267 self
.writer_thread
.join()
269 self
.reader_thread
.join()
272 parser
= argparse
.ArgumentParser()
273 parser
.add_argument("--port", default
="2", help="serial port")
274 parser
.add_argument("--speed", default
=115200, help="serial baudrate")
275 parser
.add_argument("--kernel", default
=None, help="kernel image")
276 parser
.add_argument("--kernel_adr", default
=0x40000000, help="kernel address")
277 return parser
.parse_args()
279 if __name__
== "__main__":
281 flterm
= Flterm(args
.kernel
, args
.kernel_adr
)
282 flterm
.open(args
.port
, args
.speed
)
286 except KeyboardInterrupt: