Skip to content

Support for OTA update #3812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-27 23:57-0500\n"
"POT-Creation-Date: 2020-12-08 10:30+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -498,8 +498,8 @@ msgstr ""
msgid "Buffer must be a multiple of 512 bytes"
msgstr ""

#: shared-bindings/bitbangio/I2C.c shared-bindings/busdevice/I2CDevice.c
#: shared-bindings/busio/I2C.c
#: shared-bindings/adafruit_bus_device/I2CDevice.c
#: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c
msgid "Buffer must be at least length 1"
msgstr ""

Expand Down Expand Up @@ -1296,7 +1296,7 @@ msgstr ""
msgid "No DMA channel found"
msgstr ""

#: shared-module/busdevice/I2CDevice.c
#: shared-module/adafruit_bus_device/I2CDevice.c
#, c-format
msgid "No I2C device at address: %x"
msgstr ""
Expand Down Expand Up @@ -1420,6 +1420,10 @@ msgstr ""
msgid "Not settable"
msgstr ""

#: ports/esp32s2/common-hal/ota/__init__.c
msgid "OTA Update Failed"
msgstr ""

#: shared-bindings/util.c
msgid ""
"Object has been deinitialized and can no longer be used. Create a new object."
Expand Down Expand Up @@ -1503,6 +1507,7 @@ msgstr ""
msgid "Pin does not have ADC capabilities"
msgstr ""

#: shared-bindings/adafruit_bus_device/SPIDevice.c
#: shared-bindings/digitalio/DigitalInOut.c
msgid "Pin is input only"
msgstr ""
Expand Down
2 changes: 2 additions & 0 deletions ports/esp32s2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ INC += -isystem esp-idf/components/heap/include
INC += -isystem esp-idf/components/esp_system/include
INC += -isystem esp-idf/components/spi_flash/include
INC += -isystem esp-idf/components/nvs_flash/include
INC += -isystem esp-idf/components/app_update/include
INC += -isystem esp-idf/components/bootloader_support/include
INC += -I$(BUILD)/esp-idf/config

CFLAGS += -DHAVE_CONFIG_H \
Expand Down
130 changes: 130 additions & 0 deletions ports/esp32s2/common-hal/ota/__init__.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 microDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "shared-bindings/ota/__init__.h"

#include <string.h>

#include "esp_log.h"
#include "esp_ota_ops.h"

static const char *TAG = "OTA";

static void __attribute__((noreturn)) task_fatal_error(void) {
ESP_LOGE(TAG, "Exiting task due to fatal error...");
mp_raise_RuntimeError(translate("OTA Update Failed"));
}

void common_hal_ota_flash(const void *buf, const size_t len) {
esp_err_t err;
/* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
esp_ota_handle_t update_handle = 0 ;
const esp_partition_t *update_partition = NULL;

ESP_LOGI(TAG, "Starting update");

const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();

if (configured != running) {
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
configured->address, running->address);
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
}
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
running->type, running->subtype, running->address);

update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAG, "Writing partition type %d subtype %d (offset 0x%08x)\n",
update_partition->type, update_partition->subtype, update_partition->address);
assert(update_partition != NULL);


if (len > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
// check current version with downloading
esp_app_desc_t new_app_info;
memcpy(&new_app_info, &((char *)buf)[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);

esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
}

const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
esp_app_desc_t invalid_app_info;
if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
}

// check current version with last invalid partition
if (last_invalid_app != NULL) {
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
task_fatal_error();
}
}

if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
task_fatal_error();
}

err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
task_fatal_error();
}
ESP_LOGI(TAG, "esp_ota_begin succeeded");
} else {
ESP_LOGE(TAG, "received package is not fit len");
task_fatal_error();
}

err = esp_ota_write( update_handle, buf, len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err));
task_fatal_error();
}
ESP_LOGI(TAG, "Total Write binary data length: %d", len);

err = esp_ota_end(update_handle);
if (err != ESP_OK) {
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
}
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
task_fatal_error();
}

err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
task_fatal_error();
}
}
1 change: 1 addition & 0 deletions ports/esp32s2/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ CIRCUITPY_FREQUENCYIO = 1
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_ROTARYIO = 1
CIRCUITPY_NVM = 1
CIRCUITPY_OTA = 1
# We don't have enough endpoints to include MIDI.
CIRCUITPY_USB_MIDI = 0
CIRCUITPY_WIFI = 1
Expand Down
4 changes: 4 additions & 0 deletions py/circuitpy_defns.mk
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ endif
ifeq ($(CIRCUITPY_OS),1)
SRC_PATTERNS += os/%
endif
ifeq ($(CIRCUITPY_OTA),1)
SRC_PATTERNS += ota/%
endif
ifeq ($(CIRCUITPY_PIXELBUF),1)
SRC_PATTERNS += _pixelbuf/%
endif
Expand Down Expand Up @@ -347,6 +350,7 @@ SRC_COMMON_HAL_ALL = \
nvm/ByteArray.c \
nvm/__init__.c \
os/__init__.c \
ota/__init__.c \
ps2io/Ps2.c \
ps2io/__init__.c \
pulseio/PulseIn.c \
Expand Down
8 changes: 8 additions & 0 deletions py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ extern const struct _mp_obj_module_t os_module;
#define OS_MODULE_ALT_NAME
#endif

#if CIRCUITPY_OTA
extern const struct _mp_obj_module_t ota_module;
#define OTA_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ota), (mp_obj_t)&ota_module },
#else
#define OTA_MODULE
#endif

#if CIRCUITPY_PEW
extern const struct _mp_obj_module_t pew_module;
#define PEW_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pew),(mp_obj_t)&pew_module },
Expand Down Expand Up @@ -827,6 +834,7 @@ extern const struct _mp_obj_module_t wifi_module;
NETWORK_MODULE \
SOCKET_MODULE \
WIZNET_MODULE \
OTA_MODULE \
PEW_MODULE \
PIXELBUF_MODULE \
PS2IO_MODULE \
Expand Down
3 changes: 3 additions & 0 deletions py/circuitpy_mpconfig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ CFLAGS += -DCIRCUITPY_NVM=$(CIRCUITPY_NVM)
CIRCUITPY_OS ?= 1
CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS)

CIRCUITPY_OTA ?= 0
CFLAGS += -DCIRCUITPY_OTA=$(CIRCUITPY_OTA)

CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF)

Expand Down
51 changes: 51 additions & 0 deletions shared-bindings/ota/__init__.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 microDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "shared-bindings/ota/__init__.h"

//| """ota module
//|
//| The `ota` module implements over-the-air update."""

STATIC mp_obj_t ota_flash(mp_obj_t program_binary_in) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ);

common_hal_ota_flash(bufinfo.buf, bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(ota_flash_obj, ota_flash);

STATIC const mp_rom_map_elem_t ota_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ota) },
{ MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&ota_flash_obj) },
};
STATIC MP_DEFINE_CONST_DICT(ota_module_globals, ota_module_globals_table);

const mp_obj_module_t ota_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&ota_module_globals,
};
34 changes: 34 additions & 0 deletions shared-bindings/ota/__init__.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 microDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_OTA___INIT___H
#define MICROPY_INCLUDED_SHARED_BINDINGS_OTA___INIT___H

#include "py/runtime.h"

extern void common_hal_ota_flash(const void *buf, const size_t len);

#endif // MICROPY_INCLUDED_SHARED_BINDINGS_OTA___INIT___H