1/*
2  Copyright (c) 2020 Arduino LLC.  All right reserved.
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  See the GNU Lesser General Public License for more details.
13
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18
19#include <FlashStorage.h>
20#include <MKRNB.h>
21
22#include "lzss.h"
23
24#define SBU_START    0x2000
25#define SBU_SIZE     0x8000
26
27#define SKETCH_START (uint32_t*)(SBU_START + SBU_SIZE)
28
29       const char * UPDATE_FILE_NAME      = "UPDATE.BIN";
30       const char * UPDATE_FILE_NAME_LZSS = "UPDATE.BIN.LZSS";
31static const char * CHECK_FILE_NAME       = "UPDATE.OK";
32
33FlashClass mcu_flash;
34
35NBFileUtils fileUtils(true);
36
37extern "C" void __libc_init_array(void);
38
39int main()
40{
41  init();
42
43  __libc_init_array();
44
45  delay(1);
46
47  constexpr size_t blockSize = 512;
48  fileUtils.begin();
49
50  bool update_success = false;
51
52  // Try to update only if update file
53  // has been download successfully.
54
55  if (fileUtils.existFile(CHECK_FILE_NAME)) 
56  {
57    /*This is for LZSS compressed binaries. */
58    if (fileUtils.existFile(UPDATE_FILE_NAME_LZSS)) 
59    {
60      /* Erase the complete flash starting from the SSU forward
61       * because we've got no possibility of knowing how large
62       * the decompressed binary will finally be.
63       */
64      mcu_flash.erase((void*)SKETCH_START, 0x40000 - (uint32_t)SKETCH_START);
65      /* Initialize the lzss module with the data which
66       * it requires.
67       */
68      lzss_init((uint32_t)SKETCH_START);
69      /* During the process of decoding UPDATE.BIN.LZSS
70       * is decompressed and stored as UPDATE.BIN.
71       */
72      lzss_decode();
73      /* Write the data remaining in the write buffer to
74       * the file.
75       */
76      lzss_flush();
77      /* Signal a successul update. */
78      update_success = true;
79    }
80    /* This is for uncompressed binaries. */
81    else if (fileUtils.listFile(UPDATE_FILE_NAME) > 0)
82    {
83      uint32_t updateSize = fileUtils.listFile(UPDATE_FILE_NAME);
84      uint32_t tot_bytes = 0;
85      uint32_t read_bytes = 0;
86
87      if (updateSize > SBU_SIZE) {
88        updateSize = updateSize - SBU_SIZE;
89        size_t cycles = (updateSize / blockSize) + 1;
90        size_t spare_bytes = (updateSize % blockSize);
91
92        /* Erase the MCU flash */
93        uint32_t flash_address = (uint32_t)SKETCH_START;
94        mcu_flash.erase((void*)flash_address, updateSize);
95
96        for (auto i = 0; i < cycles; i++) {
97          uint8_t block[blockSize] { 0 };
98          digitalWrite(LED_BUILTIN, LOW);
99          read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SBU_SIZE, blockSize, block);
100          digitalWrite(LED_BUILTIN, HIGH);
101          mcu_flash.write((void*)flash_address, block, read_bytes);
102          flash_address += read_bytes;
103          tot_bytes += read_bytes;
104        }
105
106        if (spare_bytes){
107          uint8_t block[spare_bytes] { 0 };
108          digitalWrite(LED_BUILTIN, LOW);
109          read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, tot_bytes + SBU_SIZE, spare_bytes, block);
110          digitalWrite(LED_BUILTIN, HIGH);
111          mcu_flash.write((void*)flash_address, block, read_bytes);
112          flash_address += read_bytes;
113        }
114        update_success = true;
115      }
116    }
117    if (update_success) {
118      fileUtils.deleteFile(UPDATE_FILE_NAME);
119      fileUtils.deleteFile(UPDATE_FILE_NAME_LZSS);
120      fileUtils.deleteFile(CHECK_FILE_NAME);
121    }
122  }
123
124boot:
125  /* Jump to the sketch */
126  __set_MSP(*SKETCH_START);
127
128  /* Reset vector table address */
129  SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);
130
131  /* Address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script) */
132  uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
133  /* Jump to reset handler */
134  asm("bx %0"::"r"(resetHandlerAddress));
135}
136