Skip to content

Commit 3f464a0

Browse files
authored
Adding capability for decompressing LZSS compressed binaries during update (#548)
1 parent c04b8fd commit 3f464a0

File tree

6 files changed

+2329
-1951
lines changed

6 files changed

+2329
-1951
lines changed

libraries/SNU/extras/NiNaBoot/NiNaBoot.ino

+32-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <WiFiNINA.h>
2020
#include <FlashStorage.h>
2121

22+
#include "lzss.h"
23+
2224
#ifdef ARDUINO_SAMD_MKRVIDOR4000
2325
#include <VidorPeripherals.h>
2426
#endif /* ARDUINO_SAMD_MKRVIDOR4000 */
@@ -33,7 +35,8 @@
3335

3436
#define SKETCH_START (uint32_t*)(SDU_START + SDU_SIZE)
3537

36-
#define UPDATE_FILE "/fs/UPDATE.BIN"
38+
const char * UPDATE_FILE_NAME = "/fs/UPDATE.BIN";
39+
const char * UPDATE_FILE_NAME_LZSS = "/fs/UPDATE.BIN.LZSS";
3740

3841
FlashClass flash;
3942

@@ -66,9 +69,35 @@ int main() {
6669
goto boot;
6770
}
6871

69-
if (WiFiStorage.exists(UPDATE_FILE)) {
72+
/* For UPDATE.BIN.LZSS - LZSS compressed binary files. */
73+
if (WiFiStorage.exists(UPDATE_FILE_NAME_LZSS))
74+
{
75+
WiFiStorageFile update_file = WiFiStorage.open(UPDATE_FILE_NAME_LZSS);
76+
/* Erase the complete flash starting from the SSU forward
77+
* because we've got no possibility of knowing how large
78+
* the decompressed binary will finally be.
79+
*/
80+
flash.erase((void*)SKETCH_START, 0x40000 - (uint32_t)SKETCH_START);
81+
/* Initialize the lzss module with the data which
82+
* it requires.
83+
*/
84+
lzss_init(&update_file, (uint32_t)SKETCH_START);
85+
/* During the process of decoding UPDATE.BIN.LZSS
86+
* is decompressed and stored as UPDATE.BIN.
87+
*/
88+
lzss_decode();
89+
/* Write the data remaining in the write buffer to
90+
* the file.
91+
*/
92+
lzss_flush();
93+
/* Delete UPDATE.BIN.LZSS because this update is complete. */
94+
update_file.close();
95+
update_file.erase();
96+
}
97+
/* For UPDATE.BIN - uncompressed binary files. */
98+
else if (WiFiStorage.exists(UPDATE_FILE_NAME)) {
7099

71-
WiFiStorageFile updateFile = WiFiStorage.open(UPDATE_FILE);
100+
WiFiStorageFile updateFile = WiFiStorage.open(UPDATE_FILE_NAME);
72101
uint32_t updateSize = updateFile.size();
73102
bool updateFlashed = false;
74103

+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 <FlashStorage.h>
11+
12+
/**************************************************************************************
13+
DEFINE
14+
**************************************************************************************/
15+
16+
#define EI 11 /* typically 10..13 */
17+
#define EJ 4 /* typically 4..5 */
18+
#define P 1 /* If match length <= P then output one character */
19+
#define N (1 << EI) /* buffer size */
20+
#define F ((1 << EJ) + 1) /* lookahead buffer size */
21+
22+
#define LZSS_EOF (-1)
23+
24+
#define FPUTC_BUF_SIZE (64)
25+
#define FGETC_BUF_SIZE (64)
26+
27+
/**************************************************************************************
28+
GLOBAL VARIABLES
29+
**************************************************************************************/
30+
31+
extern FlashClass flash;
32+
extern const char * UPDATE_FILE_NAME_LZSS;
33+
34+
static uint32_t SKETCH_START = 0;
35+
static uint32_t LZSS_FILE_SIZE = 0;
36+
static WiFiStorageFile * update_file = 0;
37+
38+
int bit_buffer = 0, bit_mask = 128;
39+
unsigned char buffer[N * 2];
40+
41+
static char write_buf[FPUTC_BUF_SIZE];
42+
static size_t write_buf_num_bytes = 0;
43+
static size_t bytes_written_fputc = 0;
44+
static size_t bytes_written_flash = 0;
45+
static uint32_t flash_addr = 0;
46+
47+
/**************************************************************************************
48+
PUBLIC FUNCTIONS
49+
**************************************************************************************/
50+
51+
void lzss_init(WiFiStorageFile * update_file_ptr, uint32_t const sketch_start)
52+
{
53+
SKETCH_START = sketch_start;
54+
flash_addr = sketch_start;
55+
update_file = update_file_ptr;
56+
LZSS_FILE_SIZE = update_file->size();
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+
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 += update_file->read(read_buf, FGETC_BUF_SIZE);
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/SNU/extras/NiNaBoot/lzss.h

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

0 commit comments

Comments
 (0)