Skip to content

Commit 26eede8

Browse files
committed
Add function to update sketch from Stream
1 parent d24fa46 commit 26eede8

File tree

6 files changed

+402
-22
lines changed

6 files changed

+402
-22
lines changed

cores/esp8266/Esp.cpp

+125
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@
1919
*/
2020

2121
#include "Arduino.h"
22+
#include "flash_utils.h"
23+
#include "eboot_command.h"
24+
#include <memory>
2225

2326
extern "C" {
2427
#include "user_interface.h"
2528

2629
extern struct rst_info resetInfo;
2730
}
2831

32+
33+
// #define DEBUG_SERIAL Serial
34+
2935
//extern "C" void ets_wdt_init(uint32_t val);
3036
extern "C" void ets_wdt_enable(void);
3137
extern "C" void ets_wdt_disable(void);
@@ -315,4 +321,123 @@ bool EspClass::eraseConfig(void) {
315321
return ret;
316322
}
317323

324+
uint32_t EspClass::getSketchSize() {
325+
static uint32_t result = 0;
326+
if (result)
327+
return result;
328+
329+
image_header_t image_header;
330+
uint32_t pos = APP_START_OFFSET;
331+
if (spi_flash_read(pos, (uint32_t*) &image_header, sizeof(image_header))) {
332+
return 0;
333+
}
334+
pos += sizeof(image_header);
335+
#ifdef DEBUG_SERIAL
336+
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
337+
#endif
338+
for (uint32_t section_index = 0;
339+
section_index < image_header.num_segments;
340+
++section_index)
341+
{
342+
section_header_t section_header = {0};
343+
if (spi_flash_read(pos, (uint32_t*) &section_header, sizeof(section_header))) {
344+
return 0;
345+
}
346+
pos += sizeof(section_header);
347+
pos += section_header.size;
348+
#ifdef DEBUG_SERIAL
349+
DEBUG_SERIAL.printf("section=%u size=%u pos=%u\r\n", section_index, section_header.size, pos);
350+
#endif
351+
}
352+
result = pos;
353+
return result;
354+
}
355+
356+
extern "C" uint32_t _SPIFFS_start;
357+
358+
uint32_t EspClass::getFreeSketchSpace() {
359+
360+
uint32_t usedSize = getSketchSize();
361+
// round one sector up
362+
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
363+
uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000;
364+
365+
#ifdef DEBUG_SERIAL
366+
DEBUG_SERIAL.printf("usedSize=%u freeSpaceStart=%u freeSpaceEnd=%u\r\n", usedSize, freeSpaceStart, freeSpaceEnd);
367+
#endif
368+
return freeSpaceEnd - freeSpaceStart;
369+
}
370+
371+
bool EspClass::updateSketch(Stream& in, uint32_t size) {
372+
373+
if (size > getFreeSketchSpace())
374+
return false;
375+
376+
uint32_t usedSize = getSketchSize();
377+
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
378+
uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
379+
380+
#ifdef DEBUG_SERIAL
381+
DEBUG_SERIAL.printf("erase @0x%x size=0x%x\r\n", freeSpaceStart, roundedSize);
382+
#endif
383+
384+
noInterrupts();
385+
int rc = SPIEraseAreaEx(freeSpaceStart, roundedSize);
386+
interrupts();
387+
if (rc)
388+
return false;
389+
390+
#ifdef DEBUG_SERIAL
391+
DEBUG_SERIAL.println("erase done");
392+
#endif
393+
394+
uint32_t addr = freeSpaceStart;
395+
uint32_t left = size;
396+
397+
const uint32_t bufferSize = FLASH_SECTOR_SIZE;
398+
std::unique_ptr<uint8_t> buffer(new uint8_t[bufferSize]);
399+
400+
#ifdef DEBUG_SERIAL
401+
DEBUG_SERIAL.println("writing");
402+
#endif
403+
while (left > 0) {
404+
size_t willRead = (left < bufferSize) ? left : bufferSize;
405+
size_t rd = in.readBytes(buffer.get(), willRead);
406+
if (rd != willRead) {
407+
#ifdef DEBUG_SERIAL
408+
DEBUG_SERIAL.println("stream read failed");
409+
#endif
410+
return false;
411+
}
412+
413+
noInterrupts();
414+
rc = SPIWrite(addr, buffer.get(), willRead);
415+
interrupts();
416+
if (rc) {
417+
#ifdef DEBUG_SERIAL
418+
DEBUG_SERIAL.println("write failed");
419+
#endif
420+
return false;
421+
}
422+
423+
addr += willRead;
424+
left -= willRead;
425+
#ifdef DEBUG_SERIAL
426+
DEBUG_SERIAL.print(".");
427+
#endif
428+
}
429+
430+
#ifdef DEBUG_SERIAL
431+
DEBUG_SERIAL.println("\r\nrestarting");
432+
#endif
433+
eboot_command ebcmd;
434+
ebcmd.action = ACTION_COPY_RAW;
435+
ebcmd.args[0] = freeSpaceStart;
436+
ebcmd.args[1] = 0x00000;
437+
ebcmd.args[2] = size;
438+
eboot_command_write(&ebcmd);
439+
440+
ESP.restart();
441+
return true; // never happens
442+
}
318443

cores/esp8266/Esp.h

