Skip to content

Commit 063d608

Browse files
committed
Optimize Update class
- add roll back API to switch the running partition - do not write the partition magic until the end to prevent booting into partially written update
1 parent dcdf813 commit 063d608

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

libraries/Update/src/Update.h

+9
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,15 @@ class UpdateClass {
137137
return written;
138138
}
139139

140+
/*
141+
check if there is a firmware on the other OTA partition that you can bootinto
142+
*/
143+
bool canRollBack();
144+
/*
145+
set the other OTA partition as bootable (reboot to enable)
146+
*/
147+
bool rollBack();
148+
140149
private:
141150
void _reset();
142151
void _abort(uint8_t err);

libraries/Update/src/Updater.cpp

+61-7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ static const char * _err2str(uint8_t _error){
3535
return ("UNKNOWN");
3636
}
3737

38+
static bool _partitionIsBootable(const esp_partition_t* partition){
39+
uint8_t buf[4];
40+
if(!partition){
41+
return false;
42+
}
43+
if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) {
44+
return false;
45+
}
46+
47+
if(buf[0] != ESP_IMAGE_HEADER_MAGIC) {
48+
return false;
49+
}
50+
return true;
51+
}
52+
53+
static bool _enablePartition(const esp_partition_t* partition){
54+
uint8_t buf[4];
55+
if(!partition){
56+
return false;
57+
}
58+
if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) {
59+
return false;
60+
}
61+
buf[0] = ESP_IMAGE_HEADER_MAGIC;
62+
63+
return ESP.flashWrite(partition->address, (uint32_t*)buf, 4);
64+
}
65+
3866
UpdateClass::UpdateClass()
3967
: _error(0)
4068
, _buffer(0)
@@ -56,6 +84,22 @@ void UpdateClass::_reset() {
5684
_command = U_FLASH;
5785
}
5886

87+
bool UpdateClass::canRollBack(){
88+
if(_buffer){ //Update is running
89+
return false;
90+
}
91+
const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL);
92+
return _partitionIsBootable(partition);
93+
}
94+
95+
bool UpdateClass::rollBack(){
96+
if(_buffer){ //Update is running
97+
return false;
98+
}
99+
const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL);
100+
return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition);
101+
}
102+
59103
bool UpdateClass::begin(size_t size, int command) {
60104
if(_size > 0){
61105
log_w("already running");
@@ -121,6 +165,17 @@ void UpdateClass::abort(){
121165
}
122166

123167
bool UpdateClass::_writeBuffer(){
168+
//first bytes of new firmware
169+
if(!_progress && _command == U_FLASH){
170+
//check magic
171+
if(_buffer[0] != ESP_IMAGE_HEADER_MAGIC){
172+
_abort(UPDATE_ERROR_MAGIC_BYTE);
173+
return false;
174+
}
175+
//remove magic byte from the firmware now and write it upon success
176+
//this ensures that partially written firmware will not be bootable
177+
_buffer[0] = 0xFF;
178+
}
124179
if(!ESP.flashEraseSector((_partition->address + _progress)/SPI_FLASH_SEC_SIZE)){
125180
_abort(UPDATE_ERROR_ERASE);
126181
return false;
@@ -129,6 +184,10 @@ bool UpdateClass::_writeBuffer(){
129184
_abort(UPDATE_ERROR_WRITE);
130185
return false;
131186
}
187+
//restore magic or md5 will fail
188+
if(!_progress && _command == U_FLASH){
189+
_buffer[0] = ESP_IMAGE_HEADER_MAGIC;
190+
}
132191
_md5.add(_buffer, _bufferLen);
133192
_progress += _bufferLen;
134193
_bufferLen = 0;
@@ -150,24 +209,19 @@ bool UpdateClass::_verifyHeader(uint8_t data) {
150209

151210
bool UpdateClass::_verifyEnd() {
152211
if(_command == U_FLASH) {
153-
uint8_t buf[4];
154-
if(!ESP.flashRead(_partition->address, (uint32_t*)buf, 4)) {
212+
if(!_partitionIsBootable(_partition)) {
155213
_abort(UPDATE_ERROR_READ);
156214
return false;
157215
}
158216

159-
if(buf[0] != ESP_IMAGE_HEADER_MAGIC) {
160-
_abort(UPDATE_ERROR_MAGIC_BYTE);
161-
return false;
162-
}
163-
164217
if(esp_ota_set_boot_partition(_partition)){
165218
_abort(UPDATE_ERROR_ACTIVATE);
166219
return false;
167220
}
168221
_reset();
169222
return true;
170223
} else if(_command == U_SPIFFS) {
224+
_reset();
171225
return true;
172226
}
173227
return false;

0 commit comments

Comments
 (0)