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#define SBU_START    0x2000
23#define SBU_SIZE     0x8000
24
25#define SKETCH_START (uint32_t*)(SBU_START + SBU_SIZE)
26
27static constexpr char UPDATE_FILE_NAME[] = "UPDATE.BIN";
28static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";
29
30FlashClass mcu_flash;
31
32NBFileUtils  fileUtils(true);
33
34extern "C" void __libc_init_array(void);
35
36int main()
37{
38  init();
39
40  __libc_init_array();
41
42  delay(1);
43
44  constexpr size_t blockSize = 512;
45  fileUtils.begin();
46
47  bool update_success = false;
48
49  // Try to update only if update file
50  // has been download successfully.
51
52  if (fileUtils.existFile(CHECK_FILE_NAME)) {
53    uint32_t updateSize = fileUtils.listFile(UPDATE_FILE_NAME);
54    uint32_t tot_bytes = 0;
55    uint32_t read_bytes = 0;
56
57    if (updateSize > SBU_SIZE) {
58      updateSize = updateSize - SBU_SIZE - SBU_START;
59      size_t cycles = (updateSize / blockSize);
60      size_t spare_bytes = (updateSize % blockSize);
61      /* Erase the MCU flash */
62      uint32_t flash_address = (uint32_t)SKETCH_START;
63      mcu_flash.erase((void*)flash_address, updateSize);
64
65      for (auto i = 0; i < cycles; i++) {
66        uint8_t block[blockSize] { 0 };
67        digitalWrite(LED_BUILTIN, LOW);
68        read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SBU_SIZE + SBU_START, blockSize, block);
69        digitalWrite(LED_BUILTIN, HIGH);
70        mcu_flash.write((void*)flash_address, block, read_bytes);
71        flash_address += read_bytes;
72        tot_bytes += read_bytes;
73      }
74
75      if (spare_bytes){
76        uint8_t block[spare_bytes] { 0 };
77        digitalWrite(LED_BUILTIN, LOW);
78        read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, tot_bytes + SBU_SIZE + SBU_START, spare_bytes, block);
79        digitalWrite(LED_BUILTIN, HIGH);
80        mcu_flash.write((void*)flash_address, block, read_bytes);
81        flash_address += read_bytes;
82      }
83      update_success = true;
84    }
85    if (update_success) {
86      fileUtils.deleteFile(UPDATE_FILE_NAME);
87      fileUtils.deleteFile(CHECK_FILE_NAME);
88    }
89  }
90
91boot:
92  /* Jump to the sketch */
93  __set_MSP(*SKETCH_START);
94
95  /* Reset vector table address */
96  SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);
97
98  /* Address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script) */
99  uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
100  /* Jump to reset handler */
101  asm("bx %0"::"r"(resetHandlerAddress));
102}
103