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 char buffer[N * 2];
41
42static char write_buf[FPUTC_BUF_SIZE];
43static size_t write_buf_num_bytes = 0;
44static size_t bytes_written_fputc = 0;
45static size_t bytes_written_flash = 0;
46static uint32_t flash_addr = 0;
47
48/**************************************************************************************
49   PUBLIC FUNCTIONS
50 **************************************************************************************/
51
52void 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
59void lzss_flush()
60{
61  bytes_written_fputc += write_buf_num_bytes;
62
63  /* Only write to the flash once we've surpassed
64   * the SBU 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
79void 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
96int 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 SBUBoot: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
134void 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
143void putbit0(void)
144{
145    if ((bit_mask >>= 1) == 0) {
146        lzss_fputc(bit_buffer);
147        bit_buffer = 0;  bit_mask = 128;
148    }
149}
150
151void 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
163void 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
180int 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
198void 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