1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-22 21:23:07 +03:00

Add function to update sketch from Stream

This commit is contained in:
Ivan Grokhotkov 2015-06-05 13:48:00 +03:00
parent d24fa4636c
commit 26eede862f
6 changed files with 402 additions and 22 deletions

View File

@ -19,6 +19,9 @@
*/
#include "Arduino.h"
#include "flash_utils.h"
#include "eboot_command.h"
#include <memory>
extern "C" {
#include "user_interface.h"
@ -26,6 +29,9 @@ extern "C" {
extern struct rst_info resetInfo;
}
// #define DEBUG_SERIAL Serial
//extern "C" void ets_wdt_init(uint32_t val);
extern "C" void ets_wdt_enable(void);
extern "C" void ets_wdt_disable(void);
@ -315,4 +321,123 @@ bool EspClass::eraseConfig(void) {
return ret;
}
uint32_t EspClass::getSketchSize() {
static uint32_t result = 0;
if (result)
return result;
image_header_t image_header;
uint32_t pos = APP_START_OFFSET;
if (spi_flash_read(pos, (uint32_t*) &image_header, sizeof(image_header))) {
return 0;
}
pos += sizeof(image_header);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.printf("num_segments=%u\r\n", image_header.num_segments);
#endif
for (uint32_t section_index = 0;
section_index < image_header.num_segments;
++section_index)
{
section_header_t section_header = {0};
if (spi_flash_read(pos, (uint32_t*) &section_header, sizeof(section_header))) {
return 0;
}
pos += sizeof(section_header);
pos += section_header.size;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.printf("section=%u size=%u pos=%u\r\n", section_index, section_header.size, pos);
#endif
}
result = pos;
return result;
}
extern "C" uint32_t _SPIFFS_start;
uint32_t EspClass::getFreeSketchSpace() {
uint32_t usedSize = getSketchSize();
// round one sector up
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.printf("usedSize=%u freeSpaceStart=%u freeSpaceEnd=%u\r\n", usedSize, freeSpaceStart, freeSpaceEnd);
#endif
return freeSpaceEnd - freeSpaceStart;
}
bool EspClass::updateSketch(Stream& in, uint32_t size) {
if (size > getFreeSketchSpace())
return false;
uint32_t usedSize = getSketchSize();
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.printf("erase @0x%x size=0x%x\r\n", freeSpaceStart, roundedSize);
#endif
noInterrupts();
int rc = SPIEraseAreaEx(freeSpaceStart, roundedSize);
interrupts();
if (rc)
return false;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("erase done");
#endif
uint32_t addr = freeSpaceStart;
uint32_t left = size;
const uint32_t bufferSize = FLASH_SECTOR_SIZE;
std::unique_ptr<uint8_t> buffer(new uint8_t[bufferSize]);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("writing");
#endif
while (left > 0) {
size_t willRead = (left < bufferSize) ? left : bufferSize;
size_t rd = in.readBytes(buffer.get(), willRead);
if (rd != willRead) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("stream read failed");
#endif
return false;
}
noInterrupts();
rc = SPIWrite(addr, buffer.get(), willRead);
interrupts();
if (rc) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("write failed");
#endif
return false;
}
addr += willRead;
left -= willRead;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print(".");
#endif
}
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("\r\nrestarting");
#endif
eboot_command ebcmd;
ebcmd.action = ACTION_COPY_RAW;
ebcmd.args[0] = freeSpaceStart;
ebcmd.args[1] = 0x00000;
ebcmd.args[2] = size;
eboot_command_write(&ebcmd);
ESP.restart();
return true; // never happens
}

View File

@ -69,44 +69,48 @@ class EspClass {
// note: setting the timeout value is not implemented at the moment
void wdtEnable(WDTO_t timeout_ms = WDTO_0MS);
void wdtDisable(void);
void wdtFeed(void);
void wdtDisable();
void wdtFeed();
void deepSleep(uint32_t time_us, WakeMode mode = WAKE_RF_DEFAULT);
void reset(void);
void restart(void);
void reset();
void restart();
uint16_t getVcc(void);
uint32_t getFreeHeap(void);
uint16_t getVcc();
uint32_t getFreeHeap();
uint32_t getChipId(void);
uint32_t getChipId();
const char * getSdkVersion(void);
const char * getSdkVersion();
uint8_t getBootVersion(void);
uint8_t getBootMode(void);
uint8_t getBootVersion();
uint8_t getBootMode();
uint8_t getCpuFreqMHz(void);
uint8_t getCpuFreqMHz();
uint32_t getFlashChipId(void);
uint32_t getFlashChipId();
//gets the actual chip size based on the flash id
uint32_t getFlashChipRealSize(void);
uint32_t getFlashChipRealSize();
//gets the size of the flash as set by the compiler
uint32_t getFlashChipSize(void);
uint32_t getFlashChipSpeed(void);
FlashMode_t getFlashChipMode(void);
uint32_t getFlashChipSizeByChipId(void);
uint32_t getFlashChipSize();
uint32_t getFlashChipSpeed();
FlashMode_t getFlashChipMode();
uint32_t getFlashChipSizeByChipId();
String getResetInfo(void);
struct rst_info * getResetInfoPtr(void);
uint32_t getSketchSize();
uint32_t getFreeSketchSpace();
bool updateSketch(Stream& in, uint32_t size);
bool eraseConfig(void);
String getResetInfo();
struct rst_info * getResetInfoPtr();
inline uint32_t getCycleCount(void);
bool eraseConfig();
inline uint32_t getCycleCount();
};
uint32_t EspClass::getCycleCount(void)
uint32_t EspClass::getCycleCount()
{
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));

