summaryrefslogtreecommitdiffstatshomepage
path: root/tests/esp32/partition_ota.py
diff options
context:
space:
mode:
authorThorsten von Eicken <tve@voneicken.com>2020-04-01 22:59:08 -0700
committerDamien George <damien.p.george@gmail.com>2020-05-03 15:00:45 +1000
commit952ff8a8ea9ae6128ff5225b180d8daaacf447e4 (patch)
treec69c41d01035ec4ee279a43f460c821cf1af04f3 /tests/esp32/partition_ota.py
parent7d97d241e861ba4cbd44d3695d4db6184974f8f9 (diff)
downloadmicropython-952ff8a8ea9ae6128ff5225b180d8daaacf447e4.tar.gz
micropython-952ff8a8ea9ae6128ff5225b180d8daaacf447e4.zip
esp32: Improve support for OTA updates.
This commit adds several small items to improve the support for OTA updates on an esp32: - a partition table for 4MB flash modules that has two OTA partitions ready to go to do updates - a GENERIC_OTA board that uses that partition table and that enables automatic roll-back in the bootloader - a new esp32.Partition.mark_app_valid_cancel_rollback() class-method to signal that the boot is successful and should not be rolled back at the next reset - an automated test for doing an OTA update - documentation updates
Diffstat (limited to 'tests/esp32/partition_ota.py')
-rw-r--r--tests/esp32/partition_ota.py117
1 files changed, 117 insertions, 0 deletions
diff --git a/tests/esp32/partition_ota.py b/tests/esp32/partition_ota.py
new file mode 100644
index 0000000000..765630c8ce
--- /dev/null
+++ b/tests/esp32/partition_ota.py
@@ -0,0 +1,117 @@
+# Test ESP32 OTA updates, including automatic roll-back.
+# Running this test requires firmware with an OTA Partition, such as the GENERIC_OTA "board".
+# This test also requires patience as it copies the boot partition into the other OTA slot.
+
+import machine
+from esp32 import Partition
+
+# start by checking that the running partition table has OTA partitions, 'cause if
+# it doesn't there's nothing we can test
+cur = Partition(Partition.RUNNING)
+cur_name = cur.info()[4]
+if not cur_name.startswith("ota_"):
+ print("SKIP")
+ raise SystemExit
+
+DEBUG = True
+
+
+def log(*args):
+ if DEBUG:
+ print(*args)
+
+
+# replace boot.py with the test code that will run on each reboot
+import uos
+
+try:
+ uos.rename("boot.py", "boot-orig.py")
+except:
+ pass
+with open("boot.py", "w") as f:
+ f.write("DEBUG=" + str(DEBUG))
+ f.write(
+ """
+import machine
+from esp32 import Partition
+cur = Partition(Partition.RUNNING)
+cur_name = cur.info()[4]
+
+def log(*args):
+ if DEBUG: print(*args)
+
+from step import STEP, EXPECT
+log("Running partition: " + cur_name + " STEP=" + str(STEP) + " EXPECT=" + EXPECT)
+if cur_name != EXPECT:
+ print("\\x04FAILED: step " + str(STEP) + " expected " + EXPECT + " got " + cur_name + "\\x04")
+
+if STEP == 0:
+ log("Not confirming boot ok and resetting back into first")
+ nxt = cur.get_next_update()
+ with open("step.py", "w") as f:
+ f.write("STEP=1\\nEXPECT=\\"" + nxt.info()[4] + "\\"\\n")
+ machine.reset()
+elif STEP == 1:
+ log("Booting into second partition again")
+ nxt = cur.get_next_update()
+ nxt.set_boot()
+ with open("step.py", "w") as f:
+ f.write("STEP=2\\nEXPECT=\\"" + nxt.info()[4] + "\\"\\n")
+ machine.reset()
+elif STEP == 2:
+ log("Confirming boot ok and rebooting into same partition")
+ Partition.mark_app_valid_cancel_rollback()
+ with open("step.py", "w") as f:
+ f.write("STEP=3\\nEXPECT=\\"" + cur_name + "\\"\\n")
+ machine.reset()
+elif STEP == 3:
+ log("Booting into original partition")
+ nxt = cur.get_next_update()
+ nxt.set_boot()
+ with open("step.py", "w") as f:
+ f.write("STEP=4\\nEXPECT=\\"" + nxt.info()[4] + "\\"\\n")
+ machine.reset()
+elif STEP == 4:
+ log("Confirming boot ok and DONE!")
+ Partition.mark_app_valid_cancel_rollback()
+ import uos
+ uos.remove("step.py")
+ uos.remove("boot.py")
+ uos.rename("boot-orig.py", "boot.py")
+ print("\\nSUCCESS!\\n\\x04\\x04")
+
+"""
+ )
+
+
+def copy_partition(src, dest):
+ log("Partition copy: {} --> {}".format(src.info(), dest.info()))
+ sz = src.info()[3]
+ if dest.info()[3] != sz:
+ raise ValueError("Sizes don't match: {} vs {}".format(sz, dest.info()[3]))
+ addr = 0
+ blk = bytearray(4096)
+ while addr < sz:
+ if sz - addr < 4096:
+ blk = blk[: sz - addr]
+ if addr & 0xFFFF == 0:
+ # need to show progress to run-tests else it times out
+ print(" ... 0x{:06x}".format(addr))
+ src.readblocks(addr >> 12, blk)
+ dest.writeblocks(addr >> 12, blk)
+ addr += len(blk)
+
+
+# get things started by copying the current partition into the next slot and rebooting
+print("Copying current to next partition")
+nxt = cur.get_next_update()
+copy_partition(cur, nxt)
+print("Partition copied, booting into it")
+nxt.set_boot()
+
+# the step.py file is used to keep track of state across reboots
+# EXPECT is the name of the partition we expect to reboot into
+with open("step.py", "w") as f:
+ f.write('STEP=0\nEXPECT="' + nxt.info()[4] + '"\n')
+
+machine.reset()