Skip to content

Commit 81c0ef9

Browse files
authored
Merge pull request #166 from arduino-libraries/lzss-tooling
Add tool for LZSS compression/decompression and improve documentation
2 parents 5a9bb84 + a7ee500 commit 81c0ef9

File tree

5 files changed

+248
-6
lines changed

5 files changed

+248
-6
lines changed

Diff for: extras/tools/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.bin
2+
*.ota
3+
*.json
4+

Diff for: extras/tools/README.md

+30-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1-
`bin2ota.py`
2-
============
1+
Firmware Over-The-Air Tools
2+
===========================
3+
4+
## How-to-OTA
5+
6+
Arduino IDE: `Sketch` -> `Export compiled Binary`
7+
```bash
8+
cp sketch.bin ~/Arduino/libraries/ArduinoIoTCloud/extras/tools/
9+
cd ~/Arduino/libraries/ArduinoIoTCloud/extras/tools
10+
./bin2ota.py sketch.bin sketch.ota
11+
./bin2json.py sketch.ota sketch.json
12+
./ota-upload.sh CLIENT_ID CLIENT_SECRET DEVICE_ID sketch.json
13+
```
14+
15+
## `bin2ota.py`
316
This tool can be used to extend (actually prefix) a binary generated with e.g. the Arduino IDE with the required length and crc values required to perform an OTA (Over-The-Air) update of the firmware.
417

