Skip to content

Commit 6f2069d

Browse files
John Doeigrr
John Doe
authored andcommitted
New Update library, example, upload and more
Proper error handling in the uploading python script Much faster OTA example sketch with better results New Update class that simplifies updating the firmware from any source Updated Esp.updateSketch() to use the new class
1 parent 86cf9b2 commit 6f2069d

File tree

7 files changed

+445
-129
lines changed

7 files changed

+445
-129
lines changed

cores/esp8266/Arduino.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ void loop(void);
233233

234234
#include "HardwareSerial.h"
235235
#include "Esp.h"
236+
#include "Updater.h"
236237
#include "debug.h"
237238

238239
#define min(a,b) ((a)<(b)?(a):(b))

cores/esp8266/Esp.cpp

Lines changed: 24 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern struct rst_info resetInfo;
3030
}
3131

3232

33-
// #define DEBUG_SERIAL Serial
33+
//#define DEBUG_SERIAL Serial
3434

3535

3636
/**
@@ -358,96 +358,38 @@ uint32_t EspClass::getFreeSketchSpace() {
358358
return freeSpaceEnd - freeSpaceStart;
359359
}
360360

361-
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail) {
362-
363-
if (size > getFreeSketchSpace()){
364-
if(restartOnFail) ESP.restart();
365-
return false;
366-
}
367-
368-
uint32_t usedSize = getSketchSize();
369-
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
370-
uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
371-
372-
#ifdef DEBUG_SERIAL
373-
DEBUG_SERIAL.printf("erase @0x%x size=0x%x\r\n", freeSpaceStart, roundedSize);
374-
#endif
375-
376-
noInterrupts();
377-
int rc = SPIEraseAreaEx(freeSpaceStart, roundedSize);
378-
interrupts();
379-
if (rc){
380-
if(restartOnFail) ESP.restart();
381-
return false;
382-
}
383-
361+
bool EspClass::updateSketch(Stream& in, uint32_t size, bool restartOnFail, bool restartOnSuccess) {
362+
if(!Update.begin(size)){
384363
#ifdef DEBUG_SERIAL
385-
DEBUG_SERIAL.println("erase done");
364+
DEBUG_SERIAL.print("Update ");
365+
Update.printError(DEBUG_SERIAL);
386366
#endif
367+
if(restartOnFail) ESP.restart();
368+
return false;
369+
}
387370

388-
uint32_t addr = freeSpaceStart;
389-
uint32_t left = size;
390-
391-
const uint32_t bufferSize = FLASH_SECTOR_SIZE;
392-
std::unique_ptr<uint8_t> buffer(new uint8_t[bufferSize]);
393-
371+
if(Update.writeStream(in) != size){
394372
#ifdef DEBUG_SERIAL
395-
DEBUG_SERIAL.println("writing");
373+
DEBUG_SERIAL.print("Update ");
374+
Update.printError(DEBUG_SERIAL);
396375
#endif
397-
while (left > 0) {
398-
size_t willRead = (left < bufferSize) ? left : bufferSize;
399-
size_t rd = in.readBytes(buffer.get(), willRead);
400-
if (rd != willRead) {
401-
#ifdef DEBUG_SERIAL
402-
DEBUG_SERIAL.printf("stream read less: %u/%u\n", rd, willRead);
403-
#endif
404-
if(rd == 0){ //we got nothing from the client
405-
//we should actually give it a bit of a chance to send us something
406-
//connection could be slow ;)
407-
if(restartOnFail) ESP.restart();
408-
return false;
409-
}
410-
//we at least got some data, lets write it to the flash
411-
willRead = rd;
412-
}
413-
414-
if(addr == freeSpaceStart) {
415-
// check for valid first magic byte
416-
if(*((uint8 *) buffer.get()) != 0xE9) {
417-
if(restartOnFail) ESP.restart();
418-
return false;
419-
}
420-
}
421-
422-
noInterrupts();
423-
rc = SPIWrite(addr, buffer.get(), willRead);
424-
interrupts();
425-
if (rc) {
426-
#ifdef DEBUG_SERIAL
427-
DEBUG_SERIAL.println("write failed");
428-
#endif
429-
if(restartOnFail) ESP.restart();
430-
return false;
431-
}
376+
if(restartOnFail) ESP.restart();
377+
return false;
378+
}
432379

433-
addr += willRead;
434-
left -= willRead;
380+
if(!Update.end()){
435381
#ifdef DEBUG_SERIAL
436-
DEBUG_SERIAL.print(".");
382+
DEBUG_SERIAL.print("Update ");
383+
Update.printError(DEBUG_SERIAL);
437384
#endif
438-
}
385+
if(restartOnFail) ESP.restart();
386+
return false;
387+
}
439388

440389
#ifdef DEBUG_SERIAL
441-
DEBUG_SERIAL.println("\r\nrestarting");
442-
#endif
443-
eboot_command ebcmd;
444-
ebcmd.action = ACTION_COPY_RAW;
445-
ebcmd.args[0] = freeSpaceStart;
446-
ebcmd.args[1] = 0x00000;
447-
ebcmd.args[2] = size;
448-
eboot_command_write(&ebcmd);
449-
450-
ESP.restart();
451-
return true; // never happens
390+
DEBUG_SERIAL.println("Update SUCCESS");
391+
#endif
392+
if(restartOnSuccess) ESP.restart();
393+
return true;
452394
}
453395

cores/esp8266/Esp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class EspClass {
116116

117117
uint32_t getSketchSize();
118118
uint32_t getFreeSketchSpace();
119-
bool updateSketch(Stream& in, uint32_t size, bool restartOnFail = false);
119+
bool updateSketch(Stream& in, uint32_t size, bool restartOnFail = false, bool restartOnSuccess = true);
120120

121121
String getResetInfo();
122122
struct rst_info * getResetInfoPtr();

cores/esp8266/Updater.cpp

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include "Updater.h"
2+
#include "Arduino.h"
3+
#include "eboot_command.h"
4+
extern "C"{
5+
#include "mem.h"
6+
}
7+
#define DEBUG_UPDATER Serial
8+
9+
extern "C" uint32_t _SPIFFS_start;
10+
11+
UpdaterClass::UpdaterClass() : _error(0), _buffer(0), _bufferLen(0), _size(0), _startAddress(0), _currentAddress(0) {}
12+
13+
bool UpdaterClass::begin(size_t size){
14+
if(_size > 0){
15+
#ifdef DEBUG_UPDATER
16+
DEBUG_UPDATER.println("already running");
17+
#endif
18+
return false;
19+
}
20+
21+
if(size == 0){
22+
_error = UPDATE_ERROR_SIZE;
23+
#ifdef DEBUG_UPDATER
24+
printError(DEBUG_UPDATER);
25+
#endif
26+
return false;
27+
}
28+
29+
if(_buffer) os_free(_buffer);
30+
31+
_bufferLen = 0;
32+
_startAddress = 0;
33+
_currentAddress = 0;
34+
_size = 0;
35+
_error = 0;
36+
37+
uint32_t usedSize = ESP.getSketchSize();
38+
uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
39+
uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000;
40+
uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
41+
42+
if(roundedSize > (freeSpaceEnd - freeSpaceStart)){
43+
_error = UPDATE_ERROR_SPACE;
44+
#ifdef DEBUG_UPDATER
45+
printError(DEBUG_UPDATER);
46+
#endif
47+
return false;
48+
}
49+
noInterrupts();
50+
int rc = SPIEraseAreaEx(freeSpaceStart, roundedSize);
51+
interrupts();
52+
if (rc){
53+
_error = UPDATE_ERROR_ERASE;
54+
#ifdef DEBUG_UPDATER
55+
printError(DEBUG_UPDATER);
56+
#endif
57+
return false;
58+
}
59+
_startAddress = freeSpaceStart;
60+
_currentAddress = _startAddress;
61+
_size = size;
62+
_buffer = (uint8_t*)os_malloc(FLASH_SECTOR_SIZE);
63+
64+
return true;
65+
}
66+
67+
bool UpdaterClass::end(){
68+
if(_size == 0){
69+
#ifdef DEBUG_UPDATER
70+
DEBUG_UPDATER.println("no update");
71+
#endif
72+
return false;
73+
}
74+
75+
if(_buffer) os_free(_buffer);
76+
_bufferLen = 0;
77+
78+
if(hasError() || !isFinished()){
79+
#ifdef DEBUG_UPDATER
80+
DEBUG_UPDATER.printf("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size);
81+
#endif
82+
_currentAddress = 0;
83+
_startAddress = 0;
84+
_size = 0;
85+
return false;
86+
}
87+
88+
eboot_command ebcmd;
89+
ebcmd.action = ACTION_COPY_RAW;
90+
ebcmd.args[0] = _startAddress;
91+
ebcmd.args[1] = 0x00000;
92+
ebcmd.args[2] = _size;
93+
eboot_command_write(&ebcmd);
94+
95+
_currentAddress = 0;
96+
_startAddress = 0;
97+
_size = 0;
98+
_error = UPDATE_ERROR_OK;
99+
return true;
100+
}
101+
102+
bool UpdaterClass::_writeBuffer(){
103+
WDT_FEED();
104+
noInterrupts();
105+
int rc = SPIWrite(_currentAddress, _buffer, _bufferLen);
106+
interrupts();
107+
if (rc) {
108+
_error = UPDATE_ERROR_WRITE;
109+
#ifdef DEBUG_UPDATER
110+
printError(DEBUG_UPDATER);
111+
#endif
112+
return false;
113+
}
114+
_currentAddress += _bufferLen;
115+
_bufferLen = 0;
116+
return true;
117+
}
118+
119+
size_t UpdaterClass::write(uint8_t *data, size_t len){
120+
size_t left = len;
121+
if(hasError())
122+
return 0;
123+
124+
while((_bufferLen + left) > FLASH_SECTOR_SIZE){
125+
size_t toBuff = FLASH_SECTOR_SIZE - _bufferLen;
126+
memcpy(_buffer + _bufferLen, data + (len - left), toBuff);
127+
_bufferLen += toBuff;
128+
if(!_writeBuffer()){
129+
return len - left;
130+
}
131+
left -= toBuff;
132+
yield();
133+
}
134+
//lets see whats left
135+
memcpy(_buffer + _bufferLen, data + (len - left), left);
136+
_bufferLen += left;
137+
if(_bufferLen == remaining()){
138+
//we are at the end of the update, so should write what's left to flash
139+
if(!_writeBuffer()){
140+
return len - left;
141+
}
142+
}
143+
return len;
144+
}
145+
146+
size_t UpdaterClass::writeStream(Stream &data){
147+
size_t written = 0;
148+
size_t toRead = 0;
149+
if(hasError())
150+
return 0;
151+
152+
while(remaining()){
153+
toRead = FLASH_SECTOR_SIZE - _bufferLen;
154+
toRead = data.readBytes(_buffer + _bufferLen, toRead);
155+
if(toRead == 0){ //Timeout
156+
_error = UPDATE_ERROR_STREAM;
157+
#ifdef DEBUG_UPDATER
158+
printError(DEBUG_UPDATER);
159+
#endif
160+
return written;
161+
}
162+
_bufferLen += toRead;
163+
if((_bufferLen == remaining() || _bufferLen == FLASH_SECTOR_SIZE) && !_writeBuffer())
164+
return written;
165+
written += toRead;
166+
yield();
167+
}
168+
return written;
169+
}
170+
171+
void UpdaterClass::printError(Stream &out){
172+
out.printf("ERROR[%u]: ", _error);
173+
if(_error == UPDATE_ERROR_OK){
174+
out.println("No Error");
175+
} else if(_error == UPDATE_ERROR_WRITE){
176+
out.println("Flash Write Failed");
177+
} else if(_error == UPDATE_ERROR_ERASE){
178+
out.println("Flash Erase Failed");
179+
} else if(_error == UPDATE_ERROR_SPACE){
180+
out.println("Not Enough Space");
181+
} else if(_error == UPDATE_ERROR_SIZE){
182+
out.println("Bad Size Given");
183+
} else if(_error == UPDATE_ERROR_STREAM){
184+
out.println("Stream Read Timeout");
185+
} else {
186+
out.println("UNKNOWN");
187+
}
188+
}
189+
190+
UpdaterClass Update;

0 commit comments

Comments
 (0)