def safe_mode_act(boot_pin): if boot_pin.safe_mode: led_pin = boot_pin.led_pin led_on = boot_pin.led_on btn_pin = boot_pin.btn_pin reset_val = boot_pin.reset_val print("Pin Control: LED {}, BTN: {}".format(led_pin, btn_pin)) safe_pin = Pin(btn_pin, Pin.IN, Pin.PULL_DOWN) led_pin = Pin(led_pin, Pin.OUT) led_pin.value(led_on) print("Wait 5sec - Safe Mode") sleep(5) print("Safe Mode Activate: {}".format(safe_pin.value() == reset_val)) if safe_pin.value() == reset_val: led_pin.value(1 - led_on) Partition.set_boot(Partition('factory')) reset() sleep(1) led_pin.value(1 - led_on) else: print("Safe Mode: not present")
def __init__(self): self.part = Partition(Partition.RUNNING).get_next_update() self.sha = hashlib.sha256() self.seq = 0 self.block = 0 self.buf = bytearray(BLOCKLEN) self.buflen = 0
def get_current_partition_name(self): """ returns current partition name. Args: void. Returns: string with current partition name (ota_0 or ota_1). """ cur = Partition(Partition.RUNNING) return cur.info()[4]
def __init__(self, verbose=False): self.verbose = verbose # the partition we are writing to self.part = Partition(Partition.RUNNING).get_next_update() # sha of the new app, computed in _app_data self.sha = hashlib.sha256() # keeping track (_app_data) self.block = 0 self.buf = bytearray(BLOCKLEN) self.buflen = 0 # length of current content of self.buf
def __init__(self, _debug=True): self.debug = _debug self.update_file_pages_counter = 0 self.update_file_page_data = bytearray() current_partition = Partition(Partition.RUNNING) current_partition_name = current_partition.info()[4] self.plot_debug("current partition:" + str(current_partition.info())) if not current_partition_name.startswith( "ota_"): # firmware is adapted to OTA ? print( "memory_esp32: skipping... Partition table not adapted to OTA") raise SystemExit self.partition = current_partition.get_next_update() self.plot_debug("next partition:" + str(self.partition.info()))
def feed(): global first wdt.feed() if safemode and not revert: return elif first is None: return # done with safe mode stuff elif first == 0: first = time.ticks_ms() # record time of first feeding elif time.ticks_diff(time.ticks_ms(), first) > allok: if sys.platform == 'esp32': # mark the current partition as OK, this prevents rollback after OTA from esp32 import Partition part = Partition(Partition.RUNNING) part.mark_app_valid_cancel_rollback() if safemode: log.critical("Switching to NORMAL MODE via reset") reset(True) else: log.warning("Next reset: normal boot") normalboot(True) first = None
from esp32 import Partition bdev = Partition.find(Partition.TYPE_DATA, label="vfs") bdev = bdev[0] if bdev else None
''' import random from esp32 import Partition import esp import uos filename = "csv_data_file.txt" # Get some statistics: print( "Available flash space: ", esp.flash_size()) # This will give you the total amount of Flash available partition = Partition(Partition.RUNNING) print( partition.info() ) # Print out information about the running flash partition on which you can store your files. file_stats = uos.stat(filename) print( "File size before write: ", file_stats[6] ) # the item at index 6 of the tupple contains the total bytes in the file. # This loop will add 10 lines that contain dummy comma-delimited data. for x in range(10): random_temp = random.randint(0, 50) random_humi = random.randint(20, 90) random_pres = random.randint(900, 1100) # in hPa
def reboot(part="ota_0"): ota_0 = Partition(part) Partition.set_boot(ota_0) reset()
files = os.listdir() if '_manifest.json' in files: # have an new manifest ? make upgrade _manifest_file = open('_manifest.json', 'r') _manifest_str = _manifest_file.read() _manifest_file.close() try: _manifest_object = json.loads(_manifest_str) if _manifest_object['type'] == 'bin': print('monolithic upgrade identified.') _current_partition = Partition(Partition.RUNNING) if _manifest_object['ota'] == _current_partition.info( )[4]: # changed ota partition ? os.rename("_manifest.json", "manifest.json") print('update with success.') _updated = True else: print('failed to update.') os.remove('_manifest.json') else: print('diferential upgrade identified.') for file in files: if file[0] == '_': # is an update file (_xxx)
try: import boot_pin safe_mode_act(boot_pin) del (boot_pin) except Exception as e: print(e) pass # PARTITIONS // Path import sys import uos import gc bootpart = Partition(Partition.BOOT) runningpart = Partition(Partition.RUNNING) print("INFO - Partitions") print("Boot: {}".format(bootpart)) print("Run: {}".format(runningpart)) part_info = runningpart.info() part_name = part_info[4] try: uos.mkdir(part_name) except OSError as e: print("Path already exist") pass
# import esp from utime import sleep from machine import Pin, reset from esp32 import Partition import sys import uos import gc bootpart = Partition(Partition.BOOT) runningpart = Partition(Partition.RUNNING) print("INFO - Partitions") print("Boot: {}".format(bootpart)) print("Run: {}".format(runningpart)) # SAFE MODE safe_mode = False try: import boot_pin safe_mode = boot_pin.safe_mode print(safe_mode) except Exception: pass if safe_mode: print("Pin Control: LED {}, BTN: {}".format(boot_pin.led_pin, boot_pin.btn_pin))
if wlan.isconnected(): break time.sleep_ms(100) if not wlan.isconnected(): print("Unable to connect to WiFi!") wlan.disconnect() return print("IP", wlan.ifconfig()[0]) print("mDNS", mdns_name + ".local") # set clock to local time tm = time.localtime(ntptime.time() + getattr(secrets, 'tz_offset', 0)) print("time", tm) machine.RTC().datetime( (tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) # OTA ... accept uploaded image (if we uploaded a new one) from esp32 import Partition Partition.mark_app_valid_cancel_rollback() # connect to WiFi connect() if True: # webrepl import webrepl webrepl.start() network.WLAN(network.STA_IF).mdns_add_service('_ws', '_tcp', 8266) gc.collect()
# 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:
def part(self): runningpart = Partition(Partition.RUNNING) part_info = runningpart.info() part_name = part_info[4] return part_name
def reboot(part=None): if part: _part = Partition(part) Partition.set_boot(_part) machine.reset()
from esp32 import Partition # MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". bdev = Partition.find(Partition.TYPE_DATA, label="vfs") if not bdev: bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) bdev = bdev[0] if bdev else None
class OTA: def __init__(self): self.part = Partition(Partition.RUNNING).get_next_update() self.sha = hashlib.sha256() self.seq = 0 self.block = 0 self.buf = bytearray(BLOCKLEN) self.buflen = 0 # handle processes one message with a chunk of data in msg. The sequence number seq needs # to increment sequentially and the last call needs to have last==True as well as the # sha set to the hashlib.sha256(entire_data).hexdigest(). def handle(self, sha, msg, seq, last): if self.seq is None: raise ValueError("missing first message") elif self.seq < seq: # "duplicate message" log.warning("Duplicate OTA message seq=%d", seq) return None elif self.seq > seq: raise ValueError("message missing") else: self.seq += 1 self.sha.update(msg) # avoid allocating memory: use buf as-is msglen = len(msg) if self.buflen + msglen >= BLOCKLEN: # got a full block, assemble it and write to flash cpylen = BLOCKLEN - self.buflen self.buf[self.buflen:BLOCKLEN] = msg[:cpylen] self.part.writeblocks(self.block, self.buf) self.block += 1 msglen -= cpylen if msglen > 0: self.buf[:msglen] = msg[cpylen:] self.buflen = msglen else: self.buf[self.buflen:self.buflen + msglen] = msg self.buflen += msglen if last and self.buflen > 0: for i in range(BLOCKLEN - self.buflen): self.buf[self.buflen + i] = 0xFF # erased flash is ff self.part.writeblocks(self.block, self.buf) self.block += 1 assert len(self.buf) == BLOCKLEN if last: return self.finish(sha) elif (seq & 7) == 0: # log.info("Sending ACK {}".format(seq)) return "SEQ {}".format(seq).encode() def finish(self, check_sha): del self.buf self.seq = None calc_sha = binascii.hexlify(self.sha.digest()) check_sha = check_sha.encode() if calc_sha != check_sha: raise ValueError("SHA mismatch calc:{} check={}".format( calc_sha, check_sha)) self.part.set_boot() return "OK"
try: from esp32 import Partition as p import micropython except ImportError: print("SKIP") raise SystemExit # try some vanilla OSError to get std error code try: open("this filedoesnotexist", "r") print("FAILED TO RAISE") except OSError as e: print(e) # try to make nvs partition bootable, which ain't gonna work part = p.find(type=p.TYPE_DATA)[0] fun = p.set_boot try: fun(part) print("FAILED TO RAISE") except OSError as e: print(e) # same but with out of memory condition by locking the heap exc = "FAILED TO RAISE" micropython.heap_lock() try: fun(part) except OSError as e: exc = e micropython.heap_unlock()
from esp32 import Partition bdev = Partition.find(Partition.TYPE_DATA, label='vfs') bdev = bdev[0] if bdev else None
class OTA: # constructor, follow by calling ota(...) def __init__(self, verbose=False): self.verbose = verbose # the partition we are writing to self.part = Partition(Partition.RUNNING).get_next_update() # sha of the new app, computed in _app_data self.sha = hashlib.sha256() # keeping track (_app_data) self.block = 0 self.buf = bytearray(BLOCKLEN) self.buflen = 0 # length of current content of self.buf # load app into the next partition and set it as the next one to boot upon restart # :param: url of app # :sha256: sha256 of app def ota(self, url, sha256): if sys.platform != 'esp32': raise ValueError("N/A") if self.verbose: print('OTA ', end='') buffer = bytearray(BLOCKLEN) mv = memoryview(buffer) sock = open_url(url) while True: sz = sock.readinto(buffer) if not sz: break self._app_data(mv[0:sz]) self._finish(sha256) buffer = None gc.collect() # accept chunks of the app and write to self.part def _app_data(self, data, last=False): global BLOCKLEN, buf, buflen, block data_len = len(data) self.sha.update(data) if self.buflen + data_len >= BLOCKLEN: # got a full block, assemble it and write to flash cpylen = BLOCKLEN - self.buflen self.buf[self.buflen:BLOCKLEN] = data[:cpylen] assert len(self.buf) == BLOCKLEN if self.verbose: print('.', end='') self.part.writeblocks(self.block, self.buf) self.block += 1 data_len -= cpylen if data_len > 0: self.buf[:data_len] = data[cpylen:] self.buflen = data_len else: self.buf[self.buflen:self.buflen + data_len] = data self.buflen += data_len if last and self.buflen > 0: for i in range(BLOCKLEN - self.buflen): self.buf[self.buflen + i] = 0xFF # ord('-') # erased flash is ff if self.verbose: print('.', end='') self.part.writeblocks(self.block, self.buf) assert len(self.buf) == BLOCKLEN # finish writing the app to the partition and check the sha def _finish(self, check_sha): # flush the app buffer and complete the write self._app_data(b'', last=False) self._app_data(b'', last=True) del self.buf # check the sha calc_sha = binascii.hexlify(self.sha.digest()) check_sha = check_sha.encode() if calc_sha != check_sha: raise ValueError( "SHA mismatch\n calc: {}\n check: {}".format( calc_sha, check_sha)) self.part.set_boot() if self.verbose: print(' Done.')