2019-07-06 14:21:08 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2019 Dius Computing Pty Ltd. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* - Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* - Neither the name of the copyright holders nor the names of
|
|
|
|
* its contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @author Johny Mattsson <jmattsson@dius.com.au>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "module.h"
|
|
|
|
#include "lauxlib.h"
|
|
|
|
|
|
|
|
#include "esp_system.h"
|
|
|
|
#include "esp_ota_ops.h"
|
|
|
|
#include "esp_partition.h"
|
|
|
|
|
|
|
|
static esp_ota_handle_t ota_handle;
|
|
|
|
static const esp_partition_t *next;
|
|
|
|
|
|
|
|
// ----------otaupgrade Lua API ------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// Lua: otaupgrade.commence() -- wipes an inactive slot and enables .write()
|
|
|
|
static int lotaupgrade_commence (lua_State* L)
|
|
|
|
{
|
|
|
|
next = esp_ota_get_next_update_partition (NULL);
|
|
|
|
if (!next)
|
|
|
|
return luaL_error (L, "no OTA partition available");
|
|
|
|
|
|
|
|
esp_err_t err = esp_ota_begin (next, OTA_SIZE_UNKNOWN, &ota_handle);
|
|
|
|
const char *msg = NULL;
|
|
|
|
switch (err) {
|
|
|
|
case ESP_OK: break;
|
|
|
|
case ESP_ERR_NO_MEM: msg = "out of memory"; break;
|
|
|
|
case ESP_ERR_OTA_PARTITION_CONFLICT: // I don't think we can get this?
|
|
|
|
msg = "can't overrite running firmware"; break;
|
|
|
|
case ESP_ERR_OTA_SELECT_INFO_INVALID:
|
|
|
|
msg = "ota data partition invalid"; break;
|
|
|
|
case ESP_ERR_OTA_ROLLBACK_INVALID_STATE:
|
|
|
|
msg = "can't upgrade from unconfirmed firmware"; break;
|
|
|
|
default: msg = "ota error"; break;
|
|
|
|
}
|
|
|
|
if (msg)
|
|
|
|
return luaL_error (L, msg);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lua: otaupgrade.write(data) -- writes the data block to flash
|
|
|
|
static int lotaupgrade_write (lua_State *L)
|
|
|
|
{
|
|
|
|
const char *bytes = luaL_checkstring (L, 1);
|
|
|
|
size_t len = lua_objlen (L, 1);
|
|
|
|
|
|
|
|
esp_err_t err = esp_ota_write (ota_handle, bytes, len);
|
|
|
|
const char *msg = NULL;
|
|
|
|
switch (err) {
|
|
|
|
case ESP_OK: break;
|
|
|
|
case ESP_ERR_INVALID_ARG:
|
|
|
|
msg = "write not possible, use otaupgrade.commence() first"; break;
|
|
|
|
case ESP_ERR_OTA_VALIDATE_FAILED: msg = "not a valid ota image"; break;
|
|
|
|
default: msg = "ota error"; break;
|
|
|
|
}
|
|
|
|
if (msg)
|
|
|
|
return luaL_error (L, msg);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Lua: otaupgrade.complete(optional_reboot)
|
|
|
|
static int lotaupgrade_complete (lua_State *L)
|
|
|
|
{
|
|
|
|
if (!next)
|
|
|
|
return luaL_error (L, "no upgrade in progress");
|
|
|
|
|
|
|
|
esp_err_t err = esp_ota_end(ota_handle);
|
|
|
|
const char *msg = NULL;
|
|
|
|
switch (err) {
|
|
|
|
case ESP_OK: break;
|
|
|
|
case ESP_ERR_INVALID_ARG: msg = "empty firmware image"; break;
|
|
|
|
case ESP_ERR_OTA_VALIDATE_FAILED: msg = "validation failed"; break;
|
|
|
|
default: msg = "ota error"; break;
|
|
|
|
}
|
|
|
|
if (msg)
|
|
|
|
return luaL_error (L, msg);
|
|
|
|
|
|
|
|
err = esp_ota_set_boot_partition (next);
|
|
|
|
next = NULL;
|
|
|
|
|
|
|
|
if (luaL_optint (L, 1, 0))
|
|
|
|
esp_restart ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lua: otaupgrade.accept()
|
|
|
|
static int lotaupgrade_accept (lua_State *L)
|
|
|
|
{
|
|
|
|
esp_err_t err = esp_ota_mark_app_valid_cancel_rollback();
|
|
|
|
if (err != ESP_OK) // only ESP_OK defined as expected return value
|
|
|
|
return luaL_error(L, "firmware accept failed");
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lua: otaupgrade.rollback()
|
|
|
|
static int lotaupgrade_rollback (lua_State *L)
|
|
|
|
{
|
|
|
|
esp_err_t err = esp_ota_mark_app_invalid_rollback_and_reboot();
|
|
|
|
const char *msg = NULL;
|
|
|
|
switch (err) {
|
|
|
|
case ESP_OK: break;
|
|
|
|
case ESP_ERR_OTA_ROLLBACK_FAILED:
|
|
|
|
msg = "no other firmware to roll back to"; break;
|
|
|
|
default:
|
|
|
|
msg = "ota error"; break;
|
|
|
|
}
|
|
|
|
if (msg)
|
|
|
|
return luaL_error(L, msg);
|
|
|
|
else
|
|
|
|
return 0; // actually, we never get here as on success the chip reboots
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Lua: t = otaupgrade.info ()
|
|
|
|
* -- running_partition, nextboot_partition, {
|
|
|
|
* .X = { name, version, secure_version, date, time, idf_version, state },
|
|
|
|
* .Y = { name, version, secure_version, date, time, idf_version, state }
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
static int lotaupgrade_info (lua_State *L)
|
|
|
|
{
|
|
|
|
const esp_partition_t *running = esp_ota_get_running_partition ();
|
|
|
|
if (running)
|
|
|
|
lua_pushstring (L, running->label);
|
|
|
|
else
|
|
|
|
lua_pushnil (L);
|
|
|
|
|
|
|
|
const esp_partition_t *boot = esp_ota_get_boot_partition ();
|
|
|
|
if (boot)
|
|
|
|
lua_pushstring (L, boot->label);
|
|
|
|
else
|
|
|
|
lua_pushnil (L);
|
|
|
|
|
|
|
|
lua_createtable (L, 0, 2);
|
|
|
|
esp_partition_iterator_t iter = esp_partition_find (
|
|
|
|
ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
|
|
|
while (iter) {
|
|
|
|
const esp_partition_t *part = esp_partition_get (iter);
|
|
|
|
if (part->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN &&
|
|
|
|
part->subtype <= ESP_PARTITION_SUBTYPE_APP_OTA_MAX)
|
|
|
|
{
|
|
|
|
lua_pushstring (L, part->label);
|
|
|
|
lua_createtable (L, 0, 6);
|
|
|
|
|
|
|
|
esp_ota_img_states_t state;
|
|
|
|
esp_err_t err = esp_ota_get_state_partition (part, &state);
|
|
|
|
|
|
|
|
if (err == ESP_OK)
|
|
|
|
{
|
|
|
|
lua_pushliteral (L, "state");
|
|
|
|
const char *msg = "";
|
|
|
|
switch (state) {
|
|
|
|
case ESP_OTA_IMG_NEW: msg = "new"; break;
|
|
|
|
case ESP_OTA_IMG_PENDING_VERIFY: msg = "testing"; break;
|
|
|
|
case ESP_OTA_IMG_VALID: msg = "valid"; break;
|
|
|
|
case ESP_OTA_IMG_INVALID: msg = "invalid"; break;
|
|
|
|
case ESP_OTA_IMG_ABORTED: msg = "aborted"; break;
|
|
|
|
case ESP_OTA_IMG_UNDEFINED: // fall-through
|
|
|
|
default: msg = "undefined"; break;
|
|
|
|
}
|
|
|
|
lua_pushstring (L, msg);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto next; // just add an empty table for this slot
|
|
|
|
|
|
|
|
esp_app_desc_t desc;
|
|
|
|
err = esp_ota_get_partition_description(part, &desc);
|
|
|
|
|
|
|
|
if (err == ESP_OK)
|
|
|
|
{
|
|
|
|
lua_pushliteral (L, "name");
|
|
|
|
lua_pushstring (L, desc.project_name);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
|
|
|
|
lua_pushliteral (L, "version");
|
|
|
|
lua_pushstring (L, desc.version);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
|
|
|
|
lua_pushliteral (L, "secure_version");
|
|
|
|
lua_pushinteger (L, desc.secure_version);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
|
|
|
|
lua_pushliteral (L, "date");
|
|
|
|
lua_pushstring (L, desc.date);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
|
|
|
|
lua_pushliteral (L, "time");
|
|
|
|
lua_pushstring (L, desc.time);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
|
|
|
|
lua_pushliteral (L, "idf_version");
|
|
|
|
lua_pushstring (L, desc.idf_ver);
|
|
|
|
lua_settable (L, -3);
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
lua_settable (L, -3); // info table into return arg #3 table
|
|
|
|
}
|
|
|
|
iter = esp_partition_next (iter);
|
|
|
|
}
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-21 17:39:54 +02:00
|
|
|
LROT_BEGIN(otaupgrade, NULL, 0)
|
2019-07-22 11:13:43 +02:00
|
|
|
LROT_FUNCENTRY( commence, lotaupgrade_commence )
|
|
|
|
LROT_FUNCENTRY( write, lotaupgrade_write )
|
|
|
|
LROT_FUNCENTRY( complete, lotaupgrade_complete )
|
|
|
|
LROT_FUNCENTRY( accept, lotaupgrade_accept )
|
|
|
|
LROT_FUNCENTRY( rollback, lotaupgrade_rollback )
|
|
|
|
LROT_FUNCENTRY( info, lotaupgrade_info )
|
2021-08-21 17:39:54 +02:00
|
|
|
LROT_END(otaupgrade, NULL, 0)
|
2019-07-22 11:13:43 +02:00
|
|
|
|
|
|
|
NODEMCU_MODULE(OTAUPGRADE, "otaupgrade", otaupgrade, NULL);
|