518
### How-To-Use
@@ -25,17 +38,28 @@ This tool can be used to extend (actually prefix) a binary generated with e.g. t
2538
0000030 0000 0000 7485 0000 0000 0000 0000 0000
2639
```
2740

28-
`bin2json.py`
29-
=============
41+
## `lzss.py`
42+
This tool allows to compress a binary file using the LZSS algorithm.
43+
44+
### How-To-Use
45+
* Encoding (Compressing)
46+
```bash
47+
./lzss.py --encode sketch.bin sketch.lzss
48+
```
49+
* Decoding (Extracting)
50+
```bash
51+
./lzss.py --decode sketch.lzss sketch.bin
52+
```
53+
54+
## `bin2json.py`
3055
This tool converts the binary file into base64 encoded JSON which is necessary for feeding it to the server.
3156

3257
### How-To-Use
3358
```bash
3459
./bin2json.py sketch.ota sketch.json
3560
```
3661

37-
`ota-upload.sh`
38-
==============
62+
## `ota-upload.sh`
3963
This tool allows to upload a OTA binary to a device via a Arduino cloud server.
4064

4165
### How-To-Use

Diff for: extras/tools/lzss.c

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/* LZSS encoder-decoder (Haruhiko Okumura; public domain) */
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
6+
#define EI 11 /* typically 10..13 */
7+
#define EJ 4 /* typically 4..5 */
8+
#define P 1 /* If match length <= P then output one character */
9+
#define N (1 << EI) /* buffer size */
10+
#define F ((1 << EJ) + 1) /* lookahead buffer size */
11+
12+
int bit_buffer = 0, bit_mask = 128;
13+
unsigned long codecount = 0, textcount = 0;
14+
unsigned char buffer[N * 2];
15+
FILE *infile, *outfile;
16+
17+
void error(void)
18+
{
19+
printf("Output error\n"); exit(1);
20+
}
21+
22+
void putbit1(void)
23+
{
24+
bit_buffer |= bit_mask;
25+
if ((bit_mask >>= 1) == 0) {
26+
if (fputc(bit_buffer, outfile) == EOF) error();
27+
bit_buffer = 0; bit_mask = 128; codecount++;
28+
}
29+
}
30+
31+
void putbit0(void)
32+
{
33+
if ((bit_mask >>= 1) == 0) {
34+
if (fputc(bit_buffer, outfile) == EOF) error();
35+
bit_buffer = 0; bit_mask = 128; codecount++;
36+
}
37+
}
38+
39+
void flush_bit_buffer(void)
40+
{
41+
if (bit_mask != 128) {
42+
if (fputc(bit_buffer, outfile) == EOF) error();
43+
codecount++;
44+
}
45+
}
46+
47+
void output1(int c)
48+
{
49+
int mask;
50+
51+
putbit1();
52+
mask = 256;
53+
while (mask >>= 1) {
54+
if (c & mask) putbit1();
55+
else putbit0();
56+
}
57+
}
58+
59+
void output2(int x, int y)
60+
{
61+
int mask;
62+
63+
putbit0();
64+
mask = N;
65+
while (mask >>= 1) {
66+
if (x & mask) putbit1();
67+
else putbit0();
68+
}
69+
mask = (1 << EJ);
70+
while (mask >>= 1) {
71+
if (y & mask) putbit1();
72+
else putbit0();
73+
}
74+
}
75+
76+
void encode(void)
77+
{
78+
int i, j, f1, x, y, r, s, bufferend, c;
79+
80+
for (i = 0; i < N - F; i++) buffer[i] = ' ';
81+
for (i = N - F; i < N * 2; i++) {
82+
if ((c = fgetc(infile)) == EOF) break;
83+
buffer[i] = c; textcount++;
84+
}
85+
bufferend = i; r = N - F; s = 0;
86+
while (r < bufferend) {
87+
f1 = (F <= bufferend - r) ? F : bufferend - r;
88+
x = 0; y = 1; c = buffer[r];
89+
for (i = r - 1; i >= s; i--)
90+
if (buffer[i] == c) {
91+
for (j = 1; j < f1; j++)
92+
if (buffer[i + j] != buffer[r + j]) break;
93+
if (j > y) {
94+
x = i; y = j;
95+
}
96+
}
97+
if (y <= P) { y = 1; output1(c); }
98+
else output2(x & (N - 1), y - 2);
99+
r += y; s += y;
100+
if (r >= N * 2 - F) {
101+
for (i = 0; i < N; i++) buffer[i] = buffer[i + N];
102+
bufferend -= N; r -= N; s -= N;
103+
while (bufferend < N * 2) {
104+
if ((c = fgetc(infile)) == EOF) break;
105+
buffer[bufferend++] = c; textcount++;
106+
}
107+
}
108+
}
109+
flush_bit_buffer();
110+
printf("text: %ld bytes\n", textcount);
111+
printf("code: %ld bytes (%ld%%)\n",
112+
codecount, (codecount * 100) / textcount);
113+
}
114+
115+
int getbit(int n) /* get n bits */
116+
{
117+
int i, x;
118+
static int buf, mask = 0;
119+
120+
x = 0;
121+
for (i = 0; i < n; i++) {
122+
if (mask == 0) {
123+
if ((buf = fgetc(infile)) == EOF) return EOF;
124+
mask = 128;
125+
}
126+
x <<= 1;
127+
if (buf & mask) x++;
128+
mask >>= 1;
129+
}
130+
return x;
131+
}
132+
133+
void decode(void)
134+
{
135+
int i, j, k, r, c;
136+
137+
for (i = 0; i < N - F; i++) buffer[i] = ' ';
138+
r = N - F;
139+
while ((c = getbit(1)) != EOF) {
140+
if (c) {
141+
if ((c = getbit(8)) == EOF) break;
142+
fputc(c, outfile);
143+
buffer[r++] = c; r &= (N - 1);
144+
} else {
145+
if ((i = getbit(EI)) == EOF) break;
146+
if ((j = getbit(EJ)) == EOF) break;
147+
for (k = 0; k <= j + 1; k++) {
148+
c = buffer[(i + k) & (N - 1)];
149+
fputc(c, outfile);
150+
buffer[r++] = c; r &= (N - 1);
151+
}
152+
}
153+
}
154+
}
155+
156+
int encode_file(char const * in, char const * out)
157+
{
158+
infile = fopen(in, "rb");
159+
if (infile == NULL) return 0;
160+
161+
outfile = fopen(out, "wb");
162+
if (outfile == NULL) return 0;
163+
164+
encode();
165+
166+
fclose(infile);
167+
fclose(outfile);
168+
169+
return 0;
170+
}
171+
172+
int decode_file(char const * in, char const * out)
173+
{
174+
infile = fopen(in, "rb");
175+
if (infile == NULL) return 0;
176+
177+
outfile = fopen(out, "wb");
178+
if (outfile == NULL) return 0;
179+
180+
decode();
181+
182+
fclose(infile);
183+
fclose(outfile);
184+
185+
return 0;
186+
}

Diff for: extras/tools/lzss.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/python3
2+
3+
import sys
4+
import ctypes
5+
6+
LZSS_SO_FILE = "./lzss.so"
7+
8+
if len(sys.argv) != 4:
9+
print ("Usage: lzss.py --[encode|decode] infile outfile")
10+
sys.exit()
11+
12+
lzss_functions = ctypes.CDLL(LZSS_SO_FILE)
13+
14+
mode = sys.argv[1]
15+
ifile = sys.argv[2]
16+
ofile = sys.argv[3]
17+
18+
b_ifile = ifile.encode('utf-8')
19+
b_ofile = ofile.encode('utf-8')
20+
21+
if mode == "--encode":
22+
lzss_functions.encode_file.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
23+
lzss_functions.encode_file(b_ifile, b_ofile)
24+
elif mode == "--decode":
25+
lzss_functions.decode_file.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
26+
lzss_functions.decode_file(b_ifile, b_ofile)
27+
else:
28+
print ("Error, invalid mode parameter, use --encode or --decode")

Diff for: extras/tools/lzss.so

12.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)