Skip to content

Commit 6bff0b2

Browse files
authored
Merge pull request #544 from arduino/ssu-lzss
Add feature for decompressing LZSS compressed binary files by second stage bootloader SSU
2 parents 761e1e6 + 807f450 commit 6bff0b2

File tree

4 files changed

+2537
-2205
lines changed

4 files changed

+2537
-2205
lines changed

libraries/SSU/extras/SSUBoot/SSUBoot.ino

+54-24
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <FlashStorage.h>
2424
#include <MKRGSM.h>
2525

26+
#include "lzss.h"
2627

2728
/**************************************************************************************
2829
DEFINE
@@ -37,17 +38,16 @@
3738
GLOBAL CONSTANTS
3839
**************************************************************************************/
3940

40-
static constexpr char UPDATE_FILE_NAME[] = "UPDATE.BIN";
41-
static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";
42-
41+
const char * UPDATE_FILE_NAME = "UPDATE.BIN";
42+
const char * UPDATE_FILE_NAME_LZSS = "UPDATE.BIN.LZSS";
43+
static const char * CHECK_FILE_NAME = "UPDATE.OK";
4344

4445
/**************************************************************************************
4546
GLOBAL VARIABLES
4647
**************************************************************************************/
4748

4849
FlashClass mcu_flash;
49-
50-
GSMFileUtils fileUtils;
50+
GSMFileUtils fileUtils;
5151

5252
/**************************************************************************************
5353
FUNCTION DECLARATION
@@ -75,29 +75,59 @@ int main()
7575

7676
// Try to update only if update file
7777
// has been download successfully.
78-
if (fileUtils.listFile(CHECK_FILE_NAME) == 1) {
79-
uint32_t size = fileUtils.listFile(UPDATE_FILE_NAME);
80-
size_t cycles = (size / blockSize) + 1;
81-
82-
if (size > SSU_SIZE) {
83-
size -= SSU_SIZE;
84-
85-
/* Erase the MCU flash */
86-
uint32_t flash_address = (uint32_t)SKETCH_START;
87-
mcu_flash.erase((void*)flash_address, size);
88-
89-
for (auto i = 0; i < cycles; i++) {
90-
uint8_t block[blockSize] { 0 };
91-
digitalWrite(LED_BUILTIN, LOW);
92-
uint32_t read = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SSU_SIZE, blockSize, block);
93-
digitalWrite(LED_BUILTIN, HIGH);
94-
mcu_flash.write((void*)flash_address, block, read);
95-
flash_address += read;
96-
}
78+
if (fileUtils.listFile(CHECK_FILE_NAME) > 0)
79+
{
80+
/* This is for LZSS compressed binaries. */
81+
if (fileUtils.listFile(UPDATE_FILE_NAME_LZSS) > 0)
82+
{
83+
/* Erase the complete flash starting from the SSU forward
84+
* because we've got no possibility of knowing how large
85+
* the decompressed binary will finally be.
86+
*/
87+
mcu_flash.erase((void*)SKETCH_START, 0x40000 - (uint32_t)SKETCH_START);
88+
/* Initialize the lzss module with the data which
89+
* it requires.
90+
*/
91+
lzss_init((uint32_t)SKETCH_START);
92+
/* During the process of decoding UPDATE.BIN.LZSS
93+
* is decompressed and stored as UPDATE.BIN.
94+
*/
95+
lzss_decode();
96+
/* Write the data remaining in the write buffer to
97+
* the file.
98+
*/
99+
lzss_flush();
100+
/* Signal a successul update. */
97101
update_success = true;
98102
}
103+
/* This is for uncompressed binaries. */
104+
else if (fileUtils.listFile(UPDATE_FILE_NAME) > 0)
105+
{
106+
uint32_t size = fileUtils.listFile(UPDATE_FILE_NAME);
107+
size_t cycles = (size / blockSize) + 1;
108+
109+
if (size > SSU_SIZE) {
110+
size -= SSU_SIZE;
111+
112+
/* Erase the MCU flash */
113+
uint32_t flash_address = (uint32_t)SKETCH_START;
114+
mcu_flash.erase((void*)flash_address, size);
115+
116+
for (auto i = 0; i < cycles; i++) {
117+
uint8_t block[blockSize] { 0 };
118+
digitalWrite(LED_BUILTIN, LOW);
119+
uint32_t read = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SSU_SIZE, blockSize, block);
120+
digitalWrite(LED_BUILTIN, HIGH);
121+
mcu_flash.write((void*)flash_address, block, read);
122+
flash_address += read;
123+
}
124+
update_success = true;
125+
}
126+
}
127+
/* Clean up in case of success */
99128
if (update_success) {
100129
fileUtils.deleteFile(UPDATE_FILE_NAME);
130+
fileUtils.deleteFile(UPDATE_FILE_NAME_LZSS);
101131
fileUtils.deleteFile(CHECK_FILE_NAME);
102132
}
103133
}

