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