1/*
2  Copyright (c) 2017 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 <WiFiNINA.h>
20#include <FlashStorage.h>
21
22#include "lzss.h"
23
24#ifdef ARDUINO_SAMD_MKRVIDOR4000
25#include <VidorPeripherals.h>
26#endif /* ARDUINO_SAMD_MKRVIDOR4000 */
27
28#ifdef ARDUINO_SAMD_MKRVIDOR4000
29#define NINA_GPIO0  FPGA_NINA_GPIO0
30#define NINA_RESETN FPGA_SPIWIFI_RESET
31#endif /* ARDUINO_SAMD_MKRVIDOR4000 */
32
33#define SDU_START    0x2000
34#define SDU_SIZE     0x4000
35
36#define SKETCH_START (uint32_t*)(SDU_START + SDU_SIZE)
37
38const char * UPDATE_FILE_NAME      = "/fs/UPDATE.BIN";
39const char * UPDATE_FILE_NAME_LZSS = "/fs/UPDATE.BIN.LZSS";
40
41FlashClass flash;
42
43// Initialize C library
44extern "C" void __libc_init_array(void);
45
46int main() {
47  init();
48
49  __libc_init_array();
50
51  delay(1);
52
53#if defined(ARDUINO_SAMD_MKRVIDOR4000)
54  FPGA.begin();
55  /* NINA select SPI mode and enable (by setting RESETN = '1') */
56  FPGA.pinMode     (NINA_GPIO0,  OUTPUT);
57  FPGA.digitalWrite(NINA_GPIO0,  HIGH);
58  FPGA.pinMode     (NINA_RESETN, OUTPUT);
59  FPGA.digitalWrite(NINA_RESETN, HIGH);
60#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
61  /* NINA select SPI mode and enable (by setting RESETN = '1') */
62  pinMode     (NINA_GPIO0,  OUTPUT);
63  digitalWrite(NINA_GPIO0,  HIGH);
64  pinMode     (NINA_RESETN, OUTPUT);
65  digitalWrite(NINA_RESETN, HIGH);
66#endif
67
68  if (WiFi.status() == WL_NO_SHIELD) {
69    goto boot;
70  }
71
72  /* For UPDATE.BIN.LZSS - LZSS compressed binary files. */
73  if (WiFiStorage.exists(UPDATE_FILE_NAME_LZSS))
74  {
75    WiFiStorageFile update_file = WiFiStorage.open(UPDATE_FILE_NAME_LZSS);
76    /* Erase the complete flash starting from the SSU forward
77     * because we've got no possibility of knowing how large
78     * the decompressed binary will finally be.
79     */
80    flash.erase((void*)SKETCH_START, 0x40000 - (uint32_t)SKETCH_START);
81    /* Initialize the lzss module with the data which
82     * it requires.
83     */
84    lzss_init(&update_file, (uint32_t)SKETCH_START);
85    /* During the process of decoding UPDATE.BIN.LZSS
86     * is decompressed and stored as UPDATE.BIN.
87     */
88    lzss_decode();
89    /* Write the data remaining in the write buffer to
90     * the file.
91     */
92    lzss_flush();
93    /* Delete UPDATE.BIN.LZSS because this update is complete. */
94    update_file.close();
95    update_file.erase();
96  }
97  /* For UPDATE.BIN - uncompressed binary files. */
98  else if (WiFiStorage.exists(UPDATE_FILE_NAME)) {
99
100    WiFiStorageFile updateFile = WiFiStorage.open(UPDATE_FILE_NAME);
101    uint32_t updateSize = updateFile.size();
102    bool updateFlashed = false;
103
104    if (updateSize > SDU_SIZE) {
105      // skip the SDU section
106      updateFile.seek(SDU_SIZE);
107      updateSize -= SDU_SIZE;
108
109      uint32_t flashAddress = (uint32_t)SKETCH_START;
110
111      // erase the pages
112      flash.erase((void*)flashAddress, updateSize);
113
114      uint8_t buffer[128];
115
116      // write the pages
117      for (uint32_t i = 0; i < updateSize; i += sizeof(buffer)) {
118        updateFile.read(buffer, sizeof(buffer));
119
120        flash.write((void*)flashAddress, buffer, sizeof(buffer));
121
122        flashAddress += sizeof(buffer);
123      }
124
125      updateFlashed = true;
126    }
127
128    updateFile.close();
129
130    if (updateFlashed) {
131      updateFile.erase();
132    }
133  }
134
135boot:
136  // jump to the sketch
137  __set_MSP(*SKETCH_START);
138
139  //Reset vector table address
140  SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);
141
142  // address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script)
143  uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
144  // jump to reset handler
145  asm("bx %0"::"r"(resetHandlerAddress));
146}
147