forked from 32blit/32blit-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfirmware-uploader
152 lines (118 loc) · 3.76 KB
/
firmware-uploader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
"""
10 Send total size of binary (Unsigned 32bit integer, LE)
20 Send 2k block of data
30 Wait for response CRC
40 Check CRC against data send
50 If OK send next packet
60 Of !OK fail with error
70 GOTO 20
"""
import serial
import binascii
from serial.tools import list_ports
import struct
import sys
X_VID = 0x0483 # 1155
X_PID = 0x5740 # 22336
TIMEOUT = 2 # Timeout in seconds
MAX_PACKET_SIZE = 4 * 1024
binary_file_path = None
device = None
class Port(object):
def __init__(self):
self.last_write = None
def read(self, length):
if len(self.last_write) == 4: # Hack to reply with size when size is received
return self.last_write
else:
return struct.pack("<L", binascii.crc32(self.last_write))
def write(self, data):
self.last_write = data
class Packet(object):
def __init__(self, data):
self.data = data
self.size = len(data)
self.checksum = self._calculate_checksum()
def _calculate_checksum(self):
return binascii.crc32(self.data)
def __repr__(self):
orig = object.__repr__(self)
return "{} Length: {} Checksum: {}".format(orig, self.size, self.checksum)
if len(sys.argv) > 1:
binary_file_path = sys.argv[1]
if binary_file_path is None:
print("No firmware file specified!")
print("Usage: {} <firmware_file>".format(sys.argv[0]))
sys.exit(1)
"""
Attempt to find the device port.
"""
# ports = list_ports.comports()
# for port in ports:
# print(port.device)
# vid = port.vid
# pid = port.pid
# print(repr(port.pid))
# print(repr(port.vid))
# print(repr(X_PID))
# print(repr(X_VID))
# if (vid, pid) == (X_VID, X_PID):
# device = port.device
device = "COM4"
if device is None:
print("Unable to find device with VID/PID {:04x}/{:04x}".format(X_VID, X_PID))
sys.exit(1)
#port = Port()
port = serial.Serial(device, timeout=TIMEOUT, write_timeout=TIMEOUT, baudrate=9600)
binary_file = open(binary_file_path, 'rb', 0)
packets = []
total_size = 0
"""
Load the binary file into MAX_PACKET_SIZE chunks,
the "Packet" class will handle precalculating the
CRC32 of each chunk.
"""
while True:
packet = binary_file.read(MAX_PACKET_SIZE)
if len(packet) == 0: # EOF
break
total_size += len(packet)
packets.append(Packet(packet))
print("Binary file size: {} bytes".format(total_size))
print("Total Packets: {}".format(len(packets)))
"""
Send the total size as an unsigned int32.
Check the response is equal to the sent size.
"""
try:
port.write(struct.pack("<L", total_size))
except serial.serialutil.SerialTimeoutException:
print("FAILED TO START TRANSFER: Timeout writing size.")
sys.exit(1)
response = port.read(4)
if len(response) == 0:
print("FAILED TO START TRANSFER: Timeout waiting for response.")
sys.exit(1)
response_size = struct.unpack("<L", response)[0]
if response_size != total_size:
print("FAILED TO START TRANSFER: {:04d}b != {:04d}b".format(response_size, total_size))
sys.exit(1)
"""
Iterate through each packet and send it.
Check the response is equal to the packet CRC32
"""
packet_count = 0
for packet in packets:
port.write(packet.data)
response = port.read(4)
if len(response) == 0:
print("{:04d}: TIMEOUT".format(packet_count))
sys.exit(1)
crc = struct.unpack("<L", response)[0]
if crc != packet.checksum:
print("{:04d}: CRC ERROR {:08x} != {:08x}".format(packet_count, crc, packet.checksum))
sys.exit(1)
print("{:04d}: CRC OK {:08x} {:04d}b".format(packet_count, crc, packet.size))
packet_count += 1
print("DONE!")