13f464a0cSAlexander Entinger/**************************************************************************************
23f464a0cSAlexander Entinger   INCLUDE
33f464a0cSAlexander Entinger **************************************************************************************/
43f464a0cSAlexander Entinger
53f464a0cSAlexander Entinger#include "lzss.h"
63f464a0cSAlexander Entinger
73f464a0cSAlexander Entinger#include <stdlib.h>
83f464a0cSAlexander Entinger#include <stdint.h>
93f464a0cSAlexander Entinger
103f464a0cSAlexander Entinger#include <FlashStorage.h>
113f464a0cSAlexander Entinger
123f464a0cSAlexander Entinger/**************************************************************************************
133f464a0cSAlexander Entinger   DEFINE
143f464a0cSAlexander Entinger **************************************************************************************/
153f464a0cSAlexander Entinger
163f464a0cSAlexander Entinger#define EI 11             /* typically 10..13 */
173f464a0cSAlexander Entinger#define EJ  4             /* typically 4..5 */
183f464a0cSAlexander Entinger#define P   1             /* If match length <= P then output one character */
193f464a0cSAlexander Entinger#define N (1 << EI)       /* buffer size */
203f464a0cSAlexander Entinger#define F ((1 << EJ) + 1) /* lookahead buffer size */
213f464a0cSAlexander Entinger
223f464a0cSAlexander Entinger#define LZSS_EOF       (-1)
233f464a0cSAlexander Entinger
243f464a0cSAlexander Entinger#define FPUTC_BUF_SIZE (64)
253f464a0cSAlexander Entinger#define FGETC_BUF_SIZE (64)
263f464a0cSAlexander Entinger
273f464a0cSAlexander Entinger/**************************************************************************************
283f464a0cSAlexander Entinger   GLOBAL VARIABLES
293f464a0cSAlexander Entinger **************************************************************************************/
303f464a0cSAlexander Entinger
313f464a0cSAlexander Entingerextern FlashClass flash;
323f464a0cSAlexander Entingerextern const char * UPDATE_FILE_NAME_LZSS;
333f464a0cSAlexander Entinger
343f464a0cSAlexander Entingerstatic uint32_t SKETCH_START = 0;
353f464a0cSAlexander Entingerstatic uint32_t LZSS_FILE_SIZE = 0;
363f464a0cSAlexander Entingerstatic WiFiStorageFile * update_file = 0;
373f464a0cSAlexander Entinger
383f464a0cSAlexander Entingerint bit_buffer = 0, bit_mask = 128;
393f464a0cSAlexander Entingerunsigned char buffer[N * 2];
403f464a0cSAlexander Entinger
413f464a0cSAlexander Entingerstatic char write_buf[FPUTC_BUF_SIZE];
423f464a0cSAlexander Entingerstatic size_t write_buf_num_bytes = 0;
433f464a0cSAlexander Entingerstatic size_t bytes_written_fputc = 0;
443f464a0cSAlexander Entingerstatic size_t bytes_written_flash = 0;
453f464a0cSAlexander Entingerstatic uint32_t flash_addr = 0;
463f464a0cSAlexander Entinger
473f464a0cSAlexander Entinger/**************************************************************************************
483f464a0cSAlexander Entinger   PUBLIC FUNCTIONS
493f464a0cSAlexander Entinger **************************************************************************************/
503f464a0cSAlexander Entinger
512e29c3c6SAlexander Entingervoid lzss_init(WiFiStorageFile * update_file_ptr, uint32_t const sketch_start, uint32_t const lzss_file_size)
523f464a0cSAlexander Entinger{
533f464a0cSAlexander Entinger  SKETCH_START = sketch_start;
543f464a0cSAlexander Entinger  flash_addr = sketch_start;
553f464a0cSAlexander Entinger  update_file = update_file_ptr;
562e29c3c6SAlexander Entinger  LZSS_FILE_SIZE = lzss_file_size;
573f464a0cSAlexander Entinger}
583f464a0cSAlexander Entinger
593f464a0cSAlexander Entingervoid lzss_flush()
603f464a0cSAlexander Entinger{
613f464a0cSAlexander Entinger  bytes_written_fputc += write_buf_num_bytes;
623f464a0cSAlexander Entinger
633f464a0cSAlexander Entinger  /* Only write to the flash once we've surpassed
643f464a0cSAlexander Entinger   * the SSU in the update binary.
653f464a0cSAlexander Entinger   */
663f464a0cSAlexander Entinger  if (bytes_written_fputc > (SKETCH_START - 0x2000))
673f464a0cSAlexander Entinger  {
683f464a0cSAlexander Entinger    flash.write((void*)flash_addr, write_buf, write_buf_num_bytes);
693f464a0cSAlexander Entinger    flash_addr += write_buf_num_bytes;
703f464a0cSAlexander Entinger  }
713f464a0cSAlexander Entinger
723f464a0cSAlexander Entinger  write_buf_num_bytes = 0;
733f464a0cSAlexander Entinger}
743f464a0cSAlexander Entinger
753f464a0cSAlexander Entinger/**************************************************************************************
763f464a0cSAlexander Entinger   PRIVATE FUNCTIONS
773f464a0cSAlexander Entinger **************************************************************************************/
783f464a0cSAlexander Entinger
793f464a0cSAlexander Entingervoid lzss_fputc(int const c)
803f464a0cSAlexander Entinger{
813f464a0cSAlexander Entinger  /* Buffer the decompressed data into a buffer so
823f464a0cSAlexander Entinger   * we can perform block writes and don't need to
833f464a0cSAlexander Entinger   * write every byte singly on the flash (which
843f464a0cSAlexander Entinger   * wouldn't be possible anyway).
853f464a0cSAlexander Entinger   */
863f464a0cSAlexander Entinger  write_buf[write_buf_num_bytes] = static_cast<char>(c);
873f464a0cSAlexander Entinger  write_buf_num_bytes++;
883f464a0cSAlexander Entinger
893f464a0cSAlexander Entinger  /* The write buffer is full of decompressed
903f464a0cSAlexander Entinger   * data, write it to the flash now.
913f464a0cSAlexander Entinger   */
923f464a0cSAlexander Entinger  if (write_buf_num_bytes == FPUTC_BUF_SIZE)
933f464a0cSAlexander Entinger    lzss_flush();
943f464a0cSAlexander Entinger}
953f464a0cSAlexander Entinger
963f464a0cSAlexander Entingerint lzss_fgetc()
973f464a0cSAlexander Entinger{
983f464a0cSAlexander Entinger  static uint8_t read_buf[FGETC_BUF_SIZE];
993f464a0cSAlexander Entinger  static size_t read_buf_pos = FGETC_BUF_SIZE;
1003f464a0cSAlexander Entinger  static size_t bytes_read_fgetc = 0;
1013f464a0cSAlexander Entinger  static size_t bytes_read_from_modem = 0;
1023f464a0cSAlexander Entinger
1033f464a0cSAlexander Entinger  /* lzss_file_size is set within SSUBoot:main
1043f464a0cSAlexander Entinger   * and contains the size of the LZSS file. Once
1053f464a0cSAlexander Entinger   * all those bytes have been read its time to return
1063f464a0cSAlexander Entinger   * LZSS_EOF in order to signal that the end of
1073f464a0cSAlexander Entinger   * the file has been reached.
1083f464a0cSAlexander Entinger   */
1093f464a0cSAlexander Entinger  if (bytes_read_fgetc == LZSS_FILE_SIZE)
1103f464a0cSAlexander Entinger    return LZSS_EOF;
1113f464a0cSAlexander Entinger
1123f464a0cSAlexander Entinger  /* If there is no data left to be read from the read buffer
1133f464a0cSAlexander Entinger   * than read a new block and store it into the read buffer.
1143f464a0cSAlexander Entinger   */
1153f464a0cSAlexander Entinger  if (read_buf_pos == FGETC_BUF_SIZE)
1163f464a0cSAlexander Entinger  {
1173f464a0cSAlexander Entinger    /* Read the next block from the flash memory. */
1183f464a0cSAlexander Entinger    bytes_read_from_modem += update_file->read(read_buf, FGETC_BUF_SIZE);
1193f464a0cSAlexander Entinger    /* Reset the read buffer position. */
1203f464a0cSAlexander Entinger    read_buf_pos = 0;
1213f464a0cSAlexander Entinger  }
1223f464a0cSAlexander Entinger
1233f464a0cSAlexander Entinger  uint8_t const c = read_buf[read_buf_pos];
1243f464a0cSAlexander Entinger  read_buf_pos++;
1253f464a0cSAlexander Entinger  bytes_read_fgetc++;
1263f464a0cSAlexander Entinger
1273f464a0cSAlexander Entinger  return c;
1283f464a0cSAlexander Entinger}
1293f464a0cSAlexander Entinger
1303f464a0cSAlexander Entinger/**************************************************************************************
1313f464a0cSAlexander Entinger   LZSS FUNCTIONS
1323f464a0cSAlexander Entinger **************************************************************************************/
1333f464a0cSAlexander Entinger
1343f464a0cSAlexander Entingervoid putbit1(void)
1353f464a0cSAlexander Entinger{
1363f464a0cSAlexander Entinger    bit_buffer |= bit_mask;
1373f464a0cSAlexander Entinger    if ((bit_mask >>= 1) == 0) {
1383f464a0cSAlexander Entinger        lzss_fputc(bit_buffer);
1393f464a0cSAlexander Entinger        bit_buffer = 0;  bit_mask = 128;
1403f464a0cSAlexander Entinger    }
1413f464a0cSAlexander Entinger}
1423f464a0cSAlexander Entinger
1433f464a0cSAlexander Entingervoid putbit0(void)
1443f464a0cSAlexander Entinger{
1453f464a0cSAlexander Entinger    if ((bit_mask >>= 1) == 0) {
1463f464a0cSAlexander Entinger        lzss_fputc(bit_buffer);
1473f464a0cSAlexander Entinger        bit_buffer = 0;  bit_mask = 128;
1483f464a0cSAlexander Entinger    }
1493f464a0cSAlexander Entinger}
1503f464a0cSAlexander Entinger
1513f464a0cSAlexander Entingervoid output1(int c)
1523f464a0cSAlexander Entinger{
1533f464a0cSAlexander Entinger    int mask;
1543f464a0cSAlexander Entinger
1553f464a0cSAlexander Entinger    putbit1();
1563f464a0cSAlexander Entinger    mask = 256;
1573f464a0cSAlexander Entinger    while (mask >>= 1) {
1583f464a0cSAlexander Entinger        if (c & mask) putbit1();
1593f464a0cSAlexander Entinger        else putbit0();
1603f464a0cSAlexander Entinger    }
1613f464a0cSAlexander Entinger}
1623f464a0cSAlexander Entinger
1633f464a0cSAlexander Entingervoid output2(int x, int y)
1643f464a0cSAlexander Entinger{
1653f464a0cSAlexander Entinger    int mask;
1663f464a0cSAlexander Entinger
1673f464a0cSAlexander Entinger    putbit0();
1683f464a0cSAlexander Entinger    mask = N;
1693f464a0cSAlexander Entinger    while (mask >>= 1) {
1703f464a0cSAlexander Entinger        if (x & mask) putbit1();
1713f464a0cSAlexander Entinger        else putbit0();
1723f464a0cSAlexander Entinger    }
1733f464a0cSAlexander Entinger    mask = (1 << EJ);
1743f464a0cSAlexander Entinger    while (mask >>= 1) {
1753f464a0cSAlexander Entinger        if (y & mask) putbit1();
1763f464a0cSAlexander Entinger        else putbit0();
1773f464a0cSAlexander Entinger    }
1783f464a0cSAlexander Entinger}
1793f464a0cSAlexander Entinger
1803f464a0cSAlexander Entingerint getbit(int n) /* get n bits */
1813f464a0cSAlexander Entinger{
1823f464a0cSAlexander Entinger    int i, x;
1833f464a0cSAlexander Entinger    static int buf, mask = 0;
1843f464a0cSAlexander Entinger
1853f464a0cSAlexander Entinger    x = 0;
1863f464a0cSAlexander Entinger    for (i = 0; i < n; i++) {
1873f464a0cSAlexander Entinger        if (mask == 0) {
1883f464a0cSAlexander Entinger            if ((buf = lzss_fgetc()) == LZSS_EOF) return LZSS_EOF;
1893f464a0cSAlexander Entinger            mask = 128;
1903f464a0cSAlexander Entinger        }
1913f464a0cSAlexander Entinger        x <<= 1;
1923f464a0cSAlexander Entinger        if (buf & mask) x++;
1933f464a0cSAlexander Entinger        mask >>= 1;
1943f464a0cSAlexander Entinger    }
1953f464a0cSAlexander Entinger    return x;
1963f464a0cSAlexander Entinger}
1973f464a0cSAlexander Entinger
1983f464a0cSAlexander Entingervoid lzss_decode(void)
1993f464a0cSAlexander Entinger{
2003f464a0cSAlexander Entinger    int i, j, k, r, c;
2013f464a0cSAlexander Entinger
2023f464a0cSAlexander Entinger    for (i = 0; i < N - F; i++) buffer[i] = ' ';
2033f464a0cSAlexander Entinger    r = N - F;
2043f464a0cSAlexander Entinger    while ((c = getbit(1)) != LZSS_EOF) {
2053f464a0cSAlexander Entinger        if (c) {
2063f464a0cSAlexander Entinger            if ((c = getbit(8)) == LZSS_EOF) break;
2073f464a0cSAlexander Entinger            lzss_fputc(c);
2083f464a0cSAlexander Entinger            buffer[r++] = c;  r &= (N - 1);
2093f464a0cSAlexander Entinger        } else {
2103f464a0cSAlexander Entinger            if ((i = getbit(EI)) == LZSS_EOF) break;
2113f464a0cSAlexander Entinger            if ((j = getbit(EJ)) == LZSS_EOF) break;
2123f464a0cSAlexander Entinger            for (k = 0; k <= j + 1; k++) {
2133f464a0cSAlexander Entinger                c = buffer[(i + k) & (N - 1)];
2143f464a0cSAlexander Entinger                lzss_fputc(c);
2153f464a0cSAlexander Entinger                buffer[r++] = c;  r &= (N - 1);
2163f464a0cSAlexander Entinger            }
2173f464a0cSAlexander Entinger        }
2183f464a0cSAlexander Entinger    }
2193f464a0cSAlexander Entinger}
220