+26-22
Original file line numberDiff line numberDiff line change
@@ -69,44 +69,48 @@ class EspClass {
6969
// note: setting the timeout value is not implemented at the moment
7070
void wdtEnable(WDTO_t timeout_ms = WDTO_0MS);
7171

72-
void wdtDisable(void);
73-
void wdtFeed(void);
72+
void wdtDisable();
73+
void wdtFeed();
7474

7575
void deepSleep(uint32_t time_us, WakeMode mode = WAKE_RF_DEFAULT);
7676

77-
void reset(void);
78-
void restart(void);
77+
void reset();
78+
void restart();
7979

80-
uint16_t getVcc(void);
81-
uint32_t getFreeHeap(void);
80+
uint16_t getVcc();
81+
uint32_t getFreeHeap();
8282

83-
uint32_t getChipId(void);
83+
uint32_t getChipId();
8484

85-
const char * getSdkVersion(void);
85+
const char * getSdkVersion();
8686

87-
uint8_t getBootVersion(void);
88-
uint8_t getBootMode(void);
87+
uint8_t getBootVersion();
88+
uint8_t getBootMode();
8989

90-
uint8_t getCpuFreqMHz(void);
90+
uint8_t getCpuFreqMHz();
9191

92-
uint32_t getFlashChipId(void);
92+
uint32_t getFlashChipId();
9393
//gets the actual chip size based on the flash id
94-
uint32_t getFlashChipRealSize(void);
94+
uint32_t getFlashChipRealSize();
9595
//gets the size of the flash as set by the compiler
96-
uint32_t getFlashChipSize(void);
97-
uint32_t getFlashChipSpeed(void);
98-
FlashMode_t getFlashChipMode(void);
99-
uint32_t getFlashChipSizeByChipId(void);
96+
uint32_t getFlashChipSize();
97+
uint32_t getFlashChipSpeed();
98+
FlashMode_t getFlashChipMode();
99+
uint32_t getFlashChipSizeByChipId();
100100

101-
String getResetInfo(void);
102-
struct rst_info * getResetInfoPtr(void);
101+
uint32_t getSketchSize();
102+
uint32_t getFreeSketchSpace();
103+
bool updateSketch(Stream& in, uint32_t size);
103104

104-
bool eraseConfig(void);
105+
String getResetInfo();
106+
struct rst_info * getResetInfoPtr();
105107

106-
inline uint32_t getCycleCount(void);
108+
bool eraseConfig();
109+
110+
inline uint32_t getCycleCount();
107111
};
108112

109-
uint32_t EspClass::getCycleCount(void)
113+
uint32_t EspClass::getCycleCount()
110114
{
111115
uint32_t ccount;
112116
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
core_esp8266_eboot_command.c - interface to the eboot bootloader
3+
4+
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
5+
This file is part of the esp8266 core for Arduino environment.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#include <stddef.h>
23+
#include <stdbool.h>
24+
#include "eboot_command.h"
25+
26+
uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length)
27+
{
28+
uint32_t i;
29+
bool bit;
30+
uint8_t c;
31+
32+
while (length--) {
33+
c = *data++;
34+
for (i = 0x80; i > 0; i >>= 1) {
35+
bit = crc & 0x80000000;
36+
if (c & i) {
37+
bit = !bit;
38+
}
39+
crc <<= 1;
40+
if (bit) {
41+
crc ^= 0x04c11db7;
42+
}
43+
}
44+
}
45+
return crc;
46+
}
47+
48+
uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
49+
{
50+
return crc_update(0xffffffff, (const uint8_t*) cmd,
51+
offsetof(struct eboot_command, crc32));
52+
}
53+
54+
int eboot_command_read(struct eboot_command* cmd)
55+
{
56+
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
57+
uint32_t* dst = (uint32_t *) cmd;
58+
for (uint32_t i = 0; i < dw_count; ++i) {
59+
dst[i] = RTC_MEM[i];
60+
}
61+
62+
uint32_t crc32 = eboot_command_calculate_crc32(cmd);
63+
if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC ||
64+
cmd->crc32 != crc32) {
65+
return 1;
66+
}
67+
68+
return 0;
69+
}
70+
71+
void eboot_command_write(struct eboot_command* cmd)
72+
{
73+
cmd->magic = EBOOT_MAGIC;
74+
cmd->crc32 = eboot_command_calculate_crc32(cmd);
75+
76+
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
77+
const uint32_t* src = (const uint32_t *) cmd;
78+
for (uint32_t i = 0; i < dw_count; ++i) {
79+
RTC_MEM[i] = src[i];
80+
}
81+
}
82+
83+
void eboot_command_clear()
84+
{
85+
RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0;
86+
RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0;
87+
}
88+
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
core_esp8266_flash_utils.c - flash and binary image helpers
3+
4+
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
5+
This file is part of the esp8266 core for Arduino environment.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
23+
#include <stddef.h>
24+
#include <stdint.h>
25+
#include <stdbool.h>
26+
#include "flash_utils.h"
27+
28+
29+
int SPIEraseAreaEx(const uint32_t start, const uint32_t size)
30+
{
31+
if (start & (FLASH_SECTOR_SIZE - 1) != 0) {
32+
return 1;
33+
}
34+
35+
const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
36+
uint32_t current_sector = start / FLASH_SECTOR_SIZE;
37+
uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
38+
const uint32_t end = current_sector + sector_count;
39+
40+
for (; current_sector < end && (current_sector & (sectors_per_block-1));
41+
++current_sector, --sector_count) {
42+
if (SPIEraseSector(current_sector)) {
43+
return 2;
44+
}
45+
}
46+
47+
for (;current_sector + sectors_per_block <= end;
48+
current_sector += sectors_per_block,
49+
sector_count -= sectors_per_block) {
50+
if (SPIEraseBlock(current_sector / sectors_per_block)) {
51+
return 3;
52+
}
53+
}
54+
55+
for (; current_sector < end;
56+
++current_sector, --sector_count) {
57+
if (SPIEraseSector(current_sector)) {
58+
return 4;
59+
}
60+
}
61+
62+
return 0;
63+
}
64+

0 commit comments

Comments
 (0)