Fix to Partition_Wizard for shelly (#19056)

This commit is contained in:
s-hadinger 2023-07-06 20:59:50 +02:00 committed by GitHub
parent f462fa772d
commit f56307e321
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 181 additions and 94 deletions

View File

@ -300,8 +300,8 @@ class Partition_otadata
#- load otadata from SPI Flash -#
def load()
import flash
var otadata0 = flash.read(0xE000, 32)
var otadata1 = flash.read(0xF000, 32)
var otadata0 = flash.read(self.offset, 32)
var otadata1 = flash.read(self.offset + 0x1000, 32)
self.seq0 = otadata0.get(0, 4) #- ota_seq for block 1 -#
self.seq1 = otadata1.get(0, 4) #- ota_seq for block 2 -#
var valid0 = otadata0.get(28, 4) == self.crc32_ota_seq(self.seq0) #- is CRC32 valid? -#

View File

@ -248,65 +248,68 @@ be_local_closure(Partition_otadata_load, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 8]) { /* constants */
( &(const bvalue[ 9]) { /* constants */
/* K0 */ be_nested_str(flash),
/* K1 */ be_nested_str(read),
/* K2 */ be_nested_str(seq0),
/* K3 */ be_nested_str(get),
/* K4 */ be_const_int(0),
/* K5 */ be_nested_str(seq1),
/* K6 */ be_nested_str(crc32_ota_seq),
/* K7 */ be_nested_str(_validate),
/* K2 */ be_nested_str(offset),
/* K3 */ be_nested_str(seq0),
/* K4 */ be_nested_str(get),
/* K5 */ be_const_int(0),
/* K6 */ be_nested_str(seq1),
/* K7 */ be_nested_str(crc32_ota_seq),
/* K8 */ be_nested_str(_validate),
}),
&be_const_str_load,
&be_const_str_solidified,
( &(const binstruction[46]) { /* code */
( &(const binstruction[48]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x8C080301, // 0001 GETMET R2 R1 K1
0x5412DFFF, // 0002 LDINT R4 57344
0x88100102, // 0002 GETMBR R4 R0 K2
0x5416001F, // 0003 LDINT R5 32
0x7C080600, // 0004 CALL R2 3
0x8C0C0301, // 0005 GETMET R3 R1 K1
0x5416EFFF, // 0006 LDINT R5 61440
0x541A001F, // 0007 LDINT R6 32
0x7C0C0600, // 0008 CALL R3 3
0x8C100503, // 0009 GETMET R4 R2 K3
0x58180004, // 000A LDCONST R6 K4
0x541E0003, // 000B LDINT R7 4
0x7C100600, // 000C CALL R4 3
0x90020404, // 000D SETMBR R0 K2 R4
0x8C100703, // 000E GETMET R4 R3 K3
0x58180004, // 000F LDCONST R6 K4
0x541E0003, // 0010 LDINT R7 4
0x7C100600, // 0011 CALL R4 3
0x90020A04, // 0012 SETMBR R0 K5 R4
0x8C100503, // 0013 GETMET R4 R2 K3
0x541A001B, // 0014 LDINT R6 28
0x541E0003, // 0015 LDINT R7 4
0x7C100600, // 0016 CALL R4 3
0x8C140106, // 0017 GETMET R5 R0 K6
0x881C0102, // 0018 GETMBR R7 R0 K2
0x7C140400, // 0019 CALL R5 2
0x1C100805, // 001A EQ R4 R4 R5
0x8C140703, // 001B GETMET R5 R3 K3
0x541E001B, // 001C LDINT R7 28
0x54220003, // 001D LDINT R8 4
0x7C140600, // 001E CALL R5 3
0x8C180106, // 001F GETMET R6 R0 K6
0x88200105, // 0020 GETMBR R8 R0 K5
0x7C180400, // 0021 CALL R6 2
0x1C140A06, // 0022 EQ R5 R5 R6
0x5C180800, // 0023 MOVE R6 R4
0x741A0001, // 0024 JMPT R6 #0027
0x4C180000, // 0025 LDNIL R6
0x90020406, // 0026 SETMBR R0 K2 R6
0x5C180A00, // 0027 MOVE R6 R5
0x741A0001, // 0028 JMPT R6 #002B
0x4C180000, // 0029 LDNIL R6
0x90020A06, // 002A SETMBR R0 K5 R6
0x8C180107, // 002B GETMET R6 R0 K7
0x7C180200, // 002C CALL R6 1
0x80000000, // 002D RET 0
0x88140102, // 0006 GETMBR R5 R0 K2
0x541A0FFF, // 0007 LDINT R6 4096
0x00140A06, // 0008 ADD R5 R5 R6
0x541A001F, // 0009 LDINT R6 32
0x7C0C0600, // 000A CALL R3 3
0x8C100504, // 000B GETMET R4 R2 K4
0x58180005, // 000C LDCONST R6 K5
0x541E0003, // 000D LDINT R7 4
0x7C100600, // 000E CALL R4 3
0x90020604, // 000F SETMBR R0 K3 R4
0x8C100704, // 0010 GETMET R4 R3 K4
0x58180005, // 0011 LDCONST R6 K5
0x541E0003, // 0012 LDINT R7 4
0x7C100600, // 0013 CALL R4 3
0x90020C04, // 0014 SETMBR R0 K6 R4
0x8C100504, // 0015 GETMET R4 R2 K4
0x541A001B, // 0016 LDINT R6 28
0x541E0003, // 0017 LDINT R7 4
0x7C100600, // 0018 CALL R4 3
0x8C140107, // 0019 GETMET R5 R0 K7
0x881C0103, // 001A GETMBR R7 R0 K3
0x7C140400, // 001B CALL R5 2
0x1C100805, // 001C EQ R4 R4 R5
0x8C140704, // 001D GETMET R5 R3 K4
0x541E001B, // 001E LDINT R7 28
0x54220003, // 001F LDINT R8 4
0x7C140600, // 0020 CALL R5 3
0x8C180107, // 0021 GETMET R6 R0 K7
0x88200106, // 0022 GETMBR R8 R0 K6
0x7C180400, // 0023 CALL R6 2
0x1C140A06, // 0024 EQ R5 R5 R6
0x5C180800, // 0025 MOVE R6 R4
0x741A0001, // 0026 JMPT R6 #0029
0x4C180000, // 0027 LDNIL R6
0x90020606, // 0028 SETMBR R0 K3 R6
0x5C180A00, // 0029 MOVE R6 R5
0x741A0001, // 002A JMPT R6 #002D
0x4C180000, // 002B LDNIL R6
0x90020C06, // 002C SETMBR R0 K6 R6
0x8C180108, // 002D GETMET R6 R0 K8
0x7C180200, // 002E CALL R6 1
0x80000000, // 002F RET 0
})
)
);

View File

@ -24,25 +24,49 @@ class Partition_wizard_UI
if persist.find("factory_migrate") == true
# remove marker to avoid bootloop if something goes wrong
tasmota.log("UPL: Resuming after step 1", 2)
persist.remove("factory_migrate")
persist.save()
# continue the migration process 5 seconds after Wifi is connected
def continue_after_5s()
tasmota.remove_rule("parwiz_5s") # first remove rule to avoid firing it again at Wifi reconnect
tasmota.remove_rule("parwiz_5s1") # first remove rule to avoid firing it again at Wifi reconnect
tasmota.remove_rule("parwiz_5s2") # first remove rule to avoid firing it again at Wifi reconnect
tasmota.set_timer(5000, /-> self.do_safeboot_partitioning()) # delay by 5 s
end
tasmota.add_rule("Wifi#Connected=1", continue_after_5s, "parwiz_5s")
tasmota.add_rule("Wifi#Connected=1", continue_after_5s, "parwiz_5s1")
tasmota.add_rule("Wifi#Connected==1", continue_after_5s, "parwiz_5s2")
end
end
# ----------------------------------------------------------------------
# Patch partition core since we can't chang the solidified code
# ----------------------------------------------------------------------
def patch_partition_core(p)
var otadata = p.otadata
# patch load
import flash
var otadata0 = flash.read(otadata.offset, 32)
var otadata1 = flash.read(otadata.offset + 0x1000, 32)
otadata.seq0 = otadata0.get(0, 4) #- ota_seq for block 1 -#
otadata.seq1 = otadata1.get(0, 4) #- ota_seq for block 2 -#
var valid0 = otadata0.get(28, 4) == otadata.crc32_ota_seq(otadata.seq0) #- is CRC32 valid? -#
var valid1 = otadata1.get(28, 4) == otadata.crc32_ota_seq(otadata.seq1) #- is CRC32 valid? -#
if !valid0 otadata.seq0 = nil end
if !valid1 otadata.seq1 = nil end
otadata._validate()
end
def default_safeboot_URL()
import string
var arch_sub = tasmota.arch()
if arch_sub[0..4] == "esp32"
arch_sub = arch_sub[5..] # get the esp32 variant
end
return format(self._default_safeboot_URL, arch_sub)
return string.format(self._default_safeboot_URL, arch_sub)
end
# create a method for adding a button to the main menu
@ -53,15 +77,34 @@ class Partition_wizard_UI
"<form id=but_part_mgr style='display: block;' action='part_wiz' method='get'><button>Partition Wizard</button></form><p></p>")
end
# ----------------------------------------------------------------------
# Get last fs
#
# Get the last fs partition
# Return the actual slot
# ----------------------------------------------------------------------
def get_last_fs(p)
var sz = size(p.slots)
var idx = 1
while idx < sz
var slot = p.slots[-idx]
if slot.is_spiffs()
return slot
end
idx += 1
end
return nil
end
#- ---------------------------------------------------------------------- -#
#- Get fs unallocated size
#- ---------------------------------------------------------------------- -#
def get_unallocated_k(p)
var last_slot = p.slots[-1]
if last_slot.is_spiffs()
var last_fs = self.get_last_fs(p)
if last_fs != nil
# verify that last slot is filesystem
var flash_size_k = self.get_max_flash_size_k(p)
var partition_end_k = (last_slot.start + last_slot.sz) / 1024 # last kb used for fs
var partition_end_k = (last_fs.start + last_fs.sz) / 1024 # last kb used for fs
if partition_end_k < flash_size_k
return flash_size_k - partition_end_k
end
@ -73,8 +116,8 @@ class Partition_wizard_UI
#- Get max fs start address when expanded to maximum
#- ---------------------------------------------------------------------- -#
def get_max_fs_start_k(p)
var last_slot = p.slots[-1]
if last_slot.is_spiffs() # verify that last slot is filesystem
var last_fs = p.slots[-1]
if last_fs != nil # verify that last slot is filesystem
# get end of previous partition slot
var last_app = p.slots[-2]
# round upper 64kB
@ -85,7 +128,7 @@ class Partition_wizard_UI
end
#- ---------------------------------------------------------------------- -#
#- Get max falsh size
#- Get max flash size
#
# Takes into account that the flash size written may not be accurate
# and the flash chip may be larger
@ -99,15 +142,40 @@ class Partition_wizard_UI
return flash_size_k
end
# ----------------------------------------------------------------------
# Remove any non wanted partion after last FS
# ----------------------------------------------------------------------
def remove_partition_after_last_fs(p)
# remove any partition after last fs
do
var last_fs = self.get_last_fs(p)
var changed = false
if last_fs != nil
while true
var last_slot = p.slots[-1]
if !last_slot.is_spiffs() && (last_slot.type != 0)
p.slots.remove(size(p.slots) - 1) # remove last slot
changed = true
else
break
end
end
if changed p.save() end
end
end
end
#- ---------------------------------------------------------------------- -#
#- Resize flash definition if needed
#- ---------------------------------------------------------------------- -#
def resize_max_flash_size_k(p)
self.remove_partition_after_last_fs(p)
var flash_size_k = tasmota.memory()['flash']
var flash_size_real_k = tasmota.memory().find("flash_real", flash_size_k)
var flash_definition_sector = self.get_flash_definition_sector(p)
if (flash_size_k != flash_size_real_k) && flash_definition_sector != nil
import flash
import string
flash_size_k = flash_size_real_k # try to expand the flash size definition
@ -131,7 +199,7 @@ class Partition_wizard_UI
var old_def = flash_def[3]
flash_def[3] = (flash_def[3] & 0x0F) | flash_size_code
flash.write(flash_definition_sector, flash_def)
tasmota.log(format("UPL: changing flash definition from 0x02X to 0x%02X", old_def, flash_def[3]), 3)
tasmota.log(string.format("UPL: changing flash definition from 0x02X to 0x%02X", old_def, flash_def[3]), 3)
else
raise "internal_error", "wrong flash size "+str(flash_size_real_m)
end
@ -142,9 +210,9 @@ class Partition_wizard_UI
#- Get current fs size
#- ---------------------------------------------------------------------- -#
def get_cur_fs_size_k(p)
var last_slot = p.slots[-1]
if last_slot.is_spiffs() # verify that last slot is filesystem
return (last_slot.sz + 1023) / 1024
var last_fs = p.slots[-1]
if last_fs != nil
return (last_fs.sz + 1023) / 1024
end
return 0
end
@ -171,13 +239,14 @@ class Partition_wizard_UI
#- ---------------------------------------------------------------------- -#
def show_resize_fs(p)
import webserver
import string
var unallocated = self.get_unallocated_k(p)
# if there is unallocated space, propose only to claim it
if unallocated > 0
webserver.content_send("<fieldset><legend><b>&nbsp;Resize FS to max&nbsp;</b></legend><p></p>")
webserver.content_send(format("<p>You can expand the file system by %i KB.<br>Its content will be lost.</p>", unallocated))
webserver.content_send(string.format("<p>You can expand the file system by %i KB.<br>Its content will be lost.</p>", unallocated))
webserver.content_send("<form action='/part_wiz' method='post' ")
webserver.content_send("onsubmit='return confirm(\"This will DELETE the content of the file system and cause a restart.\");'>")
@ -190,7 +259,7 @@ class Partition_wizard_UI
var flash_size_k = self.get_max_flash_size_k()
var fs_max_size_k = flash_size_k - max_fs_start_k
var current_fs_size_k = self.get_cur_fs_size_k(p)
#print(format(">>> max_fs_start_k=0x%X flash_size_k=0x%X fs_max_size_k=%i current_fs_size_k=%i", max_fs_start_k, flash_size_k, fs_max_size_k, current_fs_size_k))
#print(string.format(">>> max_fs_start_k=0x%X flash_size_k=0x%X fs_max_size_k=%i current_fs_size_k=%i", max_fs_start_k, flash_size_k, fs_max_size_k, current_fs_size_k))
if max_fs_start_k > 0 && fs_max_size_k > 64
webserver.content_send("<fieldset><legend><b>&nbsp;Resize FS&nbsp;</b></legend><p></p>")
@ -199,7 +268,7 @@ class Partition_wizard_UI
webserver.content_send("<form action='/part_wiz' method='post' ")
webserver.content_send("onsubmit='return confirm(\"This will DELETE the content of the file system and cause a restart.\");'>")
webserver.content_send(format("<input type='number' min='64' max='%d' step='64' name='fs_size' value='%i'>", fs_max_size_k, current_fs_size_k))
webserver.content_send(string.format("<input type='number' min='64' max='%d' step='64' name='fs_size' value='%i'>", fs_max_size_k, current_fs_size_k))
webserver.content_send("<p></p><button name='resize_fs' class='button bred'>Resize FS</button></form></p>")
webserver.content_send("<p></p></fieldset><p></p>")
@ -231,7 +300,7 @@ class Partition_wizard_UI
def factory_migrate_eligible(p)
if p.ota_max() <= 0 return false end # device does not have 2x OTA
if p.get_factory_slot() != nil return false end
if !p.slots[-1].is_spiffs() return false end
if self.get_last_fs(p) == nil return false end
return true # device does not have factory partition
end
@ -254,11 +323,12 @@ class Partition_wizard_UI
# - true if DONE
# - string if ERROR, indicating the error
def test_step_1(p)
import string
if !self.factory_migrate_eligible(p) return "not eligible to migration" end
var cur_part = p.otadata.active_otadata # -1=factory 0=ota_0 1=ota_1...
if cur_part == 1 return true end
if cur_part != 0 return format("active_otadata=%i", cur_part) end # unsupported configuration
if cur_part != 0 return string.format("active_otadata=%i", cur_part) end # unsupported configuration
# current partition is `app0`
# get size of firmware in `app0` and check if it fits on `app1`
var app0 = p.get_ota_slot(0)
@ -314,6 +384,7 @@ class Partition_wizard_UI
# `app0` changed subtype to `factory`
# `app1` moved to right after `factory` and resized
# `app1` changed subtype to `app0` and renamed `app0`
# remove any partition past the last fs
#
# Returns:
# - false if READY
@ -345,10 +416,11 @@ class Partition_wizard_UI
static def copy_ota(from_addr, to_addr, sz)
import flash
import string
var size_left = sz
var offset = 0
tasmota.log(format("UPL: Copy flash from 0x%06X to 0x%06X (size: %ikB)", from_addr, to_addr, sz / 1024), 2)
tasmota.log(string.format("UPL: Copy flash from 0x%06X to 0x%06X (size: %ikB)", from_addr, to_addr, sz / 1024), 2)
while size_left > 0
var b = flash.read(from_addr + offset, 4096)
flash.erase(to_addr + offset, 4096)
@ -356,13 +428,14 @@ class Partition_wizard_UI
size_left -= 4096
offset += 4096
if ((offset-4096) / 102400) < (offset / 102400)
tasmota.log(format("UPL: Progress %ikB", offset/1024), 3)
tasmota.log(string.format("UPL: Progress %ikB", offset/1024), 3)
end
end
tasmota.log("UPL: done", 2)
end
def do_step_1(p)
import persist
var step1_state = self.test_step_1(p)
if step1_state == true return true end
if type(step1_state) == 'string)' raise "internal_error", step1_state end
@ -377,11 +450,15 @@ class Partition_wizard_UI
p.set_active(1)
p.save()
persist.factory_migrate = true
persist.save()
tasmota.log("UPL: restarting on `app1`", 2)
tasmota.cmd("Restart 1")
end
def do_step_2(p, safeboot_url)
import string
if safeboot_url == nil || safeboot_url == ""
safeboot_url = self.default_safeboot_URL()
tasmota.log("UPL: no `safeboot` URL, defaulting to "+safeboot_url, 2)
@ -399,7 +476,7 @@ class Partition_wizard_UI
var safeboot_size = cl.get_size()
if safeboot_size <= 500000 raise "internal_error", "wrong safeboot size "+str(safeboot_size) end
if safeboot_size > (self.app_size_min * 1024) raise "internal_error", "safeboot is too large "+str(safeboot_size / 1024)+"kB" end
tasmota.log(format("UPL: flashing `safeboot` from %s %ikB", safeboot_url, (safeboot_size / 1024) + 1), 2)
tasmota.log(string.format("UPL: flashing `safeboot` from %s %ikB", safeboot_url, (safeboot_size / 1024) + 1), 2)
var app0 = p.get_ota_slot(0)
if app0.start != 0x10000 raise "internal_error", "`app0` offset is not 0x10000" end
cl.write_flash(app0.start)
@ -415,6 +492,9 @@ class Partition_wizard_UI
if step3_state == true return true end
if type(step3_state) == 'string' raise "internal_error", step3_state end
# remove any partition after last fs
self.remove_partition_after_last_fs(p)
var app0 = p.get_ota_slot(0)
var app1 = p.get_ota_slot(1)
if app0 == nil || app1 == nil raise "internal_error", "there are no `app0` or `app1` partitions" end
@ -479,6 +559,7 @@ class Partition_wizard_UI
def show_migrate_to_factory(p)
# display ota partitions
import webserver
import string
if !self.factory_migrate_eligible(p) return end
@ -488,20 +569,20 @@ class Partition_wizard_UI
webserver.content_send("<p>Please see <a href='https://tasmota.github.io/docs/Safeboot/' target='_blank'>Safeboot layout documentation</a></p>")
webserver.content_send("<p>&nbsp;</p>")
webserver.content_send(format("<p>Step 1: %s</p>", self.display_step_state(self.test_step_1(p), "boot on `app1`")))
webserver.content_send(format("<p>Step 2: %s</p>", self.display_step_state(self.test_step_2(p), "flash `safeboot` to `app0`")))
webserver.content_send(format("<p>Step 3: %s</p>", self.display_step_state(self.test_step_3(p), "change partition map")))
webserver.content_send(format("<p>Step 4: %s</p>", self.display_step_state(self.test_step_4(p), "flash final firmware")))
webserver.content_send(string.format("<p>Step 1: %s</p>", self.display_step_state(self.test_step_1(p), "boot on `app1`")))
webserver.content_send(string.format("<p>Step 2: %s</p>", self.display_step_state(self.test_step_2(p), "flash `safeboot` to `app0`")))
webserver.content_send(string.format("<p>Step 3: %s</p>", self.display_step_state(self.test_step_3(p), "change partition map")))
webserver.content_send(string.format("<p>Step 4: %s</p>", self.display_step_state(self.test_step_4(p), "flash final firmware")))
webserver.content_send("<form action='/part_wiz' method='post' ")
webserver.content_send("onsubmit='return confirm(\"This will causes multiple restarts.\");'>")
var ota_url = tasmota.cmd("OtaUrl").find("OtaUrl", "")
webserver.content_send(format("<br><b>OTA Url</b><br><input id='o1' placeholder='OTA_URL' value='%s'><br>",
webserver.content_send(string.format("<br><b>OTA Url</b><br><input id='o1' placeholder='OTA_URL' value='%s'><br>",
ota_url))
import persist
var safeboot_url = persist.find("safeboot_url", self.default_safeboot_URL())
webserver.content_send(format("<br><b>SAFEBOOT Url</b> (don't change)<input id='o2' placeholder='SAFEBOOT_URL' value='%s'><br>",
webserver.content_send(string.format("<br><b>SAFEBOOT Url</b> (don't change)<input id='o2' placeholder='SAFEBOOT_URL' value='%s'><br>",
safeboot_url))
webserver.content_send("<p></p><button name='factory' class='button bred'>Start migration</button></form></p>")
@ -515,6 +596,7 @@ class Partition_wizard_UI
def show_current_partitions(p)
# display ota partitions
import webserver
import string
var cur_part = p.otadata.active_otadata # -1=factory 0=ota_0 1=ota_1...
webserver.content_send("<fieldset><legend><b>&nbsp;Current partitions&nbsp;</b></legend><p></p><table>")
@ -531,22 +613,22 @@ class Partition_wizard_UI
var usage_str = "unknown"
var used = slot.get_image_size()
if (used >= 0) && (used <= slot.sz)
usage_str = format("used %i%%", ((used / 1024) * 100) / (slot.sz / 1024))
usage_str = string.format("used %i%%", ((used / 1024) * 100) / (slot.sz / 1024))
end
var title = format("%ssubtype:%s offset:0x%06X size:0x%06X", current_boot_partition ? "booted " : "", slot.subtype_to_string(), slot.start, slot.sz)
var title = string.format("%ssubtype:%s offset:0x%06X size:0x%06X", current_boot_partition ? "booted " : "", slot.subtype_to_string(), slot.start, slot.sz)
var col_before = ""
var col_after = ""
if current_boot_partition
col_before = "<span style='color:#0F0'>["
col_after = "]</span>"
end
# webserver.content_send(format("<p><b>%s</b> [%s]: %i KB (%s)</p>", slot.label, slot.subtype_to_string(), slot.size / 1024, usage_str))
webserver.content_send(format("<tr><td title='%s'><b>%s%s%s</b>:&nbsp;</td><td align='right'> %i KB </td><td>&nbsp;(%s)</td></tr>",
# webserver.content_send(string.format("<p><b>%s</b> [%s]: %i KB (%s)</p>", slot.label, slot.subtype_to_string(), slot.size / 1024, usage_str))
webserver.content_send(string.format("<tr><td title='%s'><b>%s%s%s</b>:&nbsp;</td><td align='right'> %i KB </td><td>&nbsp;(%s)</td></tr>",
title, col_before, slot.label, col_after, slot.sz / 1024, usage_str))
elif slot.is_spiffs()
# spiffs partition
var title = format("subtype:%s offset:0x%06X size:0x%06X", slot.subtype_to_string(), slot.start, slot.sz)
webserver.content_send(format("<tr><td title='%s'><b>fs</b>:&nbsp;</td><td align='right'> %i KB</td></tr>", title, slot.sz / 1024))
var title = string.format("subtype:%s offset:0x%06X size:0x%06X", slot.subtype_to_string(), slot.start, slot.sz)
webserver.content_send(string.format("<tr><td title='%s'><b>fs</b>:&nbsp;</td><td align='right'> %i KB</td></tr>", title, slot.sz / 1024))
end
end
@ -555,7 +637,7 @@ class Partition_wizard_UI
var last_slot = p.slots[-1]
# verify that last slot is file-system
var partition_end_k = (last_slot.start + last_slot.sz) / 1024 # last kb used for fs
webserver.content_send(format("<tr><td title='offset:0x%06X size:0x%06X'>&lt;free&gt;:&nbsp;</td><td align='right'> %i KB</td></tr>",
webserver.content_send(string.format("<tr><td title='offset:0x%06X size:0x%06X'>&lt;free&gt;:&nbsp;</td><td align='right'> %i KB</td></tr>",
partition_end_k * 1024, unallocated * 1024, unallocated))
end
webserver.content_send("</table>")
@ -577,6 +659,7 @@ class Partition_wizard_UI
import partition_core
if !webserver.check_privileged_access() return nil end
var p = partition_core.Partition() # load partition layout
self.patch_partition_core(p)
webserver.content_start("Partition Wizard") #- title of the web page -#
webserver.content_send_style() #- send standard Tasmota styles -#
@ -601,6 +684,7 @@ class Partition_wizard_UI
#######################################################################
def page_part_ctl()
import webserver
import string
if !webserver.check_privileged_access() return nil end
import partition_core
@ -609,6 +693,7 @@ class Partition_wizard_UI
#- check that the partition is valid -#
var p = partition_core.Partition()
self.patch_partition_core(p)
try
@ -647,7 +732,7 @@ class Partition_wizard_UI
var current_fs_size_k = self.get_cur_fs_size_k(p)
var fs_target = int(webserver.arg("fs_size"))
if (fs_target < 64) || (fs_target > fs_max_size_k) raise "value_error", format("Invalid FS #%d", fs_target) end
if (fs_target < 64) || (fs_target > fs_max_size_k) raise "value_error", string.format("Invalid FS #%d", fs_target) end
# apply the change
# shrink last OTA App
@ -685,12 +770,12 @@ class Partition_wizard_UI
raise "value_error", "Unknown command"
end
except .. as e, m
tasmota.log(format("BRY: Exception> '%s' - %s", e, m), 2)
tasmota.log(string.format("BRY: Exception> '%s' - %s", e, m), 2)
#- display error page -#
webserver.content_start("Parameter error") #- title of the web page -#
webserver.content_send_style() #- send standard Tasmota styles -#
webserver.content_send(format("<p style='width:340px;'><b>Exception:</b><br>'%s'<br>%s</p>", e, m))
webserver.content_send(string.format("<p style='width:340px;'><b>Exception:</b><br>'%s'<br>%s</p>", e, m))
# webserver.content_send("<p></p></fieldset><p></p>")
webserver.content_button(webserver.BUTTON_MANAGEMENT) #- button back to management page -#
@ -710,24 +795,23 @@ class Partition_wizard_UI
def do_safeboot_partitioning()
import webserver
import partition_core
import string
var p = partition_core.Partition() # load partition layout
self.patch_partition_core(p)
if !self.factory_migrate_eligible(p) return true end
# STEP 1
var step1_state = self.test_step_1(p)
if type(step1_state) == 'string' return step1_state end
if step1_state == false
import persist
tasmota.log("UPL: Starting step 1", 2)
try
self.do_step_1(p)
except .. as e, m
tasmota.log(format("UPL: error (%s) %s", e, m), 2)
tasmota.log(string.format("UPL: error (%s) %s", e, m), 2)
return m
end
persist.factory_migrate = true
persist.save()
return false
end
tasmota.log("UPL: Step 1 Done", 2)
@ -742,7 +826,7 @@ class Partition_wizard_UI
try
self.do_step_2(p, safeboot_url)
except .. as e, m
tasmota.log(format("UPL: error (%s) %s", e, m), 2)
tasmota.log(string.format("UPL: error (%s) %s", e, m), 2)
return m
end
end
@ -756,7 +840,7 @@ class Partition_wizard_UI
try
self.do_step_3(p)
except .. as e, m
tasmota.log(format("UPL: error (%s) %s", e, m), 2)
tasmota.log(string.format("UPL: error (%s) %s", e, m), 2)
return m
end
end