-
Notifications
You must be signed in to change notification settings - Fork 1
/
genImage.py
132 lines (108 loc) · 3.5 KB
/
genImage.py
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
# Digraph compression for firmware and bootloader images
import os, sys, urllib.request
from crc import Calculator, Crc32
N = 64
chr = {}
dig = {}
calculator = Calculator(Crc32.CRC32)
def doAnalyze(filename):
global lfs, mfd, chr, dig
with open(filename, "rb") as file:
data = file.read()
for i in data:
if i in chr:
chr[i] += 1
else:
chr[i] = 1
for i in range(len(data) - 1):
x = data[i], data[i + 1]
if x in dig:
dig[x] += 1
else:
dig[x] = 1
lfs = sorted(chr.items(), key=lambda x: x[1])[:N]
lfs = [i[0] for i in lfs]
mfd = sorted(dig.items(), key=lambda x: x[1], reverse=True)[: N - 1]
mfd = [i[0] for i in mfd]
def analyze(filenames):
global lfs, mfd
for filename in filenames:
doAnalyze(filename)
print(
"""#include <stdint.h>
typedef struct {uint8_t a,b;} Digram;
"""
)
print(f"//{N} less frequent symbols:")
print("uint8_t lfs[]={\n\t", end="")
for i,s in enumerate(lfs):
print(f"0x{s:02X},", end="\n\t" if i%16==15 else "")
print("\n};\n")
print(f"//{N-1} most frequent digrams:")
print("Digram digrams[]={\n\t", end="")
for i,d in enumerate(mfd):
print(f"{{0x{d[0]:02X},0x{d[1]:02X}}},", end="\n\t" if i%8==7 else "")
print("\n};\n")
def compress(filename, varname):
global lfs, mfd
with open(filename, "rb") as file:
data = file.read()
print(f"uint32_t {varname}_CRC=0x{calculator.checksum(bytearray(data)):08X}UL;\n")
i = 0
nBytes = 0
bytes = []
while True:
if data[i] in lfs:
bytes.append(lfs[N - 1])
bytes.append(data[i])
nBytes += 2
else:
if i < len(data) - 1:
try:
k = mfd.index((data[i], data[i + 1]))
bytes.append(lfs[k])
i += 1
nBytes += 1
except ValueError:
bytes.append(data[i])
nBytes += 1
else:
bytes.append(data[i])
nBytes += 1
i += 1
if i >= len(data):
break
print(
f"//size uncompressed: {len(data)}, compressed: {nBytes}, ratio {100*nBytes//len(data)}%"
)
print(f"const uint8_t {varname}[] PROGMEM={{\n\t", end="")
for i, b in enumerate(bytes):
print(f"0x{b:02X},", end="\n\t" if i % 16 == 15 else "")
print("\n};")
# test decompressione
i = 0
data1 = bytearray([])
while True:
try:
k = lfs.index(bytes[i])
if k == N - 1:
i += 1
data1.append(bytes[i])
else:
data1.append(mfd[k][0])
data1.append(mfd[k][1])
except ValueError:
data1.append(bytes[i])
i += 1
if i >= len(bytes):
break
print(f"//decompression test {'OK' if data==data1 else 'KO'}\n")
if len(data) != len(data1):
print(f"//{len(data)} vs {len(data1)} bytes")
# TODO: download ISP_UART0.bin
url = "https://github.com/OpenNuvoton/MS51_BSP/raw/refs/heads/master/MS51FC0AE_MS51XC0BE_MS51EB0AE_MS51EC0AE_MS51TC0AE_MS51PC0AE/SampleCode/ISP/ISP_UART0/ExcutableBin/ISP_UART0.bin"
if not os.path.isfile("build/ISP_UART0.bin"):
urllib.request.urlretrieve(url, "build/ISP_UART0.bin")
analyze(["build/main.bin", "build/ISP_UART0.bin"])
compress("build/main.bin", "firmware")
compress("build/ISP_UART0.bin", "bootloader")