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/**************************************************************************************
20   INCLUDE
21 **************************************************************************************/
22
23#include <FlashStorage.h>
24#include <MKRGSM.h>
25
26#include "lzss.h"
27
28/**************************************************************************************
29   DEFINE
30 **************************************************************************************/
31
32#define SSU_START    0x2000
33#define SSU_SIZE     0x8000
34
35#define SKETCH_START (uint32_t*)(SSU_START + SSU_SIZE)
36
37/**************************************************************************************
38   GLOBAL CONSTANTS
39 **************************************************************************************/
40
41       const char * UPDATE_FILE_NAME      = "UPDATE.BIN";
42       const char * UPDATE_FILE_NAME_LZSS = "UPDATE.BIN.LZSS";
43static const char * CHECK_FILE_NAME       = "UPDATE.OK";
44
45/**************************************************************************************
46   GLOBAL VARIABLES
47 **************************************************************************************/
48
49FlashClass mcu_flash;
50GSMFileUtils fileUtils;
51
52/**************************************************************************************
53   FUNCTION DECLARATION
54 **************************************************************************************/
55
56extern "C" void __libc_init_array(void);
57
58/**************************************************************************************
59   MAIN
60 **************************************************************************************/
61
62int main()
63{
64  init();
65
66  __libc_init_array();
67
68  delay(1);
69
70  constexpr size_t blockSize = 512;
71
72  fileUtils.begin();
73
74  bool update_success = false;
75
76  // Try to update only if update file
77  // has been download successfully.
78  if (fileUtils.listFile(CHECK_FILE_NAME) > 0)
79  {
80    /* This is for LZSS compressed binaries. */
81    if (fileUtils.listFile(UPDATE_FILE_NAME_LZSS) > 0)
82    {
83      /* Erase the complete flash starting from the SSU forward
84       * because we've got no possibility of knowing how large
85       * the decompressed binary will finally be.
86       */
87      mcu_flash.erase((void*)SKETCH_START, 0x40000 - (uint32_t)SKETCH_START);
88      /* Initialize the lzss module with the data which
89       * it requires.
90       */
91      lzss_init((uint32_t)SKETCH_START);
92      /* During the process of decoding UPDATE.BIN.LZSS
93       * is decompressed and stored as UPDATE.BIN.
94       */
95      lzss_decode();
96      /* Write the data remaining in the write buffer to
97       * the file.
98       */
99      lzss_flush();
100      /* Signal a successul update. */
101      update_success = true;
102    }
103    /* This is for uncompressed binaries. */
104    else if (fileUtils.listFile(UPDATE_FILE_NAME) > 0)
105    {
106      uint32_t size = fileUtils.listFile(UPDATE_FILE_NAME);
107      size_t cycles = (size / blockSize) + 1;
108
109      if (size > SSU_SIZE) {
110        size -= SSU_SIZE;
111
112        /* Erase the MCU flash */
113        uint32_t flash_address = (uint32_t)SKETCH_START;
114        mcu_flash.erase((void*)flash_address, size);
115
116        for (auto i = 0; i < cycles; i++) {
117          uint8_t block[blockSize] { 0 };
118          digitalWrite(LED_BUILTIN, LOW);
119          uint32_t read = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SSU_SIZE, blockSize, block);
120          digitalWrite(LED_BUILTIN, HIGH);
121          mcu_flash.write((void*)flash_address, block, read);
122          flash_address += read;
123        }
124        update_success = true;
125      }
126    }
127    /* Clean up in case of success */
128    if (update_success) {
129      fileUtils.deleteFile(UPDATE_FILE_NAME);
130      fileUtils.deleteFile(UPDATE_FILE_NAME_LZSS);
131      fileUtils.deleteFile(CHECK_FILE_NAME);
132    }
133  }
134  /* Jump to the sketch */
135  __set_MSP(*SKETCH_START);
136
137  /* Reset vector table address */
138  SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);
139
140  /* Address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script) */
141  uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
142  /* Jump to reset handler */
143  asm("bx %0"::"r"(resetHandlerAddress));
144}
145