-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
857 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# | ||
# Flash bootloader from URL or filesystem | ||
# | ||
|
||
class bootloader | ||
static var _addr = [0x1000, 0x0000] # possible addresses for bootloader | ||
static var _sign = bytes('E9') # signature of the bootloader | ||
static var _addr_high = 0x8000 # address of next partition after bootloader | ||
|
||
# get the bootloader address, 0x1000 for Xtensa based, 0x0000 for RISC-V based (but might have some exception) | ||
# we prefer to probed what's already in place rather than manage a hardcoded list of architectures | ||
# (there is a low risk of collision if the address is 0x0000 and offset 0x1000 is actually E9) | ||
def get_bootloader_address() | ||
import flash | ||
# let's see where we find 0xE9, trying first 0x1000 then 0x0000 | ||
for addr : self._addr | ||
if flash.read(addr, size(self._sign)) == self._sign | ||
return addr | ||
end | ||
end | ||
return nil | ||
end | ||
|
||
# | ||
# download from URL and store to `bootloader.bin` | ||
# | ||
def download(url) | ||
# address to flash the bootloader | ||
var addr = self.get_bootloader_address() | ||
if addr == nil raise "internal_error", "can't find address for bootloader" end | ||
|
||
var cl = webclient() | ||
cl.begin(url) | ||
var r = cl.GET() | ||
if r != 200 raise "network_error", "GET returned "+str(r) end | ||
var bl_size = cl.get_size() | ||
if bl_size <= 8291 raise "internal_error", "wrong bootloader size "+str(bl_size) end | ||
if bl_size > (0x8000 - addr) raise "internal_error", "bootloader is too large "+str(bl_size / 1024)+"kB" end | ||
|
||
cl.write_file("bootloader.bin") | ||
cl.close() | ||
end | ||
|
||
# returns true if ok | ||
def flash(url) | ||
var fname = "bootloader.bin" # default local name | ||
if url != nil | ||
if url[0..3] == "http" # if starts with 'http' download | ||
self.download(url) | ||
else | ||
fname = url # else get from file system | ||
end | ||
end | ||
# address to flash the bootloader | ||
var addr = self.get_bootloader_address() | ||
if addr == nil tasmota.log("OTA: can't find address for bootloader", 2) return false end | ||
|
||
var bl = open(fname, "r") | ||
if bl.readbytes(size(self._sign)) != self._sign | ||
tasmota.log("OTA: file does not contain a bootloader signature", 2) | ||
return false | ||
end | ||
bl.seek(0) # reset to start of file | ||
|
||
var bl_size = bl.size() | ||
if bl_size <= 8291 tasmota.log("OTA: wrong bootloader size "+str(bl_size), 2) return false end | ||
if bl_size > (0x8000 - addr) tasmota.log("OTA: bootloader is too large "+str(bl_size / 1024)+"kB", 2) return false end | ||
|
||
tasmota.log("OTA: Flashing bootloader", 2) | ||
# from now on there is no turning back, any failure means a bricked device | ||
import flash | ||
# read current value for bytes 2/3 | ||
var cur_config = flash.read(addr, 4) | ||
|
||
flash.erase(addr, self._addr_high - addr) # erase the bootloader | ||
var buf = bl.readbytes(0x1000) # read by chunks of 4kb | ||
# put back signature | ||
buf[2] = cur_config[2] | ||
buf[3] = cur_config[3] | ||
while size(buf) > 0 | ||
flash.write(addr, buf, true) # set flag to no-erase since we already erased it | ||
addr += size(buf) | ||
buf = bl.readbytes(0x1000) # read next chunk | ||
end | ||
bl.close() | ||
tasmota.log("OTA: Booloader flashed, please restart", 2) | ||
return true | ||
end | ||
end | ||
|
||
return bootloader | ||
|
||
#- | ||
### FLASH | ||
import bootloader | ||
bootloader().flash('https://raw.githubusercontent.com/espressif/arduino-esp32/master/tools/sdk/esp32/bin/bootloader_dio_40m.bin') | ||
#bootloader().flash('https://raw.githubusercontent.com/espressif/arduino-esp32/master/tools/sdk/esp32/bin/bootloader_dout_40m.bin') | ||
### FLASH from local file | ||
bootloader().flash("bootloader-tasmota-c3.bin") | ||
#### debug only | ||
bl = bootloader() | ||
print(format("0x%04X", bl.get_bootloader_address())) | ||
-# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# migration script for Shelly | ||
|
||
# simple function to copy from autoconfig archive to filesystem | ||
# return true if ok | ||
def cp(from, to) | ||
import path | ||
if to == nil to = from end # to is optional | ||
if !path.exists(to) | ||
try | ||
# tasmota.log("f_in="+tasmota.wd + from) | ||
var f_in = open(tasmota.wd + from) | ||
var f_out = open(to, "w") | ||
var f_content = f_in.readbytes(0x2000) # read by chunks of 8kb | ||
while size(f_content) > 0 | ||
f_out.write(f_content) | ||
f_content = f_in.readbytes(0x2000) # read next chunk | ||
end | ||
f_in.close() | ||
f_out.close() | ||
except .. as e,m | ||
tasmota.log("OTA: Couldn't copy "+to+" "+e+" "+m,2) | ||
return false | ||
end | ||
return true | ||
end | ||
return true | ||
end | ||
|
||
def copy_ota(from_addr, to_addr, sz) | ||
import flash | ||
import string | ||
var size_left = sz | ||
var offset = 0 | ||
|
||
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) | ||
flash.write(to_addr + offset, b, true) | ||
size_left -= 4096 | ||
offset += 4096 | ||
if ((offset-4096) / 102400) < (offset / 102400) | ||
tasmota.log(string.format("UPL: Progress %ikB", offset/1024), 3) | ||
end | ||
end | ||
tasmota.log("UPL: done", 2) | ||
end | ||
|
||
# make some room if there are some leftovers from shelly | ||
import path | ||
path.remove("index.html.gz") | ||
|
||
# copy some files from autoconf to filesystem | ||
var ok | ||
ok = cp("bootloader-tasmota-c3.bin") | ||
ok = cp("Partition_Wizard.tapp") | ||
|
||
# use an alternative to partition_core that can read Shelly's otadata | ||
tasmota.log("OTA: loading "+tasmota.wd + "partition_core_shelly.be", 2) | ||
load(tasmota.wd + "partition_core_shelly.be") | ||
|
||
# load bootloader flasher | ||
tasmota.log("OTA: loading "+tasmota.wd + "bootloader.be", 2) | ||
load(tasmota.wd + "bootloader.be") | ||
|
||
|
||
# all good | ||
if ok | ||
# do some basic check that the bootloader is not already in place | ||
import flash | ||
if flash.read(0x1000, 4) == bytes('CD3F6395') | ||
tasmota.log("OTA: bootloader already in place, not flashing it") | ||
else | ||
ok = global.bootloader().flash("bootloader-tasmota-c3.bin") | ||
end | ||
if ok | ||
var p = global.partition_core_shelly.Partition() | ||
var app0 = p.get_ota_slot(0) | ||
var app1 = p.get_ota_slot(1) | ||
var app0_size = app0.get_image_size() | ||
var app1_size = app1.get_image_size() | ||
# check if we get some Tasmota signature in slot 1 | ||
if (flash.read(p.get_ota_slot(1).start + 16, 4) == bytes("00FFFF00")) | ||
copy_ota(app1.start, app0.start, app1_size) | ||
elif (flash.read(p.get_ota_slot(0).start + 16, 4) == bytes("00FFFF00")) | ||
copy_ota(app0.start, app1.start, app0_size) | ||
end | ||
var otadata_offset = p.otadata.offset | ||
flash.erase(otadata_offset, 0x2000) | ||
tasmota.log("OTA: Shelly migration successful", 2) | ||
end | ||
end | ||
|
||
# dump logs to file | ||
var lr = tasmota_log_reader() | ||
var f_logs = open("migration_logs.txt", "w") | ||
var logs = lr.get_log(2) | ||
while logs != nil | ||
f_logs.write(logs) | ||
logs = lr.get_log(2) | ||
end | ||
f_logs.close() | ||
|
||
# Done |
Oops, something went wrong.