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#ifdef ARDUINO_SAMD_MKRVIDOR4000
23#include <VidorPeripherals.h>
24#endif /* ARDUINO_SAMD_MKRVIDOR4000 */
25
26#ifdef ARDUINO_SAMD_MKRVIDOR4000
27#define NINA_GPIO0  FPGA_NINA_GPIO0
28#define NINA_RESETN FPGA_SPIWIFI_RESET
29#endif /* ARDUINO_SAMD_MKRVIDOR4000 */
30
31#define SDU_START    0x2000
32#define SDU_SIZE     0x4000
33
34#define SKETCH_START (uint32_t*)(SDU_START + SDU_SIZE)
35
36#define UPDATE_FILE "/fs/UPDATE.BIN"
37
38FlashClass flash;
39
40// Initialize C library
41extern "C" void __libc_init_array(void);
42
43int main() {
44  init();
45
46  __libc_init_array();
47
48  delay(1);
49
50#if defined(ARDUINO_SAMD_MKRVIDOR4000)
51  FPGA.begin();
52  /* NINA select SPI mode and enable (by setting RESETN = '1') */
53  FPGA.pinMode     (NINA_GPIO0,  OUTPUT);
54  FPGA.digitalWrite(NINA_GPIO0,  HIGH);
55  FPGA.pinMode     (NINA_RESETN, OUTPUT);
56  FPGA.digitalWrite(NINA_RESETN, HIGH);
57#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT)
58  /* NINA select SPI mode and enable (by setting RESETN = '1') */
59  pinMode     (NINA_GPIO0,  OUTPUT);
60  digitalWrite(NINA_GPIO0,  HIGH);
61  pinMode     (NINA_RESETN, OUTPUT);
62  digitalWrite(NINA_RESETN, HIGH);
63#endif
64
65  if (WiFi.status() == WL_NO_SHIELD) {
66    goto boot;
67  }
68
69  if (WiFiStorage.exists(UPDATE_FILE)) {
70
71    WiFiStorageFile updateFile = WiFiStorage.open(UPDATE_FILE);
72    uint32_t updateSize = updateFile.size();
73    bool updateFlashed = false;
74
75    if (updateSize > SDU_SIZE) {
76      // skip the SDU section
77      updateFile.seek(SDU_SIZE);
78      updateSize -= SDU_SIZE;
79
80      uint32_t flashAddress = (uint32_t)SKETCH_START;
81
82      // erase the pages
83      flash.erase((void*)flashAddress, updateSize);
84
85      uint8_t buffer[128];
86
87      // write the pages
88      for (uint32_t i = 0; i < updateSize; i += sizeof(buffer)) {
89        updateFile.read(buffer, sizeof(buffer));
90
91        flash.write((void*)flashAddress, buffer, sizeof(buffer));
92
93        flashAddress += sizeof(buffer);
94      }
95
96      updateFlashed = true;
97    }
98
99    updateFile.close();
100
101    if (updateFlashed) {
102      updateFile.erase();
103    }
104  }
105
106boot:
107  // jump to the sketch
108  __set_MSP(*SKETCH_START);
109
110  //Reset vector table address
111  SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);
112
113  // address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script)
114  uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
115  // jump to reset handler
116  asm("bx %0"::"r"(resetHandlerAddress));
117}
118