libraries/SSU/extras/SSUBoot/lzss.cpp

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/**************************************************************************************
2+
INCLUDE
3+
**************************************************************************************/
4+
5+
#include "lzss.h"
6+
7+
#include <stdlib.h>
8+
#include <stdint.h>
9+
10+
#include <MKRGSM.h>
11+
#include <FlashStorage.h>
12+
13+
/**************************************************************************************
14+
DEFINE
15+
**************************************************************************************/
16+
17+
#define EI 11 /* typically 10..13 */
18+
#define EJ 4 /* typically 4..5 */
19+
#define P 1 /* If match length <= P then output one character */
20+
#define N (1 << EI) /* buffer size */
21+
#define F ((1 << EJ) + 1) /* lookahead buffer size */
22+
23+
#define LZSS_EOF (-1)
24+
25+
#define FPUTC_BUF_SIZE (512)
26+
#define FGETC_BUF_SIZE (512)
27+
28+
/**************************************************************************************
29+
GLOBAL VARIABLES
30+
**************************************************************************************/
31+
32+
extern GSMFileUtils fileUtils;
33+
extern FlashClass mcu_flash;
34+
extern const char * UPDATE_FILE_NAME_LZSS;
35+
36+
static uint32_t SKETCH_START = 0;
37+
static uint32_t LZSS_FILE_SIZE = 0;
38+
39+
int bit_buffer = 0, bit_mask = 128;
40+
unsigned char buffer[N * 2];
41+
42+
static char write_buf[FPUTC_BUF_SIZE];
43+
static size_t write_buf_num_bytes = 0;
44+
static size_t bytes_written_fputc = 0;
45+
static size_t bytes_written_flash = 0;
46+
static uint32_t flash_addr = 0;
47+
48+
/**************************************************************************************
49+
PUBLIC FUNCTIONS
50+
**************************************************************************************/
51+
52+
void lzss_init(uint32_t const sketch_start)
53+
{
54+
SKETCH_START = sketch_start;
55+
flash_addr = sketch_start;
56+
LZSS_FILE_SIZE = fileUtils.listFile(UPDATE_FILE_NAME_LZSS);
57+
}
58+
59+
void lzss_flush()
60+
{
61+
bytes_written_fputc += write_buf_num_bytes;
62+
63+
/* Only write to the flash once we've surpassed
64+
* the SSU in the update binary.
65+
*/
66+
if (bytes_written_fputc > (SKETCH_START - 0x2000))
67+
{
68+
mcu_flash.write((void*)flash_addr, write_buf, write_buf_num_bytes);
69+
flash_addr += write_buf_num_bytes;
70+
}
71+
72+
write_buf_num_bytes = 0;
73+
}
74+
75+
/**************************************************************************************
76+
PRIVATE FUNCTIONS
77+
**************************************************************************************/
78+
79+
void lzss_fputc(int const c)
80+
{
81+
/* Buffer the decompressed data into a buffer so
82+
* we can perform block writes and don't need to
83+
* write every byte singly on the flash (which
84+
* wouldn't be possible anyway).
85+
*/
86+
write_buf[write_buf_num_bytes] = static_cast<char>(c);
87+
write_buf_num_bytes++;
88+
89+
/* The write buffer is full of decompressed
90+
* data, write it to the flash now.
91+
*/
92+
if (write_buf_num_bytes == FPUTC_BUF_SIZE)
93+
lzss_flush();
94+
}
95+
96+
int lzss_fgetc()
97+
{
98+
static uint8_t read_buf[FGETC_BUF_SIZE];
99+
static size_t read_buf_pos = FGETC_BUF_SIZE;
100+
static size_t bytes_read_fgetc = 0;
101+
static size_t bytes_read_from_modem = 0;
102+
103+
/* lzss_file_size is set within SSUBoot:main
104+
* and contains the size of the LZSS file. Once
105+
* all those bytes have been read its time to return
106+
* LZSS_EOF in order to signal that the end of
107+
* the file has been reached.
108+
*/
109+
if (bytes_read_fgetc == LZSS_FILE_SIZE)
110+
return LZSS_EOF;
111+
112+
/* If there is no data left to be read from the read buffer
113+
* than read a new block and store it into the read buffer.
114+
*/
115+
if (read_buf_pos == FGETC_BUF_SIZE)
116+
{
117+
/* Read the next block from the flash memory. */
118+
bytes_read_from_modem += fileUtils.readBlock(UPDATE_FILE_NAME_LZSS, bytes_read_from_modem, FGETC_BUF_SIZE, read_buf);
119+
/* Reset the read buffer position. */
120+
read_buf_pos = 0;
121+
}
122+
123+
uint8_t const c = read_buf[read_buf_pos];
124+
read_buf_pos++;
125+
bytes_read_fgetc++;
126+
127+
return c;
128+
}
129+
130+
/**************************************************************************************
131+
LZSS FUNCTIONS
132+
**************************************************************************************/
133+
134+
void putbit1(void)
135+
{
136+
bit_buffer |= bit_mask;
137+
if ((bit_mask >>= 1) == 0) {
138+
lzss_fputc(bit_buffer);
139+
bit_buffer = 0; bit_mask = 128;
140+
}
141+
}
142+
143+
void putbit0(void)
144+
{
145+
if ((bit_mask >>= 1) == 0) {
146+
lzss_fputc(bit_buffer);
147+
bit_buffer = 0; bit_mask = 128;
148+
}
149+
}
150+
151+
void output1(int c)
152+
{
153+
int mask;
154+
155+
putbit1();
156+
mask = 256;
157+
while (mask >>= 1) {
158+
if (c & mask) putbit1();
159+
else putbit0();
160+
}
161+
}
162+
163+
void output2(int x, int y)
164+
{
165+
int mask;
166+
167+
putbit0();
168+
mask = N;
169+
while (mask >>= 1) {
170+
if (x & mask) putbit1();
171+
else putbit0();
172+
}
173+
mask = (1 << EJ);
174+
while (mask >>= 1) {
175+
if (y & mask) putbit1();
176+
else putbit0();
177+
}
178+
}
179+
180+
int getbit(int n) /* get n bits */
181+
{
182+
int i, x;
183+
static int buf, mask = 0;
184+
185+
x = 0;
186+
for (i = 0; i < n; i++) {
187+
if (mask == 0) {
188+
if ((buf = lzss_fgetc()) == LZSS_EOF) return LZSS_EOF;
189+
mask = 128;
190+
}
191+
x <<= 1;
192+
if (buf & mask) x++;
193+
mask >>= 1;
194+
}
195+
return x;
196+
}
197+
198+
void lzss_decode(void)
199+
{
200+
int i, j, k, r, c;
201+
202+
for (i = 0; i < N - F; i++) buffer[i] = ' ';
203+
r = N - F;
204+
while ((c = getbit(1)) != LZSS_EOF) {
205+
if (c) {
206+
if ((c = getbit(8)) == LZSS_EOF) break;
207+
lzss_fputc(c);
208+
buffer[r++] = c; r &= (N - 1);
209+
} else {
210+
if ((i = getbit(EI)) == LZSS_EOF) break;
211+
if ((j = getbit(EJ)) == LZSS_EOF) break;
212+
for (k = 0; k <= j + 1; k++) {
213+
c = buffer[(i + k) & (N - 1)];
214+
lzss_fputc(c);
215+
buffer[r++] = c; r &= (N - 1);
216+
}
217+
}
218+
}
219+
}

libraries/SSU/extras/SSUBoot/lzss.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef SSU_LZSS_H_
2+
#define SSU_LZSS_H_
3+
4+
/**************************************************************************************
5+
INCLUDE
6+
**************************************************************************************/
7+
8+
#include <stdint.h>
9+
10+
/**************************************************************************************
11+
FUNCTION DEFINITION
12+
**************************************************************************************/
13+
14+
void lzss_init(uint32_t const sketch_start);
15+
void lzss_decode();
16+
void lzss_flush();
17+
18+
#endif /* SSU_LZSS_H_ */

0 commit comments

Comments
 (0)