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(port
, speed
, timeout
=0.25)
121 self
.serial
.flushOutput()
122 self
.serial
.flushInput()
123 self
.serial
.close() # in case port was not correctly closed
129 def write_exact(self
, data
):
130 if isinstance(data
, str):
131 self
.serial
.write(bytes(data
, "utf-8"))
133 self
.serial
.write(serial
.to_bytes(data
))
135 def send_frame(self
, frame
):
139 self
.write_exact(frame
.raw
)
140 # Get the reply from the device
141 reply
= character(self
.serial
.read())
142 if reply
== sfl_ack_success
:
144 elif reply
== sfl_ack_crcerror
:
147 print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply
))
151 def upload(self
, filename
, address
):
152 data
= get_file_data(filename
)
153 print("[FLTERM] Uploading {} ({} bytes)...".format(filename
, len(data
)))
154 current_address
= address
158 while len(data
) != 0:
159 print("{}%\r".format(100*position
//length
), end
="")
162 frame_data
= data
[:251]
163 frame
.length
= len(frame_data
)+4
164 frame
.cmd
= sfl_cmd_load
165 frame
.payload
.append((current_address
& 0xff000000) >> 24)
166 frame
.payload
.append((current_address
& 0x00ff0000) >> 16)
167 frame
.payload
.append((current_address
& 0x0000ff00) >> 8)
168 frame
.payload
.append((current_address
& 0x000000ff) >> 0)
170 frame
.payload
.append(d
)
171 if self
.send_frame(frame
) == 0:
173 current_address
+= len(frame_data
)
174 position
+= len(frame_data
)
180 elapsed
= end
- start
181 print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length
/(elapsed
*1024)))
185 print("[FLTERM] Booting the device.")
188 frame
.cmd
= sfl_cmd_jump
189 frame
.payload
.append((self
.kernel_address
& 0xff000000) >> 24)
190 frame
.payload
.append((self
.kernel_address
& 0x00ff0000) >> 16)
191 frame
.payload
.append((self
.kernel_address
& 0x0000ff00) >> 8)
192 frame
.payload
.append((self
.kernel_address
& 0x000000ff) >> 0)
193 self
.send_frame(frame
)
195 def detect_magic(self
, data
):
197 self
.detect_magic_str
= self
.detect_magic_str
[1:] + data
198 return self
.detect_magic_str
== sfl_magic_req
202 def answer_magic(self
):
203 print("[FLTERM] Received firmware download request from the device.")
204 if os
.path
.exists(self
.kernel_image
):
205 self
.write_exact(sfl_magic_ack
)
206 self
.upload(self
.kernel_image
, self
.kernel_address
)
208 print("[FLTERM] Done.");
212 while self
.reader_alive
:
213 c
= character(self
.serial
.read())
215 sys
.stdout
.write('\n')
220 if self
.kernel_image
is not None:
221 if self
.detect_magic(c
):
224 except serial
.SerialException
:
225 self
.reader_alive
= False
228 def start_reader(self
):
229 self
.reader_alive
= True
230 self
.reader_thread
= threading
.Thread(target
=self
.reader
)
231 self
.reader_thread
.setDaemon(True)
232 self
.reader_thread
.start()
234 def stop_reader(self
):
235 self
.reader_alive
= False
236 self
.reader_thread
.join()
240 while self
.writer_alive
:
243 except KeyboardInterrupt:
244 b
= serial
.to_bytes([3])
249 self
.serial
.write(LF
)
253 self
.writer_alive
= False
256 def start_writer(self
):
257 self
.writer_alive
= True
258 self
.writer_thread
= threading
.Thread(target
=self
.writer
)
259 self
.writer_thread
.setDaemon(True)
260 self
.writer_thread
.start()
262 def stop_writer(self
):
263 self
.writer_alive
= False
264 self
.writer_thread
.join()
267 print("[FLTERM] Starting....")
272 self
.reader_alive
= False
273 self
.writer_alive
= False
275 def join(self
, writer_only
=False):
276 self
.writer_thread
.join()
278 self
.reader_thread
.join()
282 parser
= argparse
.ArgumentParser()
283 parser
.add_argument("--port", default
="2", help="serial port")
284 parser
.add_argument("--speed", default
=115200, help="serial baudrate")
285 parser
.add_argument("--kernel", default
=None, help="kernel image")
286 parser
.add_argument("--kernel_adr", default
=0x40000000, help="kernel address")
287 return parser
.parse_args()
289 if __name__
== "__main__":
291 flterm
= Flterm(args
.kernel
, args
.kernel_adr
)
292 flterm
.open(args
.port
, args
.speed
)
296 except KeyboardInterrupt: