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
lzss_init(uint32_t const sketch_start)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
lzss_flush()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
lzss_fputc(int const c)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
lzss_fgetc()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
putbit1(void)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
putbit0(void)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
output1(int c)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
output2(int x, int y)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
getbit(int n)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
lzss_decode(void)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 }
220