View File

@ -0,0 +1,88 @@
/*
core_esp8266_eboot_command.c - interface to the eboot bootloader
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stddef.h>
#include <stdbool.h>
#include "eboot_command.h"
uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length)
{
uint32_t i;
bool bit;
uint8_t c;
while (length--) {
c = *data++;
for (i = 0x80; i > 0; i >>= 1) {
bit = crc & 0x80000000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x04c11db7;
}
}
}
return crc;
}
uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd)
{
return crc_update(0xffffffff, (const uint8_t*) cmd,
offsetof(struct eboot_command, crc32));
}
int eboot_command_read(struct eboot_command* cmd)
{
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
uint32_t* dst = (uint32_t *) cmd;
for (uint32_t i = 0; i < dw_count; ++i) {
dst[i] = RTC_MEM[i];
}
uint32_t crc32 = eboot_command_calculate_crc32(cmd);
if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC ||
cmd->crc32 != crc32) {
return 1;
}
return 0;
}
void eboot_command_write(struct eboot_command* cmd)
{
cmd->magic = EBOOT_MAGIC;
cmd->crc32 = eboot_command_calculate_crc32(cmd);
const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t);
const uint32_t* src = (const uint32_t *) cmd;
for (uint32_t i = 0; i < dw_count; ++i) {
RTC_MEM[i] = src[i];
}
}
void eboot_command_clear()
{
RTC_MEM[offsetof(struct eboot_command, magic) / sizeof(uint32_t)] = 0;
RTC_MEM[offsetof(struct eboot_command, crc32) / sizeof(uint32_t)] = 0;
}

View File

@ -0,0 +1,64 @@
/*
core_esp8266_flash_utils.c - flash and binary image helpers
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "flash_utils.h"
int SPIEraseAreaEx(const uint32_t start, const uint32_t size)
{
if (start & (FLASH_SECTOR_SIZE - 1) != 0) {
return 1;
}
const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
uint32_t current_sector = start / FLASH_SECTOR_SIZE;
uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE;
const uint32_t end = current_sector + sector_count;
for (; current_sector < end && (current_sector & (sectors_per_block-1));
++current_sector, --sector_count) {
if (SPIEraseSector(current_sector)) {
return 2;
}
}
for (;current_sector + sectors_per_block <= end;
current_sector += sectors_per_block,
sector_count -= sectors_per_block) {
if (SPIEraseBlock(current_sector / sectors_per_block)) {
return 3;
}
}
for (; current_sector < end;
++current_sector, --sector_count) {
if (SPIEraseSector(current_sector)) {
return 4;
}
}
return 0;
}

View File

@ -0,0 +1,36 @@
#ifndef EBOOT_COMMAND_H
#define EBOOT_COMMAND_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RTC_MEM ((volatile uint32_t*)0x60001200)
enum action_t {
ACTION_COPY_RAW = 0x00000001,
ACTION_LOAD_APP = 0xffffffff
};
#define EBOOT_MAGIC 0xeb001000
#define EBOOT_MAGIC_MASK 0xfffff000
struct eboot_command {
uint32_t magic;
enum action_t action;
uint32_t args[29];
uint32_t crc32;
};
int eboot_command_read(struct eboot_command* cmd);
void eboot_command_write(struct eboot_command* cmd);
void eboot_command_clear();
#ifdef __cplusplus
}
#endif
#endif //EBOOT_COMMAND_H

View File

@ -0,0 +1,63 @@
/*
flash_utils.h - Flash access function and data structures
Copyright (c) 2015 Ivan Grokhotkov. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FLASH_UTILS_H
#define FLASH_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
int SPIEraseBlock(uint32_t block);
int SPIEraseSector(uint32_t sector);
int SPIRead(uint32_t addr, void *dest, size_t size);
int SPIWrite(uint32_t addr, void *src, size_t size);
int SPIEraseAreaEx(const uint32_t start, const uint32_t size);
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_BLOCK_SIZE 0x10000
#define APP_START_OFFSET 0x1000
typedef struct {
unsigned char magic;
unsigned char num_segments;
/* SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT) */
unsigned char flash_mode;
/* High four bits: 0 = 512K, 1 = 256K, 2 = 1M, 3 = 2M, 4 = 4M,
Low four bits: 0 = 40MHz, 1= 26MHz, 2 = 20MHz, 0xf = 80MHz */
unsigned char flash_size_freq;
uint32_t entry;
} image_header_t;
typedef struct {
uint32_t address;
uint32_t size;
} section_header_t;
#ifdef __cplusplus
}
#endif
#endif //FLASH_UTILS_H