3 # ESP8266 & ESP32 family ROM Bootloader Utility
4 # Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted.
5 # https://github.com/espressif/esptool
7 # This program is free software; you can redistribute it and/or modify it under
8 # the terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
17 # Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 from __future__
import division
, print_function
40 print("Pyserial is not installed for %s. Check the README for installation instructions." % (sys
.executable
))
43 # check 'serial' is 'pyserial' and not 'serial' https://github.com/espressif/esptool/issues/269
45 if "serialization" in serial
.__doc
__ and "deserialization" in serial
.__doc
__:
47 esptool.py depends on pyserial, but there is a conflict with a currently installed package named 'serial'.
49 You may be able to work around this by 'pip uninstall serial; pip install pyserial' \
50 but this may break other installed Python software that depends on 'serial'.
52 There is no good fix for this right now, apart from configuring virtualenvs. \
53 See https://github.com/espressif/esptool/issues/269#issuecomment-385298196 for discussion of the underlying issue(s).""")
55 pass # __doc__ returns None for pyserial
58 import serial
.tools
.list_ports
as list_ports
60 print("The installed version (%s) of pyserial appears to be too old for esptool.py (Python interpreter %s). "
61 "Check the README for installation instructions." % (sys
.VERSION
, sys
.executable
))
64 if sys
.platform
== "darwin":
65 # swallow the exception, this is a known issue in pyserial+macOS Big Sur preview ref https://github.com/espressif/esptool/issues/540
73 MAX_UINT32
= 0xffffffff
76 DEFAULT_TIMEOUT
= 3 # timeout for most flash operations
77 START_FLASH_TIMEOUT
= 20 # timeout for starting flash (may perform erase)
78 CHIP_ERASE_TIMEOUT
= 120 # timeout for full chip erase
79 MAX_TIMEOUT
= CHIP_ERASE_TIMEOUT
* 2 # longest any command can run
80 SYNC_TIMEOUT
= 0.1 # timeout for syncing with bootloader
81 MD5_TIMEOUT_PER_MB
= 8 # timeout (per megabyte) for calculating md5sum
82 ERASE_REGION_TIMEOUT_PER_MB
= 30 # timeout (per megabyte) for erasing a region
83 MEM_END_ROM_TIMEOUT
= 0.05 # special short timeout for ESP_MEM_END, as it may never respond
84 DEFAULT_SERIAL_WRITE_TIMEOUT
= 10 # timeout for serial port write
85 DEFAULT_CONNECT_ATTEMPTS
= 7 # default number of times to try connection
88 def timeout_per_mb(seconds_per_mb
, size_bytes
):
89 """ Scales timeouts which are size-specific """
90 result
= seconds_per_mb
* (size_bytes
/ 1e6
)
91 if result
< DEFAULT_TIMEOUT
:
92 return DEFAULT_TIMEOUT
96 DETECTED_FLASH_SIZES
= {0x12: '256KB', 0x13: '512KB', 0x14: '1MB',
97 0x15: '2MB', 0x16: '4MB', 0x17: '8MB', 0x18: '16MB'}
100 def check_supported_function(func
, check_func
):
102 Decorator implementation that wraps a check around an ESPLoader
103 bootloader function to check if it's supported.
105 This is used to capture the multidimensional differences in
106 functionality between the ESP8266 & ESP32/32S2/32S3/32C3 ROM loaders, and the
107 software stub that runs on both. Not possible to do this cleanly
108 via inheritance alone.
110 def inner(*args
, **kwargs
):
113 return func(*args
, **kwargs
)
115 raise NotImplementedInROMError(obj
, func
)
119 def stub_function_only(func
):
120 """ Attribute for a function only supported in the software stub loader """
121 return check_supported_function(func
, lambda o
: o
.IS_STUB
)
124 def stub_and_esp32_function_only(func
):
125 """ Attribute for a function only supported by software stubs or ESP32/32S2/32S3/32C3 ROM """
126 return check_supported_function(func
, lambda o
: o
.IS_STUB
or isinstance(o
, ESP32ROM
))
129 PYTHON2
= sys
.version_info
[0] < 3 # True if on pre-Python 3
131 # Function to return nth byte of a bitstring
132 # Different behaviour on Python 2 vs 3
134 def byte(bitstr
, index
):
135 return ord(bitstr
[index
])
137 def byte(bitstr
, index
):
140 # Provide a 'basestring' class on Python 3
147 def print_overwrite(message
, last_line
=False):
148 """ Print a message, overwriting the currently printed line.
150 If last_line is False, don't append a newline at the end (expecting another subsequent call will overwrite this one.)
152 After a sequence of calls with last_line=False, call once with last_line=True.
154 If output is not a TTY (for example redirected a pipe), no overwriting happens and this function is the same as print().
156 if sys
.stdout
.isatty():
157 print("\r%s" % message
, end
='\n' if last_line
else '')
162 def _mask_to_shift(mask
):
163 """ Return the index of the least significant bit in the mask """
165 while mask
& 0x1 == 0:
171 def esp8266_function_only(func
):
172 """ Attribute for a function only supported on ESP8266 """
173 return check_supported_function(func
, lambda o
: o
.CHIP_NAME
== "ESP8266")
176 class ESPLoader(object):
177 """ Base class providing access to ESP ROM & software stub bootloaders.
178 Subclasses provide ESP8266 & ESP32 specific functionality.
180 Don't instantiate this base class directly, either instantiate a subclass or
181 call ESPLoader.detect_chip() which will interrogate the chip and return the
182 appropriate subclass instance.
185 CHIP_NAME
= "Espressif device"
188 DEFAULT_PORT
= "/dev/ttyUSB0"
190 # Commands supported by ESP8266 ROM bootloader
191 ESP_FLASH_BEGIN
= 0x02
192 ESP_FLASH_DATA
= 0x03
201 # Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub)
202 ESP_SPI_SET_PARAMS
= 0x0B
203 ESP_SPI_ATTACH
= 0x0D
204 ESP_READ_FLASH_SLOW
= 0x0e # ROM only, much slower than the stub flash read
205 ESP_CHANGE_BAUDRATE
= 0x0F
206 ESP_FLASH_DEFL_BEGIN
= 0x10
207 ESP_FLASH_DEFL_DATA
= 0x11
208 ESP_FLASH_DEFL_END
= 0x12
209 ESP_SPI_FLASH_MD5
= 0x13
211 # Commands supported by ESP32-S2/S3/C3 ROM bootloader only
212 ESP_GET_SECURITY_INFO
= 0x14
214 # Some commands supported by stub only
215 ESP_ERASE_FLASH
= 0xD0
216 ESP_ERASE_REGION
= 0xD1
217 ESP_READ_FLASH
= 0xD2
218 ESP_RUN_USER_CODE
= 0xD3
220 # Flash encryption encrypted data command
221 ESP_FLASH_ENCRYPT_DATA
= 0xD4
223 # Response code(s) sent by ROM
224 ROM_INVALID_RECV_MSG
= 0x05 # response if an invalid message is received
226 # Maximum block sized for RAM and Flash writes, respectively.
227 ESP_RAM_BLOCK
= 0x0800
229 FLASH_WRITE_SIZE
= 0x400
231 # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
232 ESP_ROM_BAUD
= 115200
234 # First byte of the application image
235 ESP_IMAGE_MAGIC
= 0xe9
237 # Initial state for the checksum routine
238 ESP_CHECKSUM_MAGIC
= 0xef
240 # Flash sector size, minimum unit of erase.
241 FLASH_SECTOR_SIZE
= 0x1000
243 UART_DATE_REG_ADDR
= 0x60000078
245 CHIP_DETECT_MAGIC_REG_ADDR
= 0x40001000 # This ROM address has a different value on each chip model
247 UART_CLKDIV_MASK
= 0xFFFFF
250 IROM_MAP_START
= 0x40200000
251 IROM_MAP_END
= 0x40300000
253 # The number of bytes in the UART response that signify command status
254 STATUS_BYTES_LENGTH
= 2
256 def __init__(self
, port
=DEFAULT_PORT
, baud
=ESP_ROM_BAUD
, trace_enabled
=False):
257 """Base constructor for ESPLoader bootloader interaction
259 Don't call this constructor, either instantiate ESP8266ROM
260 or ESP32ROM, or use ESPLoader.detect_chip().
262 This base class has all of the instance methods for bootloader
263 functionality supported across various chips & stub
264 loaders. Subclasses replace the functions they don't support
265 with ones which throw NotImplementedInROMError().
268 self
.secure_download_mode
= False # flag is set to True if esptool detects the ROM is in Secure Download Mode
270 if isinstance(port
, basestring
):
271 self
._port
= serial
.serial_for_url(port
)
274 self
._slip
_reader
= slip_reader(self
._port
, self
.trace
)
275 # setting baud rate in a separate step is a workaround for
276 # CH341 driver on some Linux versions (this opens at 9600 then
277 # sets), shouldn't matter for other platforms/drivers. See
278 # https://github.com/espressif/esptool/issues/44#issuecomment-107094446
279 self
._set
_port
_baudrate
(baud
)
280 self
._trace
_enabled
= trace_enabled
281 # set write timeout, to prevent esptool blocked at write forever.
283 self
._port
.write_timeout
= DEFAULT_SERIAL_WRITE_TIMEOUT
284 except NotImplementedError:
285 # no write timeout for RFC2217 ports
286 # need to set the property back to None or it will continue to fail
287 self
._port
.write_timeout
= None
289 def _set_port_baudrate(self
, baud
):
291 self
._port
.baudrate
= baud
293 raise FatalError("Failed to set baud rate %d. The driver may not support this rate." % baud
)
296 def detect_chip(port
=DEFAULT_PORT
, baud
=ESP_ROM_BAUD
, connect_mode
='default_reset', trace_enabled
=False,
297 connect_attempts
=DEFAULT_CONNECT_ATTEMPTS
):
298 """ Use serial access to detect the chip type.
300 We use the UART's datecode register for this, it's mapped at
301 the same address on ESP8266 & ESP32 so we can use one
302 memory read and compare to the datecode register for each chip
305 This routine automatically performs ESPLoader.connect() (passing
306 connect_mode parameter) as part of querying the chip.
308 detect_port
= ESPLoader(port
, baud
, trace_enabled
=trace_enabled
)
309 detect_port
.connect(connect_mode
, connect_attempts
, detecting
=True)
311 print('Detecting chip type...', end
='')
313 chip_magic_value
= detect_port
.read_reg(ESPLoader
.CHIP_DETECT_MAGIC_REG_ADDR
)
315 for cls
in [ESP8266ROM
, ESP32ROM
, ESP32S2ROM
, ESP32S3BETA2ROM
, ESP32C3ROM
]:
316 if chip_magic_value
== cls
.CHIP_DETECT_MAGIC_VALUE
:
317 # don't connect a second time
318 inst
= cls(detect_port
._port
, baud
, trace_enabled
=trace_enabled
)
320 print(' %s' % inst
.CHIP_NAME
, end
='')
322 except UnsupportedCommandError
:
323 raise FatalError("Unsupported Command Error received. Probably this means Secure Download Mode is enabled, "
324 "autodetection will not work. Need to manually specify the chip.")
327 raise FatalError("Unexpected CHIP magic value 0x%08x. Failed to autodetect chip type." % (chip_magic_value
))
329 """ Read a SLIP packet from the serial port """
331 return next(self
._slip
_reader
)
333 """ Write bytes to the serial port while performing SLIP escaping """
334 def write(self
, packet
):
336 + (packet
.replace(b
'\xdb', b
'\xdb\xdd').replace(b
'\xc0', b
'\xdb\xdc')) \
338 self
.trace("Write %d bytes: %s", len(buf
), HexFormatter(buf
))
339 self
._port
.write(buf
)
341 def trace(self
, message
, *format_args
):
342 if self
._trace
_enabled
:
346 delta
= now
- self
._last
_trace
347 except AttributeError:
349 self
._last
_trace
= now
350 prefix
= "TRACE +%.3f " % delta
351 print(prefix
+ (message
% format_args
))
353 """ Calculate checksum of a blob, as it is defined by the ROM """
355 def checksum(data
, state
=ESP_CHECKSUM_MAGIC
):
357 if type(b
) is int: # python 2/3 compat
364 """ Send a request and read the response """
365 def command(self
, op
=None, data
=b
"", chk
=0, wait_response
=True, timeout
=DEFAULT_TIMEOUT
):
366 saved_timeout
= self
._port
.timeout
367 new_timeout
= min(timeout
, MAX_TIMEOUT
)
368 if new_timeout
!= saved_timeout
:
369 self
._port
.timeout
= new_timeout
373 self
.trace("command op=0x%02x data len=%s wait_response=%d timeout=%.3f data=%s",
374 op
, len(data
), 1 if wait_response
else 0, timeout
, HexFormatter(data
))
375 pkt
= struct
.pack(b
'<BBHI', 0x00, op
, len(data
), chk
) + data
378 if not wait_response
:
381 # tries to get a response until that response has the
382 # same operation as the request or a retries limit has
383 # exceeded. This is needed for some esp8266s that
384 # reply with more sync responses than expected.
385 for retry
in range(100):
389 (resp
, op_ret
, len_ret
, val
) = struct
.unpack('<BBHI', p
[:8])
394 if op
is None or op_ret
== op
:
396 if byte(data
, 0) != 0 and byte(data
, 1) == self
.ROM_INVALID_RECV_MSG
:
397 self
.flush_input() # Unsupported read_reg can result in more than one error response for some reason
398 raise UnsupportedCommandError(self
, op
)
401 if new_timeout
!= saved_timeout
:
402 self
._port
.timeout
= saved_timeout
404 raise FatalError("Response doesn't match request")
406 def check_command(self
, op_description
, op
=None, data
=b
'', chk
=0, timeout
=DEFAULT_TIMEOUT
):
408 Execute a command with 'command', check the result code and throw an appropriate
409 FatalError if it fails.
411 Returns the "result" of a successful command.
413 val
, data
= self
.command(op
, data
, chk
, timeout
=timeout
)
415 # things are a bit weird here, bear with us
417 # the status bytes are the last 2/4 bytes in the data (depending on chip)
418 if len(data
) < self
.STATUS_BYTES_LENGTH
:
419 raise FatalError("Failed to %s. Only got %d byte status response." % (op_description
, len(data
)))
420 status_bytes
= data
[-self
.STATUS_BYTES_LENGTH
:]
421 # we only care if the first one is non-zero. If it is, the second byte is a reason.
422 if byte(status_bytes
, 0) != 0:
423 raise FatalError
.WithResult('Failed to %s' % op_description
, status_bytes
)
425 # if we had more data than just the status bytes, return it as the result
426 # (this is used by the md5sum command, maybe other commands?)
427 if len(data
) > self
.STATUS_BYTES_LENGTH
:
428 return data
[:-self
.STATUS_BYTES_LENGTH
]
429 else: # otherwise, just return the 'val' field which comes from the reply header (this is used by read_reg)
432 def flush_input(self
):
433 self
._port
.flushInput()
434 self
._slip
_reader
= slip_reader(self
._port
, self
.trace
)
437 self
.command(self
.ESP_SYNC
, b
'\x07\x07\x12\x20' + 32 * b
'\x55',
438 timeout
=SYNC_TIMEOUT
)
442 def _setDTR(self
, state
):
443 self
._port
.setDTR(state
)
445 def _setRTS(self
, state
):
446 self
._port
.setRTS(state
)
447 # Work-around for adapters on Windows using the usbser.sys driver:
448 # generate a dummy change to DTR so that the set-control-line-state
449 # request is sent with the updated RTS state and the same DTR state
450 self
._port
.setDTR(self
._port
.dtr
)
452 def _connect_attempt(self
, mode
='default_reset', esp32r0_delay
=False):
453 """ A single connection attempt, with esp32r0 workaround options """
454 # esp32r0_delay is a workaround for bugs with the most common auto reset
455 # circuit and Windows, if the EN pin on the dev board does not have
456 # enough capacitance.
458 # Newer dev boards shouldn't have this problem (higher value capacitor
459 # on the EN pin), and ESP32 revision 1 can't use this workaround as it
460 # relies on a silicon bug.
462 # Details: https://github.com/espressif/esptool/issues/136
465 # If we're doing no_sync, we're likely communicating as a pass through
466 # with an intermediate device to the ESP32
467 if mode
== "no_reset_no_sync":
470 # issue reset-to-bootloader:
471 # RTS = either CH_PD/EN or nRESET (both active low = chip in reset
472 # DTR = GPIO0 (active low = boot to flasher)
474 # DTR & RTS are active low signals,
475 # ie True = pin @ 0V, False = pin @ VCC.
476 if mode
!= 'no_reset':
477 self
._setDTR
(False) # IO0=HIGH
478 self
._setRTS
(True) # EN=LOW, chip in reset
481 # Some chips are more likely to trigger the esp32r0
482 # watchdog reset silicon bug if they're held with EN=LOW
483 # for a longer period
485 self
._setDTR
(True) # IO0=LOW
486 self
._setRTS
(False) # EN=HIGH, chip out of reset
488 # Sleep longer after reset.
489 # This workaround only works on revision 0 ESP32 chips,
490 # it exploits a silicon bug spurious watchdog reset.
491 time
.sleep(0.4) # allow watchdog reset to occur
493 self
._setDTR
(False) # IO0=HIGH, done
498 self
._port
.flushOutput()
501 except FatalError
as e
:
511 def connect(self
, mode
='default_reset', attempts
=DEFAULT_CONNECT_ATTEMPTS
, detecting
=False):
512 """ Try connecting repeatedly until successful, or giving up """
513 print('Connecting...', end
='')
518 for _
in range(attempts
) if attempts
> 0 else itertools
.count():
519 last_error
= self
._connect
_attempt
(mode
=mode
, esp32r0_delay
=False)
520 if last_error
is None:
522 last_error
= self
._connect
_attempt
(mode
=mode
, esp32r0_delay
=True)
523 if last_error
is None:
526 print('') # end 'Connecting...' line
528 if last_error
is not None:
529 raise FatalError('Failed to connect to %s: %s' % (self
.CHIP_NAME
, last_error
))
533 # check the date code registers match what we expect to see
534 chip_magic_value
= self
.read_reg(ESPLoader
.CHIP_DETECT_MAGIC_REG_ADDR
)
535 if chip_magic_value
!= self
.CHIP_DETECT_MAGIC_VALUE
:
537 for cls
in [ESP8266ROM
, ESP32ROM
, ESP32S2ROM
, ESP32S3BETA2ROM
, ESP32C3ROM
]:
538 if chip_magic_value
== cls
.CHIP_DETECT_MAGIC_VALUE
:
542 print(("WARNING: This chip doesn't appear to be a %s (chip magic value 0x%08x). "
543 "Probably it is unsupported by this version of esptool.") % (self
.CHIP_NAME
, chip_magic_value
))
545 raise FatalError("This chip is %s not %s. Wrong --chip argument?" % (actually
.CHIP_NAME
, self
.CHIP_NAME
))
546 except UnsupportedCommandError
:
547 self
.secure_download_mode
= True
550 def _post_connect(self
):
552 Additional initialization hook, may be overridden by the chip-specific class.
553 Gets called after connect, and after auto-detection.
557 def read_reg(self
, addr
):
558 """ Read memory address in target """
559 # we don't call check_command here because read_reg() function is called
560 # when detecting chip type, and the way we check for success (STATUS_BYTES_LENGTH) is different
561 # for different chip types (!)
562 val
, data
= self
.command(self
.ESP_READ_REG
, struct
.pack('<I', addr
))
563 if byte(data
, 0) != 0:
564 raise FatalError
.WithResult("Failed to read register address %08x" % addr
, data
)
567 """ Write to memory address in target """
568 def write_reg(self
, addr
, value
, mask
=0xFFFFFFFF, delay_us
=0, delay_after_us
=0):
569 command
= struct
.pack('<IIII', addr
, value
, mask
, delay_us
)
570 if delay_after_us
> 0:
571 # add a dummy write to a date register as an excuse to have a delay
572 command
+= struct
.pack('<IIII', self
.UART_DATE_REG_ADDR
, 0, 0, delay_after_us
)
574 return self
.check_command("write target memory", self
.ESP_WRITE_REG
, command
)
576 def update_reg(self
, addr
, mask
, new_val
):
577 """ Update register at 'addr', replace the bits masked out by 'mask'
578 with new_val. new_val is shifted left to match the LSB of 'mask'
580 Returns just-written value of register.
582 shift
= _mask_to_shift(mask
)
583 val
= self
.read_reg(addr
)
585 val |
= (new_val
<< shift
) & mask
586 self
.write_reg(addr
, val
)
590 """ Start downloading an application image to RAM """
591 def mem_begin(self
, size
, blocks
, blocksize
, offset
):
592 if self
.IS_STUB
: # check we're not going to overwrite a running stub with this data
593 stub
= self
.STUB_CODE
595 load_end
= offset
+ size
596 for (start
, end
) in [(stub
["data_start"], stub
["data_start"] + len(stub
["data"])),
597 (stub
["text_start"], stub
["text_start"] + len(stub
["text"]))]:
598 if load_start
< end
and load_end
> start
:
599 raise FatalError(("Software loader is resident at 0x%08x-0x%08x. "
600 "Can't load binary at overlapping address range 0x%08x-0x%08x. "
601 "Either change binary loading address, or use the --no-stub "
602 "option to disable the software loader.") % (start
, end
, load_start
, load_end
))
604 return self
.check_command("enter RAM download mode", self
.ESP_MEM_BEGIN
,
605 struct
.pack('<IIII', size
, blocks
, blocksize
, offset
))
607 """ Send a block of an image to RAM """
608 def mem_block(self
, data
, seq
):
609 return self
.check_command("write to target RAM", self
.ESP_MEM_DATA
,
610 struct
.pack('<IIII', len(data
), seq
, 0, 0) + data
,
613 """ Leave download mode and run the application """
614 def mem_finish(self
, entrypoint
=0):
615 # Sending ESP_MEM_END usually sends a correct response back, however sometimes
616 # (with ROM loader) the executed code may reset the UART or change the baud rate
617 # before the transmit FIFO is empty. So in these cases we set a short timeout and
619 timeout
= DEFAULT_TIMEOUT
if self
.IS_STUB
else MEM_END_ROM_TIMEOUT
620 data
= struct
.pack('<II', int(entrypoint
== 0), entrypoint
)
622 return self
.check_command("leave RAM download mode", self
.ESP_MEM_END
,
623 data
=data
, timeout
=timeout
)
629 """ Start downloading to Flash (performs an erase)
631 Returns number of blocks (of size self.FLASH_WRITE_SIZE) to write.
633 def flash_begin(self
, size
, offset
, begin_rom_encrypted
=False):
634 num_blocks
= (size
+ self
.FLASH_WRITE_SIZE
- 1) // self
.FLASH_WRITE_SIZE
635 erase_size
= self
.get_erase_size(offset
, size
)
639 timeout
= DEFAULT_TIMEOUT
641 timeout
= timeout_per_mb(ERASE_REGION_TIMEOUT_PER_MB
, size
) # ROM performs the erase up front
643 params
= struct
.pack('<IIII', erase_size
, num_blocks
, self
.FLASH_WRITE_SIZE
, offset
)
644 if isinstance(self
, (ESP32S2ROM
, ESP32S3BETA2ROM
, ESP32C3ROM
)) and not self
.IS_STUB
:
645 params
+= struct
.pack('<I', 1 if begin_rom_encrypted
else 0)
646 self
.check_command("enter Flash download mode", self
.ESP_FLASH_BEGIN
,
647 params
, timeout
=timeout
)
648 if size
!= 0 and not self
.IS_STUB
:
649 print("Took %.2fs to erase flash block" % (time
.time() - t
))
652 """ Write block to flash """
653 def flash_block(self
, data
, seq
, timeout
=DEFAULT_TIMEOUT
):
654 self
.check_command("write to target Flash after seq %d" % seq
,
656 struct
.pack('<IIII', len(data
), seq
, 0, 0) + data
,
660 """ Encrypt before writing to flash """
661 def flash_encrypt_block(self
, data
, seq
, timeout
=DEFAULT_TIMEOUT
):
662 if isinstance(self
, (ESP32S2ROM
, ESP32C3ROM
)) and not self
.IS_STUB
:
663 # ROM support performs the encrypted writes via the normal write command,
664 # triggered by flash_begin(begin_rom_encrypted=True)
665 return self
.flash_block(data
, seq
, timeout
)
667 self
.check_command("Write encrypted to target Flash after seq %d" % seq
,
668 self
.ESP_FLASH_ENCRYPT_DATA
,
669 struct
.pack('<IIII', len(data
), seq
, 0, 0) + data
,
673 """ Leave flash mode and run/reboot """
674 def flash_finish(self
, reboot
=False):
675 pkt
= struct
.pack('<I', int(not reboot
))
676 # stub sends a reply to this command
677 self
.check_command("leave Flash mode", self
.ESP_FLASH_END
, pkt
)
679 """ Run application code in flash """
680 def run(self
, reboot
=False):
681 # Fake flash begin immediately followed by flash end
682 self
.flash_begin(0, 0)
683 self
.flash_finish(reboot
)
685 """ Read SPI flash manufacturer and device id """
688 return self
.run_spiflash_command(SPIFLASH_RDID
, b
"", 24)
690 def get_security_info(self
):
691 # TODO: this only works on the ESP32S2 ROM code loader and needs to work in stub loader also
692 res
= self
.check_command('get security info', self
.ESP_GET_SECURITY_INFO
, b
'')
693 res
= struct
.unpack("<IBBBBBBBB", res
)
694 flags
, flash_crypt_cnt
, key_purposes
= res
[0], res
[1], res
[2:]
695 # TODO: pack this as some kind of better data type
696 return (flags
, flash_crypt_cnt
, key_purposes
)
698 def parse_flash_size_arg(self
, arg
):
700 return self
.FLASH_SIZES
[arg
]
702 raise FatalError("Flash size '%s' is not supported by this chip type. Supported sizes: %s"
703 % (arg
, ", ".join(self
.FLASH_SIZES
.keys())))
705 def run_stub(self
, stub
=None):
708 raise FatalError("Not possible for a stub to load another stub (memory likely to overlap.)")
709 stub
= self
.STUB_CODE
712 print("Uploading stub...")
713 for field
in ['text', 'data']:
715 offs
= stub
[field
+ "_start"]
716 length
= len(stub
[field
])
717 blocks
= (length
+ self
.ESP_RAM_BLOCK
- 1) // self
.ESP_RAM_BLOCK
718 self
.mem_begin(length
, blocks
, self
.ESP_RAM_BLOCK
, offs
)
719 for seq
in range(blocks
):
720 from_offs
= seq
* self
.ESP_RAM_BLOCK
721 to_offs
= from_offs
+ self
.ESP_RAM_BLOCK
722 self
.mem_block(stub
[field
][from_offs
:to_offs
], seq
)
723 print("Running stub...")
724 self
.mem_finish(stub
['entry'])
728 raise FatalError("Failed to start stub. Unexpected response: %s" % p
)
729 print("Stub running...")
730 return self
.STUB_CLASS(self
)
732 @stub_and_esp32_function_only
733 def flash_defl_begin(self
, size
, compsize
, offset
):
734 """ Start downloading compressed data to Flash (performs an erase)
736 Returns number of blocks (size self.FLASH_WRITE_SIZE) to write.
738 num_blocks
= (compsize
+ self
.FLASH_WRITE_SIZE
- 1) // self
.FLASH_WRITE_SIZE
739 erase_blocks
= (size
+ self
.FLASH_WRITE_SIZE
- 1) // self
.FLASH_WRITE_SIZE
743 write_size
= size
# stub expects number of bytes here, manages erasing internally
744 timeout
= DEFAULT_TIMEOUT
746 write_size
= erase_blocks
* self
.FLASH_WRITE_SIZE
# ROM expects rounded up to erase block size
747 timeout
= timeout_per_mb(ERASE_REGION_TIMEOUT_PER_MB
, write_size
) # ROM performs the erase up front
748 print("Compressed %d bytes to %d..." % (size
, compsize
))
749 params
= struct
.pack('<IIII', write_size
, num_blocks
, self
.FLASH_WRITE_SIZE
, offset
)
750 if isinstance(self
, (ESP32S2ROM
, ESP32S3BETA2ROM
, ESP32C3ROM
)) and not self
.IS_STUB
:
751 params
+= struct
.pack('<I', 0) # extra param is to enter encrypted flash mode via ROM (not supported currently)
752 self
.check_command("enter compressed flash mode", self
.ESP_FLASH_DEFL_BEGIN
, params
, timeout
=timeout
)
753 if size
!= 0 and not self
.IS_STUB
:
754 # (stub erases as it writes, but ROM loaders erase on begin)
755 print("Took %.2fs to erase flash block" % (time
.time() - t
))
758 """ Write block to flash, send compressed """
759 @stub_and_esp32_function_only
760 def flash_defl_block(self
, data
, seq
, timeout
=DEFAULT_TIMEOUT
):
761 self
.check_command("write compressed data to flash after seq %d" % seq
,
762 self
.ESP_FLASH_DEFL_DATA
, struct
.pack('<IIII', len(data
), seq
, 0, 0) + data
, self
.checksum(data
), timeout
=timeout
)
764 """ Leave compressed flash mode and run/reboot """
765 @stub_and_esp32_function_only
766 def flash_defl_finish(self
, reboot
=False):
767 if not reboot
and not self
.IS_STUB
:
768 # skip sending flash_finish to ROM loader, as this
769 # exits the bootloader. Stub doesn't do this.
771 pkt
= struct
.pack('<I', int(not reboot
))
772 self
.check_command("leave compressed flash mode", self
.ESP_FLASH_DEFL_END
, pkt
)
773 self
.in_bootloader
= False
775 @stub_and_esp32_function_only
776 def flash_md5sum(self
, addr
, size
):
777 # the MD5 command returns additional bytes in the standard
779 timeout
= timeout_per_mb(MD5_TIMEOUT_PER_MB
, size
)
780 res
= self
.check_command('calculate md5sum', self
.ESP_SPI_FLASH_MD5
, struct
.pack('<IIII', addr
, size
, 0, 0),
784 return res
.decode("utf-8") # already hex formatted
786 return hexify(res
).lower()
788 raise FatalError("MD5Sum command returned unexpected result: %r" % res
)
790 @stub_and_esp32_function_only
791 def change_baud(self
, baud
):
792 print("Changing baud rate to %d" % baud
)
793 # stub takes the new baud rate and the old one
794 second_arg
= self
._port
.baudrate
if self
.IS_STUB
else 0
795 self
.command(self
.ESP_CHANGE_BAUDRATE
, struct
.pack('<II', baud
, second_arg
))
797 self
._set
_port
_baudrate
(baud
)
798 time
.sleep(0.05) # get rid of crap sent during baud rate change
802 def erase_flash(self
):
803 # depending on flash chip model the erase may take this long (maybe longer!)
804 self
.check_command("erase flash", self
.ESP_ERASE_FLASH
,
805 timeout
=CHIP_ERASE_TIMEOUT
)
808 def erase_region(self
, offset
, size
):
809 if offset
% self
.FLASH_SECTOR_SIZE
!= 0:
810 raise FatalError("Offset to erase from must be a multiple of 4096")
811 if size
% self
.FLASH_SECTOR_SIZE
!= 0:
812 raise FatalError("Size of data to erase must be a multiple of 4096")
813 timeout
= timeout_per_mb(ERASE_REGION_TIMEOUT_PER_MB
, size
)
814 self
.check_command("erase region", self
.ESP_ERASE_REGION
, struct
.pack('<II', offset
, size
), timeout
=timeout
)
816 def read_flash_slow(self
, offset
, length
, progress_fn
):
817 raise NotImplementedInROMError(self
, self
.read_flash_slow
)
819 def read_flash(self
, offset
, length
, progress_fn
=None):
821 return self
.read_flash_slow(offset
, length
, progress_fn
) # ROM-only routine
823 # issue a standard bootloader command to trigger the read
824 self
.check_command("read flash", self
.ESP_READ_FLASH
,
828 self
.FLASH_SECTOR_SIZE
,
830 # now we expect (length // block_size) SLIP frames with the data
832 while len(data
) < length
:
835 if len(data
) < length
and len(p
) < self
.FLASH_SECTOR_SIZE
:
836 raise FatalError('Corrupt data, expected 0x%x bytes but received 0x%x bytes' % (self
.FLASH_SECTOR_SIZE
, len(p
)))
837 self
.write(struct
.pack('<I', len(data
)))
838 if progress_fn
and (len(data
) % 1024 == 0 or len(data
) == length
):
839 progress_fn(len(data
), length
)
841 progress_fn(len(data
), length
)
842 if len(data
) > length
:
843 raise FatalError('Read more than expected')
845 digest_frame
= self
.read()
846 if len(digest_frame
) != 16:
847 raise FatalError('Expected digest, got: %s' % hexify(digest_frame
))
848 expected_digest
= hexify(digest_frame
).upper()
849 digest
= hashlib
.md5(data
).hexdigest().upper()
850 if digest
!= expected_digest
:
851 raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest
, digest
))
854 def flash_spi_attach(self
, hspi_arg
):
855 """Send SPI attach command to enable the SPI flash pins
857 ESP8266 ROM does this when you send flash_begin, ESP32 ROM
858 has it as a SPI command.
860 # last 3 bytes in ESP_SPI_ATTACH argument are reserved values
861 arg
= struct
.pack('<I', hspi_arg
)
863 # ESP32 ROM loader takes additional 'is legacy' arg, which is not
864 # currently supported in the stub loader or esptool.py (as it's not usually needed.)
866 arg
+= struct
.pack('BBBB', is_legacy
, 0, 0, 0)
867 self
.check_command("configure SPI flash pins", ESP32ROM
.ESP_SPI_ATTACH
, arg
)
869 def flash_set_parameters(self
, size
):
870 """Tell the ESP bootloader the parameters of the chip
872 Corresponds to the "flashchip" data structure that the ROM
877 All other flash parameters are currently hardcoded (on ESP8266
878 these are mostly ignored by ROM code, on ESP32 I'm not sure.)
882 block_size
= 64 * 1024
883 sector_size
= 4 * 1024
886 self
.check_command("set SPI params", ESP32ROM
.ESP_SPI_SET_PARAMS
,
887 struct
.pack('<IIIIII', fl_id
, total_size
, block_size
, sector_size
, page_size
, status_mask
))
889 def run_spiflash_command(self
, spiflash_command
, data
=b
"", read_bits
=0):
890 """Run an arbitrary SPI flash command.
892 This function uses the "USR_COMMAND" functionality in the ESP
893 SPI hardware, rather than the precanned commands supported by
894 hardware. So the value of spiflash_command is an actual command
895 byte, sent over the wire.
897 After writing command byte, writes 'data' to MOSI and then
898 reads back 'read_bits' of reply on MISO. Result is a number.
901 # SPI_USR register flags
902 SPI_USR_COMMAND
= (1 << 31)
903 SPI_USR_MISO
= (1 << 28)
904 SPI_USR_MOSI
= (1 << 27)
906 # SPI registers, base address differs ESP32* vs 8266
907 base
= self
.SPI_REG_BASE
908 SPI_CMD_REG
= base
+ 0x00
909 SPI_USR_REG
= base
+ self
.SPI_USR_OFFS
910 SPI_USR1_REG
= base
+ self
.SPI_USR1_OFFS
911 SPI_USR2_REG
= base
+ self
.SPI_USR2_OFFS
912 SPI_W0_REG
= base
+ self
.SPI_W0_OFFS
914 # following two registers are ESP32 & 32S2/32C3 only
915 if self
.SPI_MOSI_DLEN_OFFS
is not None:
916 # ESP32/32S2/32C3 has a more sophisticated way to set up "user" commands
917 def set_data_lengths(mosi_bits
, miso_bits
):
918 SPI_MOSI_DLEN_REG
= base
+ self
.SPI_MOSI_DLEN_OFFS
919 SPI_MISO_DLEN_REG
= base
+ self
.SPI_MISO_DLEN_OFFS
921 self
.write_reg(SPI_MOSI_DLEN_REG
, mosi_bits
- 1)
923 self
.write_reg(SPI_MISO_DLEN_REG
, miso_bits
- 1)
926 def set_data_lengths(mosi_bits
, miso_bits
):
927 SPI_DATA_LEN_REG
= SPI_USR1_REG
928 SPI_MOSI_BITLEN_S
= 17
929 SPI_MISO_BITLEN_S
= 8
930 mosi_mask
= 0 if (mosi_bits
== 0) else (mosi_bits
- 1)
931 miso_mask
= 0 if (miso_bits
== 0) else (miso_bits
- 1)
932 self
.write_reg(SPI_DATA_LEN_REG
,
933 (miso_mask
<< SPI_MISO_BITLEN_S
) |
(
934 mosi_mask
<< SPI_MOSI_BITLEN_S
))
936 # SPI peripheral "command" bitmasks for SPI_CMD_REG
937 SPI_CMD_USR
= (1 << 18)
940 SPI_USR2_COMMAND_LEN_SHIFT
= 28
943 raise FatalError("Reading more than 32 bits back from a SPI flash operation is unsupported")
945 raise FatalError("Writing more than 64 bytes of data with one SPI command is unsupported")
947 data_bits
= len(data
) * 8
948 old_spi_usr
= self
.read_reg(SPI_USR_REG
)
949 old_spi_usr2
= self
.read_reg(SPI_USR2_REG
)
950 flags
= SPI_USR_COMMAND
952 flags |
= SPI_USR_MISO
954 flags |
= SPI_USR_MOSI
955 set_data_lengths(data_bits
, read_bits
)
956 self
.write_reg(SPI_USR_REG
, flags
)
957 self
.write_reg(SPI_USR2_REG
,
958 (7 << SPI_USR2_COMMAND_LEN_SHIFT
) | spiflash_command
)
960 self
.write_reg(SPI_W0_REG
, 0) # clear data register before we read it
962 data
= pad_to(data
, 4, b
'\00') # pad to 32-bit multiple
963 words
= struct
.unpack("I" * (len(data
) // 4), data
)
964 next_reg
= SPI_W0_REG
966 self
.write_reg(next_reg
, word
)
968 self
.write_reg(SPI_CMD_REG
, SPI_CMD_USR
)
972 if (self
.read_reg(SPI_CMD_REG
) & SPI_CMD_USR
) == 0:
974 raise FatalError("SPI command did not complete in time")
977 status
= self
.read_reg(SPI_W0_REG
)
978 # restore some SPI controller registers
979 self
.write_reg(SPI_USR_REG
, old_spi_usr
)
980 self
.write_reg(SPI_USR2_REG
, old_spi_usr2
)
983 def read_status(self
, num_bytes
=2):
984 """Read up to 24 bits (num_bytes) of SPI flash status register contents
985 via RDSR, RDSR2, RDSR3 commands
987 Not all SPI flash supports all three commands. The upper 1 or 2
991 SPIFLASH_RDSR2
= 0x35
992 SPIFLASH_RDSR3
= 0x15
996 for cmd
in [SPIFLASH_RDSR
, SPIFLASH_RDSR2
, SPIFLASH_RDSR3
][0:num_bytes
]:
997 status
+= self
.run_spiflash_command(cmd
, read_bits
=8) << shift
1001 def write_status(self
, new_status
, num_bytes
=2, set_non_volatile
=False):
1002 """Write up to 24 bits (num_bytes) of new status register
1004 num_bytes can be 1, 2 or 3.
1006 Not all flash supports the additional commands to write the
1007 second and third byte of the status register. When writing 2
1008 bytes, esptool also sends a 16-byte WRSR command (as some
1009 flash types use this instead of WRSR2.)
1011 If the set_non_volatile flag is set, non-volatile bits will
1012 be set as well as volatile ones (WREN used instead of WEVSR).
1015 SPIFLASH_WRSR
= 0x01
1016 SPIFLASH_WRSR2
= 0x31
1017 SPIFLASH_WRSR3
= 0x11
1018 SPIFLASH_WEVSR
= 0x50
1019 SPIFLASH_WREN
= 0x06
1020 SPIFLASH_WRDI
= 0x04
1022 enable_cmd
= SPIFLASH_WREN
if set_non_volatile
else SPIFLASH_WEVSR
1024 # try using a 16-bit WRSR (not supported by all chips)
1025 # this may be redundant, but shouldn't hurt
1027 self
.run_spiflash_command(enable_cmd
)
1028 self
.run_spiflash_command(SPIFLASH_WRSR
, struct
.pack("<H", new_status
))
1030 # also try using individual commands (also not supported by all chips for num_bytes 2 & 3)
1031 for cmd
in [SPIFLASH_WRSR
, SPIFLASH_WRSR2
, SPIFLASH_WRSR3
][0:num_bytes
]:
1032 self
.run_spiflash_command(enable_cmd
)
1033 self
.run_spiflash_command(cmd
, struct
.pack("B", new_status
& 0xFF))
1036 self
.run_spiflash_command(SPIFLASH_WRDI
)
1038 def get_crystal_freq(self
):
1039 # Figure out the crystal frequency from the UART clock divider
1040 # Returns a normalized value in integer MHz (40 or 26 are the only supported values)
1042 # The logic here is:
1043 # - We know that our baud rate and the ESP UART baud rate are roughly the same, or we couldn't communicate
1044 # - We can read the UART clock divider register to know how the ESP derives this from the APB bus frequency
1045 # - Multiplying these two together gives us the bus frequency which is either the crystal frequency (ESP32)
1046 # or double the crystal frequency (ESP8266). See the self.XTAL_CLK_DIVIDER parameter for this factor.
1047 uart_div
= self
.read_reg(self
.UART_CLKDIV_REG
) & self
.UART_CLKDIV_MASK
1048 est_xtal
= (self
._port
.baudrate
* uart_div
) / 1e6
/ self
.XTAL_CLK_DIVIDER
1049 norm_xtal
= 40 if est_xtal
> 33 else 26
1050 if abs(norm_xtal
- est_xtal
) > 1:
1051 print("WARNING: Detected crystal freq %.2fMHz is quite different to normalized freq %dMHz. Unsupported crystal in use?" % (est_xtal
, norm_xtal
))
1054 def hard_reset(self
):
1055 self
._setRTS
(True) # EN->LOW
1059 def soft_reset(self
, stay_in_bootloader
):
1060 if not self
.IS_STUB
:
1061 if stay_in_bootloader
:
1062 return # ROM bootloader is already in bootloader!
1064 # 'run user code' is as close to a soft reset as we can do
1065 self
.flash_begin(0, 0)
1066 self
.flash_finish(False)
1068 if stay_in_bootloader
:
1069 # soft resetting from the stub loader
1070 # will re-load the ROM bootloader
1071 self
.flash_begin(0, 0)
1072 self
.flash_finish(True)
1073 elif self
.CHIP_NAME
!= "ESP8266":
1074 raise FatalError("Soft resetting is currently only supported on ESP8266")
1076 # running user code from stub loader requires some hacks
1077 # in the stub loader
1078 self
.command(self
.ESP_RUN_USER_CODE
, wait_response
=False)
1081 class ESP8266ROM(ESPLoader
):
1082 """ Access class for ESP8266 ROM bootloader
1084 CHIP_NAME
= "ESP8266"
1087 CHIP_DETECT_MAGIC_VALUE
= 0xfff0c101
1090 ESP_OTP_MAC0
= 0x3ff00050
1091 ESP_OTP_MAC1
= 0x3ff00054
1092 ESP_OTP_MAC3
= 0x3ff0005c
1094 SPI_REG_BASE
= 0x60000200
1096 SPI_USR1_OFFS
= 0x20
1097 SPI_USR2_OFFS
= 0x24
1098 SPI_MOSI_DLEN_OFFS
= None
1099 SPI_MISO_DLEN_OFFS
= None
1102 UART_CLKDIV_REG
= 0x60000014
1104 XTAL_CLK_DIVIDER
= 2
1118 BOOTLOADER_FLASH_OFFSET
= 0
1120 MEMORY_MAP
= [[0x3FF00000, 0x3FF00010, "DPORT"],
1121 [0x3FFE8000, 0x40000000, "DRAM"],
1122 [0x40100000, 0x40108000, "IRAM"],
1123 [0x40201010, 0x402E1010, "IROM"]]
1125 def get_efuses(self
):
1126 # Return the 128 bits of ESP8266 efuse as a single Python integer
1127 result
= self
.read_reg(0x3ff0005c) << 96
1128 result |
= self
.read_reg(0x3ff00058) << 64
1129 result |
= self
.read_reg(0x3ff00054) << 32
1130 result |
= self
.read_reg(0x3ff00050)
1133 def get_chip_description(self
):
1134 efuses
= self
.get_efuses()
1135 is_8285
= (efuses
& ((1 << 4) |
1 << 80)) != 0 # One or the other efuse bit is set for ESP8285
1136 return "ESP8285" if is_8285
else "ESP8266EX"
1138 def get_chip_features(self
):
1140 if self
.get_chip_description() == "ESP8285":
1141 features
+= ["Embedded Flash"]
1144 def flash_spi_attach(self
, hspi_arg
):
1146 super(ESP8266ROM
, self
).flash_spi_attach(hspi_arg
)
1148 # ESP8266 ROM has no flash_spi_attach command in serial protocol,
1149 # but flash_begin will do it
1150 self
.flash_begin(0, 0)
1152 def flash_set_parameters(self
, size
):
1153 # not implemented in ROM, but OK to silently skip for ROM
1155 super(ESP8266ROM
, self
).flash_set_parameters(size
)
1158 """ Read Chip ID from efuse - the equivalent of the SDK system_get_chip_id() function """
1159 id0
= self
.read_reg(self
.ESP_OTP_MAC0
)
1160 id1
= self
.read_reg(self
.ESP_OTP_MAC1
)
1161 return (id0
>> 24) |
((id1
& MAX_UINT24
) << 8)
1164 """ Read MAC from OTP ROM """
1165 mac0
= self
.read_reg(self
.ESP_OTP_MAC0
)
1166 mac1
= self
.read_reg(self
.ESP_OTP_MAC1
)
1167 mac3
= self
.read_reg(self
.ESP_OTP_MAC3
)
1169 oui
= ((mac3
>> 16) & 0xff, (mac3
>> 8) & 0xff, mac3
& 0xff)
1170 elif ((mac1
>> 16) & 0xff) == 0:
1171 oui
= (0x18, 0xfe, 0x34)
1172 elif ((mac1
>> 16) & 0xff) == 1:
1173 oui
= (0xac, 0xd0, 0x74)
1175 raise FatalError("Unknown OUI")
1176 return oui
+ ((mac1
>> 8) & 0xff, mac1
& 0xff, (mac0
>> 24) & 0xff)
1178 def get_erase_size(self
, offset
, size
):
1179 """ Calculate an erase size given a specific size in bytes.
1181 Provides a workaround for the bootloader erase bug."""
1183 sectors_per_block
= 16
1184 sector_size
= self
.FLASH_SECTOR_SIZE
1185 num_sectors
= (size
+ sector_size
- 1) // sector_size
1186 start_sector
= offset
// sector_size
1188 head_sectors
= sectors_per_block
- (start_sector
% sectors_per_block
)
1189 if num_sectors
< head_sectors
:
1190 head_sectors
= num_sectors
1192 if num_sectors
< 2 * head_sectors
:
1193 return (num_sectors
+ 1) // 2 * sector_size
1195 return (num_sectors
- head_sectors
) * sector_size
1197 def override_vddsdio(self
, new_voltage
):
1198 raise NotImplementedInROMError("Overriding VDDSDIO setting only applies to ESP32")
1201 class ESP8266StubLoader(ESP8266ROM
):
1202 """ Access class for ESP8266 stub loader, runs on top of ROM.
1204 FLASH_WRITE_SIZE
= 0x0800 # matches MAX_WRITE_BLOCK in stub_loader.c
1207 def __init__(self
, rom_loader
):
1208 self
.secure_download_mode
= rom_loader
.secure_download_mode
1209 self
._port
= rom_loader
._port
1210 self
._trace
_enabled
= rom_loader
._trace
_enabled
1211 self
.flush_input() # resets _slip_reader
1213 def get_erase_size(self
, offset
, size
):
1214 return size
# stub doesn't have same size bug as ROM loader
1217 ESP8266ROM
.STUB_CLASS
= ESP8266StubLoader
1220 class ESP32ROM(ESPLoader
):
1221 """Access class for ESP32 ROM bootloader
1228 CHIP_DETECT_MAGIC_VALUE
= 0x00f01d83
1230 IROM_MAP_START
= 0x400d0000
1231 IROM_MAP_END
= 0x40400000
1233 DROM_MAP_START
= 0x3F400000
1234 DROM_MAP_END
= 0x3F800000
1236 # ESP32 uses a 4 byte status reply
1237 STATUS_BYTES_LENGTH
= 4
1239 SPI_REG_BASE
= 0x3ff42000
1241 SPI_USR1_OFFS
= 0x20
1242 SPI_USR2_OFFS
= 0x24
1243 SPI_MOSI_DLEN_OFFS
= 0x28
1244 SPI_MISO_DLEN_OFFS
= 0x2c
1245 EFUSE_RD_REG_BASE
= 0x3ff5a000
1247 EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG
= EFUSE_RD_REG_BASE
+ 0x18
1248 EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
= (1 << 7) # EFUSE_RD_DISABLE_DL_ENCRYPT
1250 DR_REG_SYSCON_BASE
= 0x3ff66000
1254 UART_CLKDIV_REG
= 0x3ff40014
1256 XTAL_CLK_DIVIDER
= 1
1266 BOOTLOADER_FLASH_OFFSET
= 0x1000
1268 OVERRIDE_VDDSDIO_CHOICES
= ["1.8V", "1.9V", "OFF"]
1270 MEMORY_MAP
= [[0x00000000, 0x00010000, "PADDING"],
1271 [0x3F400000, 0x3F800000, "DROM"],
1272 [0x3F800000, 0x3FC00000, "EXTRAM_DATA"],
1273 [0x3FF80000, 0x3FF82000, "RTC_DRAM"],
1274 [0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"],
1275 [0x3FFAE000, 0x40000000, "DRAM"],
1276 [0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"],
1277 [0x40000000, 0x40070000, "IROM"],
1278 [0x40070000, 0x40078000, "CACHE_PRO"],
1279 [0x40078000, 0x40080000, "CACHE_APP"],
1280 [0x40080000, 0x400A0000, "IRAM"],
1281 [0x400A0000, 0x400BFFFC, "DIRAM_IRAM"],
1282 [0x400C0000, 0x400C2000, "RTC_IRAM"],
1283 [0x400D0000, 0x40400000, "IROM"],
1284 [0x50000000, 0x50002000, "RTC_DATA"]]
1286 FLASH_ENCRYPTED_WRITE_ALIGN
= 32
1288 """ Try to read the BLOCK1 (encryption key) and check if it is valid """
1290 def is_flash_encryption_key_valid(self
):
1292 """ Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1
1293 this bit is at position 16 in EFUSE_BLK0_RDATA0_REG """
1294 word0
= self
.read_efuse(0)
1295 rd_disable
= (word0
>> 16) & 0x1
1297 # reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed
1301 # reading of BLOCK1 is ALLOWED so we will read and verify for non-zero.
1302 # When ESP32 has not generated AES/encryption key in BLOCK1, the contents will be readable and 0.
1303 # If the flash encryption is enabled it is expected to have a valid non-zero key. We break out on
1304 # first occurance of non-zero value
1306 for i
in range(len(key_word
)):
1307 key_word
[i
] = self
.read_efuse(14 + i
)
1308 # key is non-zero so break & return
1309 if key_word
[i
] != 0:
1313 def get_flash_crypt_config(self
):
1314 """ For flash encryption related commands we need to make sure
1315 user has programmed all the relevant efuse correctly so before
1316 writing encrypted write_flash_encrypt esptool will verify the values
1317 of flash_crypt_config to be non zero if they are not read
1318 protected. If the values are zero a warning will be printed
1320 bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config
1321 this bit is at position 19 in EFUSE_BLK0_RDATA0_REG """
1322 word0
= self
.read_efuse(0)
1323 rd_disable
= (word0
>> 19) & 0x1
1326 """ we can read the flash_crypt_config efuse value
1327 so go & read it (EFUSE_BLK0_RDATA5_REG[31:28]) """
1328 word5
= self
.read_efuse(5)
1329 word5
= (word5
>> 28) & 0xF
1332 # if read of the efuse is disabled we assume it is set correctly
1335 def get_encrypted_download_disabled(self
):
1336 if self
.read_reg(self
.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG
) & self
.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
:
1341 def get_pkg_version(self
):
1342 word3
= self
.read_efuse(3)
1343 pkg_version
= (word3
>> 9) & 0x07
1344 pkg_version
+= ((word3
>> 2) & 0x1) << 3
1347 def get_chip_revision(self
):
1348 word3
= self
.read_efuse(3)
1349 word5
= self
.read_efuse(5)
1350 apb_ctl_date
= self
.read_reg(self
.DR_REG_SYSCON_BASE
+ 0x7C)
1352 rev_bit0
= (word3
>> 15) & 0x1
1353 rev_bit1
= (word5
>> 20) & 0x1
1354 rev_bit2
= (apb_ctl_date
>> 31) & 0x1
1365 def get_chip_description(self
):
1366 pkg_version
= self
.get_pkg_version()
1367 chip_revision
= self
.get_chip_revision()
1368 rev3
= (chip_revision
== 3)
1369 single_core
= self
.read_efuse(3) & (1 << 0) # CHIP_VER DIS_APP_CPU
1372 0: "ESP32-S0WDQ6" if single_core
else "ESP32-D0WDQ6",
1373 1: "ESP32-S0WD" if single_core
else "ESP32-D0WD",
1376 5: "ESP32-PICO-V3" if rev3
else "ESP32-PICO-D4",
1377 6: "ESP32-PICO-V3-02",
1378 }.get(pkg_version
, "unknown ESP32")
1380 # ESP32-D0WD-V3, ESP32-D0WDQ6-V3
1381 if chip_name
.startswith("ESP32-D0WD") and rev3
:
1384 return "%s (revision %d)" % (chip_name
, chip_revision
)
1386 def get_chip_features(self
):
1388 word3
= self
.read_efuse(3)
1390 # names of variables in this section are lowercase
1391 # versions of EFUSE names as documented in TRM and
1392 # ESP-IDF efuse_reg.h
1394 chip_ver_dis_bt
= word3
& (1 << 1)
1395 if chip_ver_dis_bt
== 0:
1398 chip_ver_dis_app_cpu
= word3
& (1 << 0)
1399 if chip_ver_dis_app_cpu
:
1400 features
+= ["Single Core"]
1402 features
+= ["Dual Core"]
1404 chip_cpu_freq_rated
= word3
& (1 << 13)
1405 if chip_cpu_freq_rated
:
1406 chip_cpu_freq_low
= word3
& (1 << 12)
1407 if chip_cpu_freq_low
:
1408 features
+= ["160MHz"]
1410 features
+= ["240MHz"]
1412 pkg_version
= self
.get_pkg_version()
1413 if pkg_version
in [2, 4, 5, 6]:
1414 features
+= ["Embedded Flash"]
1416 if pkg_version
== 6:
1417 features
+= ["Embedded PSRAM"]
1419 word4
= self
.read_efuse(4)
1420 adc_vref
= (word4
>> 8) & 0x1F
1422 features
+= ["VRef calibration in efuse"]
1424 blk3_part_res
= word3
>> 14 & 0x1
1426 features
+= ["BLK3 partially reserved"]
1428 word6
= self
.read_efuse(6)
1429 coding_scheme
= word6
& 0x3
1430 features
+= ["Coding Scheme %s" % {
1433 2: "Repeat (UNSUPPORTED)",
1434 3: "Invalid"}[coding_scheme
]]
1438 def read_efuse(self
, n
):
1439 """ Read the nth word of the ESP3x EFUSE region. """
1440 return self
.read_reg(self
.EFUSE_RD_REG_BASE
+ (4 * n
))
1443 raise NotSupportedError(self
, "chip_id")
1446 """ Read MAC from EFUSE region """
1447 words
= [self
.read_efuse(2), self
.read_efuse(1)]
1448 bitstring
= struct
.pack(">II", *words
)
1449 bitstring
= bitstring
[2:8] # trim the 2 byte CRC
1451 return tuple(ord(b
) for b
in bitstring
)
1452 except TypeError: # Python 3, bitstring elements are already bytes
1453 return tuple(bitstring
)
1455 def get_erase_size(self
, offset
, size
):
1458 def override_vddsdio(self
, new_voltage
):
1459 new_voltage
= new_voltage
.upper()
1460 if new_voltage
not in self
.OVERRIDE_VDDSDIO_CHOICES
:
1461 raise FatalError("The only accepted VDDSDIO overrides are '1.8V', '1.9V' and 'OFF'")
1462 RTC_CNTL_SDIO_CONF_REG
= 0x3ff48074
1463 RTC_CNTL_XPD_SDIO_REG
= (1 << 31)
1464 RTC_CNTL_DREFH_SDIO_M
= (3 << 29)
1465 RTC_CNTL_DREFM_SDIO_M
= (3 << 27)
1466 RTC_CNTL_DREFL_SDIO_M
= (3 << 25)
1467 # RTC_CNTL_SDIO_TIEH = (1 << 23) # not used here, setting TIEH=1 would set 3.3V output, not safe for esptool.py to do
1468 RTC_CNTL_SDIO_FORCE
= (1 << 22)
1469 RTC_CNTL_SDIO_PD_EN
= (1 << 21)
1471 reg_val
= RTC_CNTL_SDIO_FORCE
# override efuse setting
1472 reg_val |
= RTC_CNTL_SDIO_PD_EN
1473 if new_voltage
!= "OFF":
1474 reg_val |
= RTC_CNTL_XPD_SDIO_REG
# enable internal LDO
1475 if new_voltage
== "1.9V":
1476 reg_val |
= (RTC_CNTL_DREFH_SDIO_M | RTC_CNTL_DREFM_SDIO_M | RTC_CNTL_DREFL_SDIO_M
) # boost voltage
1477 self
.write_reg(RTC_CNTL_SDIO_CONF_REG
, reg_val
)
1478 print("VDDSDIO regulator set to %s" % new_voltage
)
1480 def read_flash_slow(self
, offset
, length
, progress_fn
):
1481 BLOCK_LEN
= 64 # ROM read limit per command (this limit is why it's so slow)
1484 while len(data
) < length
:
1485 block_len
= min(BLOCK_LEN
, length
- len(data
))
1486 r
= self
.check_command("read flash block", self
.ESP_READ_FLASH_SLOW
,
1487 struct
.pack('<II', offset
+ len(data
), block_len
))
1488 if len(r
) < block_len
:
1489 raise FatalError("Expected %d byte block, got %d bytes. Serial errors?" % (block_len
, len(r
)))
1490 data
+= r
[:block_len
] # command always returns 64 byte buffer, regardless of how many bytes were actually read from flash
1491 if progress_fn
and (len(data
) % 1024 == 0 or len(data
) == length
):
1492 progress_fn(len(data
), length
)
1496 class ESP32S2ROM(ESP32ROM
):
1497 CHIP_NAME
= "ESP32-S2"
1500 IROM_MAP_START
= 0x40080000
1501 IROM_MAP_END
= 0x40b80000
1502 DROM_MAP_START
= 0x3F000000
1503 DROM_MAP_END
= 0x3F3F0000
1505 CHIP_DETECT_MAGIC_VALUE
= 0x000007c6
1507 SPI_REG_BASE
= 0x3f402000
1509 SPI_USR1_OFFS
= 0x1c
1510 SPI_USR2_OFFS
= 0x20
1511 SPI_MOSI_DLEN_OFFS
= 0x24
1512 SPI_MISO_DLEN_OFFS
= 0x28
1515 MAC_EFUSE_REG
= 0x3f41A044 # ESP32-S2 has special block for MAC efuses
1517 UART_CLKDIV_REG
= 0x3f400014
1519 FLASH_ENCRYPTED_WRITE_ALIGN
= 16
1521 # todo: use espefuse APIs to get this info
1522 EFUSE_BASE
= 0x3f41A000
1523 EFUSE_RD_REG_BASE
= EFUSE_BASE
+ 0x030 # BLOCK0 read base address
1525 EFUSE_PURPOSE_KEY0_REG
= EFUSE_BASE
+ 0x34
1526 EFUSE_PURPOSE_KEY0_SHIFT
= 24
1527 EFUSE_PURPOSE_KEY1_REG
= EFUSE_BASE
+ 0x34
1528 EFUSE_PURPOSE_KEY1_SHIFT
= 28
1529 EFUSE_PURPOSE_KEY2_REG
= EFUSE_BASE
+ 0x38
1530 EFUSE_PURPOSE_KEY2_SHIFT
= 0
1531 EFUSE_PURPOSE_KEY3_REG
= EFUSE_BASE
+ 0x38
1532 EFUSE_PURPOSE_KEY3_SHIFT
= 4
1533 EFUSE_PURPOSE_KEY4_REG
= EFUSE_BASE
+ 0x38
1534 EFUSE_PURPOSE_KEY4_SHIFT
= 8
1535 EFUSE_PURPOSE_KEY5_REG
= EFUSE_BASE
+ 0x38
1536 EFUSE_PURPOSE_KEY5_SHIFT
= 12
1538 EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG
= EFUSE_RD_REG_BASE
1539 EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
= 1 << 19
1541 PURPOSE_VAL_XTS_AES256_KEY_1
= 2
1542 PURPOSE_VAL_XTS_AES256_KEY_2
= 3
1543 PURPOSE_VAL_XTS_AES128_KEY
= 4
1545 UARTDEV_BUF_NO
= 0x3ffffd14 # Variable in ROM .bss which indicates the port in use
1546 UARTDEV_BUF_NO_USB
= 2 # Value of the above variable indicating that USB is in use
1548 USB_RAM_BLOCK
= 0x800 # Max block size USB CDC is used
1550 GPIO_STRAP_REG
= 0x3f404038
1551 GPIO_STRAP_SPI_BOOT_MASK
= 0x8 # Not download mode
1552 RTC_CNTL_OPTION1_REG
= 0x3f408128
1553 RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK
= 0x1 # Is download mode forced over USB?
1555 MEMORY_MAP
= [[0x00000000, 0x00010000, "PADDING"],
1556 [0x3F000000, 0x3FF80000, "DROM"],
1557 [0x3F500000, 0x3FF80000, "EXTRAM_DATA"],
1558 [0x3FF9E000, 0x3FFA0000, "RTC_DRAM"],
1559 [0x3FF9E000, 0x40000000, "BYTE_ACCESSIBLE"],
1560 [0x3FF9E000, 0x40072000, "MEM_INTERNAL"],
1561 [0x3FFB0000, 0x40000000, "DRAM"],
1562 [0x40000000, 0x4001A100, "IROM_MASK"],
1563 [0x40020000, 0x40070000, "IRAM"],
1564 [0x40070000, 0x40072000, "RTC_IRAM"],
1565 [0x40080000, 0x40800000, "IROM"],
1566 [0x50000000, 0x50002000, "RTC_DATA"]]
1568 def get_pkg_version(self
):
1570 block1_addr
= self
.EFUSE_BASE
+ 0x044
1571 word3
= self
.read_reg(block1_addr
+ (4 * num_word
))
1572 pkg_version
= (word3
>> 21) & 0x0F
1575 def get_chip_description(self
):
1580 }.get(self
.get_pkg_version(), "unknown ESP32-S2")
1582 return "%s" % (chip_name
)
1584 def get_chip_features(self
):
1587 if self
.secure_download_mode
:
1588 features
+= ["Secure Download Mode Enabled"]
1590 pkg_version
= self
.get_pkg_version()
1592 if pkg_version
in [1, 2]:
1593 if pkg_version
== 1:
1594 features
+= ["Embedded 2MB Flash"]
1595 elif pkg_version
== 2:
1596 features
+= ["Embedded 4MB Flash"]
1597 features
+= ["105C temp rating"]
1600 block2_addr
= self
.EFUSE_BASE
+ 0x05C
1601 word4
= self
.read_reg(block2_addr
+ (4 * num_word
))
1602 block2_version
= (word4
>> 4) & 0x07
1604 if block2_version
== 1:
1605 features
+= ["ADC and temperature sensor calibration in BLK2 of efuse"]
1608 def get_crystal_freq(self
):
1609 # ESP32-S2 XTAL is fixed to 40MHz
1612 def override_vddsdio(self
, new_voltage
):
1613 raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-S2")
1616 mac0
= self
.read_reg(self
.MAC_EFUSE_REG
)
1617 mac1
= self
.read_reg(self
.MAC_EFUSE_REG
+ 4) # only bottom 16 bits are MAC
1618 bitstring
= struct
.pack(">II", mac1
, mac0
)[2:]
1620 return tuple(ord(b
) for b
in bitstring
)
1621 except TypeError: # Python 3, bitstring elements are already bytes
1622 return tuple(bitstring
)
1624 def get_flash_crypt_config(self
):
1625 return None # doesn't exist on ESP32-S2
1627 def get_key_block_purpose(self
, key_block
):
1628 if key_block
< 0 or key_block
> 5:
1629 raise FatalError("Valid key block numbers must be in range 0-5")
1631 reg
, shift
= [(self
.EFUSE_PURPOSE_KEY0_REG
, self
.EFUSE_PURPOSE_KEY0_SHIFT
),
1632 (self
.EFUSE_PURPOSE_KEY1_REG
, self
.EFUSE_PURPOSE_KEY1_SHIFT
),
1633 (self
.EFUSE_PURPOSE_KEY2_REG
, self
.EFUSE_PURPOSE_KEY2_SHIFT
),
1634 (self
.EFUSE_PURPOSE_KEY3_REG
, self
.EFUSE_PURPOSE_KEY3_SHIFT
),
1635 (self
.EFUSE_PURPOSE_KEY4_REG
, self
.EFUSE_PURPOSE_KEY4_SHIFT
),
1636 (self
.EFUSE_PURPOSE_KEY5_REG
, self
.EFUSE_PURPOSE_KEY5_SHIFT
)][key_block
]
1637 return (self
.read_reg(reg
) >> shift
) & 0xF
1639 def is_flash_encryption_key_valid(self
):
1640 # Need to see either an AES-128 key or two AES-256 keys
1641 purposes
= [self
.get_key_block_purpose(b
) for b
in range(6)]
1643 if any(p
== self
.PURPOSE_VAL_XTS_AES128_KEY
for p
in purposes
):
1646 return any(p
== self
.PURPOSE_VAL_XTS_AES256_KEY_1
for p
in purposes
) \
1647 and any(p
== self
.PURPOSE_VAL_XTS_AES256_KEY_2
for p
in purposes
)
1649 def uses_usb(self
, _cache
=[]):
1650 if self
.secure_download_mode
:
1651 return False # can't detect native USB in secure download mode
1653 buf_no
= self
.read_reg(self
.UARTDEV_BUF_NO
) & 0xff
1654 _cache
.append(buf_no
== self
.UARTDEV_BUF_NO_USB
)
1657 def _post_connect(self
):
1659 self
.ESP_RAM_BLOCK
= self
.USB_RAM_BLOCK
1661 def _check_if_can_reset(self
):
1663 Check the strapping register to see if we can reset out of download mode.
1665 if os
.getenv("ESPTOOL_TESTING") is not None:
1666 print("ESPTOOL_TESTING is set, ignoring strapping mode check")
1667 # Esptool tests over USB CDC run with GPIO0 strapped low, don't complain in this case.
1669 strap_reg
= self
.read_reg(self
.GPIO_STRAP_REG
)
1670 force_dl_reg
= self
.read_reg(self
.RTC_CNTL_OPTION1_REG
)
1671 if strap_reg
& self
.GPIO_STRAP_SPI_BOOT_MASK
== 0 and force_dl_reg
& self
.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK
== 0:
1672 print("ERROR: {} chip was placed into download mode using GPIO0.\n"
1673 "esptool.py can not exit the download mode over USB. "
1674 "To run the app, reset the chip manually.\n"
1675 "To suppress this error, set --after option to 'no_reset'.".format(self
.get_chip_description()))
1678 def hard_reset(self
):
1680 self
._check
_if
_can
_reset
()
1682 self
._setRTS
(True) # EN->LOW
1684 # Give the chip some time to come out of reset, to be able to handle further DTR/RTS transitions
1692 class ESP32S3BETA2ROM(ESP32ROM
):
1693 CHIP_NAME
= "ESP32-S3(beta2)"
1696 IROM_MAP_START
= 0x42000000
1697 IROM_MAP_END
= 0x44000000
1698 DROM_MAP_START
= 0x3c000000
1699 DROM_MAP_END
= 0x3e000000
1701 UART_DATE_REG_ADDR
= 0x60000080
1703 CHIP_DETECT_MAGIC_VALUE
= 0xeb004136
1705 SPI_REG_BASE
= 0x60002000
1707 SPI_USR1_OFFS
= 0x1c
1708 SPI_USR2_OFFS
= 0x20
1709 SPI_MOSI_DLEN_OFFS
= 0x24
1710 SPI_MISO_DLEN_OFFS
= 0x28
1713 EFUSE_REG_BASE
= 0x6001A030 # BLOCK0 read base address
1715 MAC_EFUSE_REG
= 0x6001A000 # ESP32S3 has special block for MAC efuses
1717 UART_CLKDIV_REG
= 0x60000014
1719 GPIO_STRAP_REG
= 0x60004038
1721 MEMORY_MAP
= [[0x00000000, 0x00010000, "PADDING"],
1722 [0x3C000000, 0x3D000000, "DROM"],
1723 [0x3D000000, 0x3E000000, "EXTRAM_DATA"],
1724 [0x600FE000, 0x60100000, "RTC_DRAM"],
1725 [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
1726 [0x3FC88000, 0x403E2000, "MEM_INTERNAL"],
1727 [0x3FC88000, 0x3FD00000, "DRAM"],
1728 [0x40000000, 0x4001A100, "IROM_MASK"],
1729 [0x40370000, 0x403E0000, "IRAM"],
1730 [0x600FE000, 0x60100000, "RTC_IRAM"],
1731 [0x42000000, 0x42800000, "IROM"],
1732 [0x50000000, 0x50002000, "RTC_DATA"]]
1734 def get_chip_description(self
):
1735 return "ESP32-S3(beta2)"
1737 def get_chip_features(self
):
1738 return ["WiFi", "BLE"]
1740 def get_crystal_freq(self
):
1741 # ESP32S3 XTAL is fixed to 40MHz
1744 def override_vddsdio(self
, new_voltage
):
1745 raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-S3")
1748 mac0
= self
.read_reg(self
.MAC_EFUSE_REG
)
1749 mac1
= self
.read_reg(self
.MAC_EFUSE_REG
+ 4) # only bottom 16 bits are MAC
1750 bitstring
= struct
.pack(">II", mac1
, mac0
)[2:]
1752 return tuple(ord(b
) for b
in bitstring
)
1753 except TypeError: # Python 3, bitstring elements are already bytes
1754 return tuple(bitstring
)
1757 class ESP32C3ROM(ESP32ROM
):
1758 CHIP_NAME
= "ESP32-C3"
1761 IROM_MAP_START
= 0x42000000
1762 IROM_MAP_END
= 0x42800000
1763 DROM_MAP_START
= 0x3c000000
1764 DROM_MAP_END
= 0x3c800000
1766 SPI_REG_BASE
= 0x3f402000
1768 SPI_USR1_OFFS
= 0x1c
1769 SPI_USR2_OFFS
= 0x20
1770 SPI_MOSI_DLEN_OFFS
= 0x24
1771 SPI_MISO_DLEN_OFFS
= 0x28
1774 BOOTLOADER_FLASH_OFFSET
= 0x0
1776 CHIP_DETECT_MAGIC_VALUE
= 0x6921506f
1778 UART_DATE_REG_ADDR
= 0x60000000 + 0x7c
1780 EFUSE_BASE
= 0x60008800
1781 MAC_EFUSE_REG
= EFUSE_BASE
+ 0x044
1783 GPIO_STRAP_REG
= 0x3f404038
1785 FLASH_ENCRYPTED_WRITE_ALIGN
= 16
1787 MEMORY_MAP
= [[0x00000000, 0x00010000, "PADDING"],
1788 [0x3C000000, 0x3C800000, "DROM"],
1789 [0x3FC80000, 0x3FCE0000, "DRAM"],
1790 [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
1791 [0x3FF00000, 0x3FF20000, "DROM_MASK"],
1792 [0x40000000, 0x40060000, "IROM_MASK"],
1793 [0x42000000, 0x42800000, "IROM"],
1794 [0x4037C000, 0x403E0000, "IRAM"],
1795 [0x50000000, 0x50002000, "RTC_IRAM"],
1796 [0x50000000, 0x50002000, "RTC_DRAM"],
1797 [0x600FE000, 0x60100000, "MEM_INTERNAL2"]]
1799 def get_pkg_version(self
):
1801 block1_addr
= self
.EFUSE_BASE
+ 0x044
1802 word3
= self
.read_reg(block1_addr
+ (4 * num_word
))
1803 pkg_version
= (word3
>> 21) & 0x0F
1806 def get_chip_description(self
):
1809 }.get(self
.get_pkg_version(), "unknown ESP32-C3")
1811 return "%s" % (chip_name
)
1813 def get_chip_features(self
):
1816 def get_crystal_freq(self
):
1817 # ESP32C3 XTAL is fixed to 40MHz
1820 def override_vddsdio(self
, new_voltage
):
1821 raise NotImplementedInROMError("VDD_SDIO overrides are not supported for ESP32-C3")
1824 mac0
= self
.read_reg(self
.MAC_EFUSE_REG
)
1825 mac1
= self
.read_reg(self
.MAC_EFUSE_REG
+ 4) # only bottom 16 bits are MAC
1826 bitstring
= struct
.pack(">II", mac1
, mac0
)[2:]
1828 return tuple(ord(b
) for b
in bitstring
)
1829 except TypeError: # Python 3, bitstring elements are already bytes
1830 return tuple(bitstring
)
1833 class ESP32StubLoader(ESP32ROM
):
1834 """ Access class for ESP32 stub loader, runs on top of ROM.
1836 FLASH_WRITE_SIZE
= 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
1837 STATUS_BYTES_LENGTH
= 2 # same as ESP8266, different to ESP32 ROM
1840 def __init__(self
, rom_loader
):
1841 self
.secure_download_mode
= rom_loader
.secure_download_mode
1842 self
._port
= rom_loader
._port
1843 self
._trace
_enabled
= rom_loader
._trace
_enabled
1844 self
.flush_input() # resets _slip_reader
1847 ESP32ROM
.STUB_CLASS
= ESP32StubLoader
1850 class ESP32S2StubLoader(ESP32S2ROM
):
1851 """ Access class for ESP32-S2 stub loader, runs on top of ROM.
1853 (Basically the same as ESP32StubLoader, but different base class.
1854 Can possibly be made into a mixin.)
1856 FLASH_WRITE_SIZE
= 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
1857 STATUS_BYTES_LENGTH
= 2 # same as ESP8266, different to ESP32 ROM
1860 def __init__(self
, rom_loader
):
1861 self
.secure_download_mode
= rom_loader
.secure_download_mode
1862 self
._port
= rom_loader
._port
1863 self
._trace
_enabled
= rom_loader
._trace
_enabled
1864 self
.flush_input() # resets _slip_reader
1866 if rom_loader
.uses_usb():
1867 self
.ESP_RAM_BLOCK
= self
.USB_RAM_BLOCK
1868 self
.FLASH_WRITE_SIZE
= self
.USB_RAM_BLOCK
1871 ESP32S2ROM
.STUB_CLASS
= ESP32S2StubLoader
1874 class ESP32S3BETA2StubLoader(ESP32S3BETA2ROM
):
1875 """ Access class for ESP32S3 stub loader, runs on top of ROM.
1877 (Basically the same as ESP32StubLoader, but different base class.
1878 Can possibly be made into a mixin.)
1880 FLASH_WRITE_SIZE
= 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
1881 STATUS_BYTES_LENGTH
= 2 # same as ESP8266, different to ESP32 ROM
1884 def __init__(self
, rom_loader
):
1885 self
.secure_download_mode
= rom_loader
.secure_download_mode
1886 self
._port
= rom_loader
._port
1887 self
._trace
_enabled
= rom_loader
._trace
_enabled
1888 self
.flush_input() # resets _slip_reader
1891 ESP32S3BETA2ROM
.STUB_CLASS
= ESP32S3BETA2StubLoader
1894 class ESP32C3StubLoader(ESP32C3ROM
):
1895 """ Access class for ESP32C3 stub loader, runs on top of ROM.
1897 (Basically the same as ESP32StubLoader, but different base class.
1898 Can possibly be made into a mixin.)
1900 FLASH_WRITE_SIZE
= 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
1901 STATUS_BYTES_LENGTH
= 2 # same as ESP8266, different to ESP32 ROM
1904 def __init__(self
, rom_loader
):
1905 self
.secure_download_mode
= rom_loader
.secure_download_mode
1906 self
._port
= rom_loader
._port
1907 self
._trace
_enabled
= rom_loader
._trace
_enabled
1908 self
.flush_input() # resets _slip_reader
1911 ESP32C3ROM
.STUB_CLASS
= ESP32C3StubLoader
1914 class ESPBOOTLOADER(object):
1915 """ These are constants related to software ESP bootloader, working with 'v2' image files """
1917 # First byte of the "v2" application image
1918 IMAGE_V2_MAGIC
= 0xea
1920 # First 'segment' value in a "v2" application image, appears to be a constant version value?
1921 IMAGE_V2_SEGMENT
= 4
1924 def LoadFirmwareImage(chip
, filename
):
1925 """ Load a firmware image. Can be for any supported SoC.
1927 ESP8266 images will be examined to determine if they are original ROM firmware images (ESP8266ROMFirmwareImage)
1928 or "v2" OTA bootloader images.
1930 Returns a BaseFirmwareImage subclass, either ESP8266ROMFirmwareImage (v1) or ESP8266V2FirmwareImage (v2).
1932 chip
= chip
.lower().replace("-", "")
1933 with
open(filename
, 'rb') as f
:
1935 return ESP32FirmwareImage(f
)
1936 elif chip
== "esp32s2":
1937 return ESP32S2FirmwareImage(f
)
1938 elif chip
== "esp32s3beta2":
1939 return ESP32S3BETA2FirmwareImage(f
)
1940 elif chip
== 'esp32c3':
1941 return ESP32C3FirmwareImage(f
)
1942 else: # Otherwise, ESP8266 so look at magic to determine the image type
1943 magic
= ord(f
.read(1))
1945 if magic
== ESPLoader
.ESP_IMAGE_MAGIC
:
1946 return ESP8266ROMFirmwareImage(f
)
1947 elif magic
== ESPBOOTLOADER
.IMAGE_V2_MAGIC
:
1948 return ESP8266V2FirmwareImage(f
)
1950 raise FatalError("Invalid image magic number: %d" % magic
)
1953 class ImageSegment(object):
1954 """ Wrapper class for a segment in an ESP image
1955 (very similar to a section in an ELFImage also) """
1956 def __init__(self
, addr
, data
, file_offs
=None):
1959 self
.file_offs
= file_offs
1960 self
.include_in_checksum
= True
1962 self
.pad_to_alignment(4) # pad all "real" ImageSegments 4 byte aligned length
1964 def copy_with_new_addr(self
, new_addr
):
1965 """ Return a new ImageSegment with same data, but mapped at
1967 return ImageSegment(new_addr
, self
.data
, 0)
1969 def split_image(self
, split_len
):
1970 """ Return a new ImageSegment which splits "split_len" bytes
1971 from the beginning of the data. Remaining bytes are kept in
1972 this segment object (and the start address is adjusted to match.) """
1973 result
= copy
.copy(self
)
1974 result
.data
= self
.data
[:split_len
]
1975 self
.data
= self
.data
[split_len
:]
1976 self
.addr
+= split_len
1977 self
.file_offs
= None
1978 result
.file_offs
= None
1982 r
= "len 0x%05x load 0x%08x" % (len(self
.data
), self
.addr
)
1983 if self
.file_offs
is not None:
1984 r
+= " file_offs 0x%08x" % (self
.file_offs
)
1987 def pad_to_alignment(self
, alignment
):
1988 self
.data
= pad_to(self
.data
, alignment
, b
'\x00')
1991 class ELFSection(ImageSegment
):
1992 """ Wrapper class for a section in an ELF image, has a section
1993 name as well as the common properties of an ImageSegment. """
1994 def __init__(self
, name
, addr
, data
):
1995 super(ELFSection
, self
).__init
__(addr
, data
)
1996 self
.name
= name
.decode("utf-8")
1999 return "%s %s" % (self
.name
, super(ELFSection
, self
).__repr
__())
2002 class BaseFirmwareImage(object):
2004 SHA256_DIGEST_LEN
= 32
2006 """ Base class with common firmware image functions """
2010 self
.elf_sha256
= None
2011 self
.elf_sha256_offset
= 0
2013 def load_common_header(self
, load_file
, expected_magic
):
2014 (magic
, segments
, self
.flash_mode
, self
.flash_size_freq
, self
.entrypoint
) = struct
.unpack('<BBBBI', load_file
.read(8))
2016 if magic
!= expected_magic
:
2017 raise FatalError('Invalid firmware image magic=0x%x' % (magic
))
2021 if len(self
.segments
) > 16:
2022 raise FatalError('Invalid segment count %d (max 16). Usually this indicates a linker script problem.' % len(self
.segments
))
2024 def load_segment(self
, f
, is_irom_segment
=False):
2025 """ Load the next segment from the image file """
2026 file_offs
= f
.tell()
2027 (offset
, size
) = struct
.unpack('<II', f
.read(8))
2028 self
.warn_if_unusual_segment(offset
, size
, is_irom_segment
)
2029 segment_data
= f
.read(size
)
2030 if len(segment_data
) < size
:
2031 raise FatalError('End of file reading segment 0x%x, length %d (actual length %d)' % (offset
, size
, len(segment_data
)))
2032 segment
= ImageSegment(offset
, segment_data
, file_offs
)
2033 self
.segments
.append(segment
)
2036 def warn_if_unusual_segment(self
, offset
, size
, is_irom_segment
):
2037 if not is_irom_segment
:
2038 if offset
> 0x40200000 or offset
< 0x3ffe0000 or size
> 65536:
2039 print('WARNING: Suspicious segment 0x%x, length %d' % (offset
, size
))
2041 def maybe_patch_segment_data(self
, f
, segment_data
):
2042 """If SHA256 digest of the ELF file needs to be inserted into this segment, do so. Returns segment data."""
2043 segment_len
= len(segment_data
)
2044 file_pos
= f
.tell() # file_pos is position in the .bin file
2045 if self
.elf_sha256_offset
>= file_pos
and self
.elf_sha256_offset
< file_pos
+ segment_len
:
2046 # SHA256 digest needs to be patched into this binary segment,
2047 # calculate offset of the digest inside the binary segment.
2048 patch_offset
= self
.elf_sha256_offset
- file_pos
2050 if patch_offset
< self
.SEG_HEADER_LEN
or patch_offset
+ self
.SHA256_DIGEST_LEN
> segment_len
:
2051 raise FatalError('Cannot place SHA256 digest on segment boundary'
2052 '(elf_sha256_offset=%d, file_pos=%d, segment_size=%d)' %
2053 (self
.elf_sha256_offset
, file_pos
, segment_len
))
2054 # offset relative to the data part
2055 patch_offset
-= self
.SEG_HEADER_LEN
2056 if segment_data
[patch_offset
:patch_offset
+ self
.SHA256_DIGEST_LEN
] != b
'\x00' * self
.SHA256_DIGEST_LEN
:
2057 raise FatalError('Contents of segment at SHA256 digest offset 0x%x are not all zero. Refusing to overwrite.' %
2058 self
.elf_sha256_offset
)
2059 assert(len(self
.elf_sha256
) == self
.SHA256_DIGEST_LEN
)
2060 segment_data
= segment_data
[0:patch_offset
] + self
.elf_sha256
+ \
2061 segment_data
[patch_offset
+ self
.SHA256_DIGEST_LEN
:]
2064 def save_segment(self
, f
, segment
, checksum
=None):
2065 """ Save the next segment to the image file, return next checksum value if provided """
2066 segment_data
= self
.maybe_patch_segment_data(f
, segment
.data
)
2067 f
.write(struct
.pack('<II', segment
.addr
, len(segment_data
)))
2068 f
.write(segment_data
)
2069 if checksum
is not None:
2070 return ESPLoader
.checksum(segment_data
, checksum
)
2072 def read_checksum(self
, f
):
2073 """ Return ESPLoader checksum from end of just-read image """
2074 # Skip the padding. The checksum is stored in the last byte so that the
2075 # file is a multiple of 16 bytes.
2076 align_file_position(f
, 16)
2077 return ord(f
.read(1))
2079 def calculate_checksum(self
):
2080 """ Calculate checksum of loaded image, based on segments in
2083 checksum
= ESPLoader
.ESP_CHECKSUM_MAGIC
2084 for seg
in self
.segments
:
2085 if seg
.include_in_checksum
:
2086 checksum
= ESPLoader
.checksum(seg
.data
, checksum
)
2089 def append_checksum(self
, f
, checksum
):
2090 """ Append ESPLoader checksum to the just-written image """
2091 align_file_position(f
, 16)
2092 f
.write(struct
.pack(b
'B', checksum
))
2094 def write_common_header(self
, f
, segments
):
2095 f
.write(struct
.pack('<BBBBI', ESPLoader
.ESP_IMAGE_MAGIC
, len(segments
),
2096 self
.flash_mode
, self
.flash_size_freq
, self
.entrypoint
))
2098 def is_irom_addr(self
, addr
):
2099 """ Returns True if an address starts in the irom region.
2100 Valid for ESP8266 only.
2102 return ESP8266ROM
.IROM_MAP_START
<= addr
< ESP8266ROM
.IROM_MAP_END
2104 def get_irom_segment(self
):
2105 irom_segments
= [s
for s
in self
.segments
if self
.is_irom_addr(s
.addr
)]
2106 if len(irom_segments
) > 0:
2107 if len(irom_segments
) != 1:
2108 raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments
))
2109 return irom_segments
[0]
2112 def get_non_irom_segments(self
):
2113 irom_segment
= self
.get_irom_segment()
2114 return [s
for s
in self
.segments
if s
!= irom_segment
]
2117 class ESP8266ROMFirmwareImage(BaseFirmwareImage
):
2118 """ 'Version 1' firmware image, segments loaded directly by the ROM bootloader. """
2120 ROM_LOADER
= ESP8266ROM
2122 def __init__(self
, load_file
=None):
2123 super(ESP8266ROMFirmwareImage
, self
).__init
__()
2125 self
.flash_size_freq
= 0
2128 if load_file
is not None:
2129 segments
= self
.load_common_header(load_file
, ESPLoader
.ESP_IMAGE_MAGIC
)
2131 for _
in range(segments
):
2132 self
.load_segment(load_file
)
2133 self
.checksum
= self
.read_checksum(load_file
)
2137 def default_output_name(self
, input_file
):
2138 """ Derive a default output name from the ELF name. """
2139 return input_file
+ '-'
2141 def save(self
, basename
):
2142 """ Save a set of V1 images for flashing. Parameter is a base filename. """
2143 # IROM data goes in its own plain binary file
2144 irom_segment
= self
.get_irom_segment()
2145 if irom_segment
is not None:
2146 with
open("%s0x%05x.bin" % (basename
, irom_segment
.addr
- ESP8266ROM
.IROM_MAP_START
), "wb") as f
:
2147 f
.write(irom_segment
.data
)
2149 # everything but IROM goes at 0x00000 in an image file
2150 normal_segments
= self
.get_non_irom_segments()
2151 with
open("%s0x00000.bin" % basename
, 'wb') as f
:
2152 self
.write_common_header(f
, normal_segments
)
2153 checksum
= ESPLoader
.ESP_CHECKSUM_MAGIC
2154 for segment
in normal_segments
:
2155 checksum
= self
.save_segment(f
, segment
, checksum
)
2156 self
.append_checksum(f
, checksum
)
2159 ESP8266ROM
.BOOTLOADER_IMAGE
= ESP8266ROMFirmwareImage
2162 class ESP8266V2FirmwareImage(BaseFirmwareImage
):
2163 """ 'Version 2' firmware image, segments loaded by software bootloader stub
2164 (ie Espressif bootloader or rboot)
2167 ROM_LOADER
= ESP8266ROM
2169 def __init__(self
, load_file
=None):
2170 super(ESP8266V2FirmwareImage
, self
).__init
__()
2172 if load_file
is not None:
2173 segments
= self
.load_common_header(load_file
, ESPBOOTLOADER
.IMAGE_V2_MAGIC
)
2174 if segments
!= ESPBOOTLOADER
.IMAGE_V2_SEGMENT
:
2175 # segment count is not really segment count here, but we expect to see '4'
2176 print('Warning: V2 header has unexpected "segment" count %d (usually 4)' % segments
)
2178 # irom segment comes before the second header
2180 # the file is saved in the image with a zero load address
2181 # in the header, so we need to calculate a load address
2182 irom_segment
= self
.load_segment(load_file
, True)
2183 irom_segment
.addr
= 0 # for actual mapped addr, add ESP8266ROM.IROM_MAP_START + flashing_addr + 8
2184 irom_segment
.include_in_checksum
= False
2186 first_flash_mode
= self
.flash_mode
2187 first_flash_size_freq
= self
.flash_size_freq
2188 first_entrypoint
= self
.entrypoint
2189 # load the second header
2191 segments
= self
.load_common_header(load_file
, ESPLoader
.ESP_IMAGE_MAGIC
)
2193 if first_flash_mode
!= self
.flash_mode
:
2194 print('WARNING: Flash mode value in first header (0x%02x) disagrees with second (0x%02x). Using second value.'
2195 % (first_flash_mode
, self
.flash_mode
))
2196 if first_flash_size_freq
!= self
.flash_size_freq
:
2197 print('WARNING: Flash size/freq value in first header (0x%02x) disagrees with second (0x%02x). Using second value.'
2198 % (first_flash_size_freq
, self
.flash_size_freq
))
2199 if first_entrypoint
!= self
.entrypoint
:
2200 print('WARNING: Entrypoint address in first header (0x%08x) disagrees with second header (0x%08x). Using second value.'
2201 % (first_entrypoint
, self
.entrypoint
))
2203 # load all the usual segments
2204 for _
in range(segments
):
2205 self
.load_segment(load_file
)
2206 self
.checksum
= self
.read_checksum(load_file
)
2210 def default_output_name(self
, input_file
):
2211 """ Derive a default output name from the ELF name. """
2212 irom_segment
= self
.get_irom_segment()
2213 if irom_segment
is not None:
2214 irom_offs
= irom_segment
.addr
- ESP8266ROM
.IROM_MAP_START
2217 return "%s-0x%05x.bin" % (os
.path
.splitext(input_file
)[0],
2218 irom_offs
& ~
(ESPLoader
.FLASH_SECTOR_SIZE
- 1))
2220 def save(self
, filename
):
2221 with
open(filename
, 'wb') as f
:
2222 # Save first header for irom0 segment
2223 f
.write(struct
.pack(b
'<BBBBI', ESPBOOTLOADER
.IMAGE_V2_MAGIC
, ESPBOOTLOADER
.IMAGE_V2_SEGMENT
,
2224 self
.flash_mode
, self
.flash_size_freq
, self
.entrypoint
))
2226 irom_segment
= self
.get_irom_segment()
2227 if irom_segment
is not None:
2228 # save irom0 segment, make sure it has load addr 0 in the file
2229 irom_segment
= irom_segment
.copy_with_new_addr(0)
2230 irom_segment
.pad_to_alignment(16) # irom_segment must end on a 16 byte boundary
2231 self
.save_segment(f
, irom_segment
)
2233 # second header, matches V1 header and contains loadable segments
2234 normal_segments
= self
.get_non_irom_segments()
2235 self
.write_common_header(f
, normal_segments
)
2236 checksum
= ESPLoader
.ESP_CHECKSUM_MAGIC
2237 for segment
in normal_segments
:
2238 checksum
= self
.save_segment(f
, segment
, checksum
)
2239 self
.append_checksum(f
, checksum
)
2241 # calculate a crc32 of entire file and append
2242 # (algorithm used by recent 8266 SDK bootloaders)
2243 with
open(filename
, 'rb') as f
:
2244 crc
= esp8266_crc32(f
.read())
2245 with
open(filename
, 'ab') as f
:
2246 f
.write(struct
.pack(b
'<I', crc
))
2249 # Backwards compatibility for previous API, remove in esptool.py V3
2250 ESPFirmwareImage
= ESP8266ROMFirmwareImage
2251 OTAFirmwareImage
= ESP8266V2FirmwareImage
2254 def esp8266_crc32(data
):
2256 CRC32 algorithm used by 8266 SDK bootloader (and gen_appbin.py).
2258 crc
= binascii
.crc32(data
, 0) & 0xFFFFFFFF
2259 if crc
& 0x80000000:
2260 return crc ^
0xFFFFFFFF
2265 class ESP32FirmwareImage(BaseFirmwareImage
):
2266 """ ESP32 firmware image is very similar to V1 ESP8266 image,
2267 except with an additional 16 byte reserved header at top of image,
2268 and because of new flash mapping capabilities the flash-mapped regions
2269 can be placed in the normal image (just @ 64kB padded offsets).
2272 ROM_LOADER
= ESP32ROM
2274 # ROM bootloader will read the wp_pin field if SPI flash
2275 # pins are remapped via flash. IDF actually enables QIO only
2276 # from software bootloader, so this can be ignored. But needs
2277 # to be set to this value so ROM bootloader will skip it.
2278 WP_PIN_DISABLED
= 0xEE
2280 EXTENDED_HEADER_STRUCT_FMT
= "<BBBBHB" + ("B" * 8) + "B"
2284 def __init__(self
, load_file
=None):
2285 super(ESP32FirmwareImage
, self
).__init
__()
2286 self
.secure_pad
= None
2288 self
.flash_size_freq
= 0
2290 self
.wp_pin
= self
.WP_PIN_DISABLED
2291 # SPI pin drive levels
2300 self
.append_digest
= True
2302 if load_file
is not None:
2303 start
= load_file
.tell()
2305 segments
= self
.load_common_header(load_file
, ESPLoader
.ESP_IMAGE_MAGIC
)
2306 self
.load_extended_header(load_file
)
2308 for _
in range(segments
):
2309 self
.load_segment(load_file
)
2310 self
.checksum
= self
.read_checksum(load_file
)
2312 if self
.append_digest
:
2313 end
= load_file
.tell()
2314 self
.stored_digest
= load_file
.read(32)
2315 load_file
.seek(start
)
2316 calc_digest
= hashlib
.sha256()
2317 calc_digest
.update(load_file
.read(end
- start
))
2318 self
.calc_digest
= calc_digest
.digest() # TODO: decide what to do here?
2322 def is_flash_addr(self
, addr
):
2323 return (self
.ROM_LOADER
.IROM_MAP_START
<= addr
< self
.ROM_LOADER
.IROM_MAP_END
) \
2324 or (self
.ROM_LOADER
.DROM_MAP_START
<= addr
< self
.ROM_LOADER
.DROM_MAP_END
)
2326 def default_output_name(self
, input_file
):
2327 """ Derive a default output name from the ELF name. """
2328 return "%s.bin" % (os
.path
.splitext(input_file
)[0])
2330 def warn_if_unusual_segment(self
, offset
, size
, is_irom_segment
):
2331 pass # TODO: add warnings for ESP32 segment offset/size combinations that are wrong
2333 def save(self
, filename
):
2335 with io
.BytesIO() as f
: # write file to memory first
2336 self
.write_common_header(f
, self
.segments
)
2338 # first 4 bytes of header are read by ROM bootloader for SPI
2339 # config, but currently unused
2340 self
.save_extended_header(f
)
2342 checksum
= ESPLoader
.ESP_CHECKSUM_MAGIC
2344 # split segments into flash-mapped vs ram-loaded, and take copies so we can mutate them
2345 flash_segments
= [copy
.deepcopy(s
) for s
in sorted(self
.segments
, key
=lambda s
:s
.addr
) if self
.is_flash_addr(s
.addr
)]
2346 ram_segments
= [copy
.deepcopy(s
) for s
in sorted(self
.segments
, key
=lambda s
:s
.addr
) if not self
.is_flash_addr(s
.addr
)]
2348 # check for multiple ELF sections that are mapped in the same flash mapping region.
2349 # this is usually a sign of a broken linker script, but if you have a legitimate
2350 # use case then let us know (we can merge segments here, but as a rule you probably
2351 # want to merge them in your linker script.)
2352 if len(flash_segments
) > 0:
2353 last_addr
= flash_segments
[0].addr
2354 for segment
in flash_segments
[1:]:
2355 if segment
.addr
// self
.IROM_ALIGN
== last_addr
// self
.IROM_ALIGN
:
2356 raise FatalError(("Segment loaded at 0x%08x lands in same 64KB flash mapping as segment loaded at 0x%08x. "
2357 "Can't generate binary. Suggest changing linker script or ELF to merge sections.") %
2358 (segment
.addr
, last_addr
))
2359 last_addr
= segment
.addr
2361 def get_alignment_data_needed(segment
):
2362 # Actual alignment (in data bytes) required for a segment header: positioned so that
2363 # after we write the next 8 byte header, file_offs % IROM_ALIGN == segment.addr % IROM_ALIGN
2365 # (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is aligned
2366 # IROM_ALIGN+0x18 to account for the binary file header
2367 align_past
= (segment
.addr
% self
.IROM_ALIGN
) - self
.SEG_HEADER_LEN
2368 pad_len
= (self
.IROM_ALIGN
- (f
.tell() % self
.IROM_ALIGN
)) + align_past
2369 if pad_len
== 0 or pad_len
== self
.IROM_ALIGN
:
2370 return 0 # already aligned
2372 # subtract SEG_HEADER_LEN a second time, as the padding block has a header as well
2373 pad_len
-= self
.SEG_HEADER_LEN
2375 pad_len
+= self
.IROM_ALIGN
2378 # try to fit each flash segment on a 64kB aligned boundary
2379 # by padding with parts of the non-flash segments...
2380 while len(flash_segments
) > 0:
2381 segment
= flash_segments
[0]
2382 pad_len
= get_alignment_data_needed(segment
)
2383 if pad_len
> 0: # need to pad
2384 if len(ram_segments
) > 0 and pad_len
> self
.SEG_HEADER_LEN
:
2385 pad_segment
= ram_segments
[0].split_image(pad_len
)
2386 if len(ram_segments
[0].data
) == 0:
2389 pad_segment
= ImageSegment(0, b
'\x00' * pad_len
, f
.tell())
2390 checksum
= self
.save_segment(f
, pad_segment
, checksum
)
2393 # write the flash segment
2394 assert (f
.tell() + 8) % self
.IROM_ALIGN
== segment
.addr
% self
.IROM_ALIGN
2395 checksum
= self
.save_flash_segment(f
, segment
, checksum
)
2396 flash_segments
.pop(0)
2399 # flash segments all written, so write any remaining RAM segments
2400 for segment
in ram_segments
:
2401 checksum
= self
.save_segment(f
, segment
, checksum
)
2405 # pad the image so that after signing it will end on a a 64KB boundary.
2406 # This ensures all mapped flash content will be verified.
2407 if not self
.append_digest
:
2408 raise FatalError("secure_pad only applies if a SHA-256 digest is also appended to the image")
2409 align_past
= (f
.tell() + self
.SEG_HEADER_LEN
) % self
.IROM_ALIGN
2410 # 16 byte aligned checksum (force the alignment to simplify calculations)
2412 if self
.secure_pad
== '1':
2413 # after checksum: SHA-256 digest + (to be added by signing process) version, signature + 12 trailing bytes due to alignment
2414 space_after_checksum
= 32 + 4 + 64 + 12
2415 elif self
.secure_pad
== '2': # Secure Boot V2
2416 # after checksum: SHA-256 digest + signature sector, but we place signature sector after the 64KB boundary
2417 space_after_checksum
= 32
2418 pad_len
= (self
.IROM_ALIGN
- align_past
- checksum_space
- space_after_checksum
) % self
.IROM_ALIGN
2419 pad_segment
= ImageSegment(0, b
'\x00' * pad_len
, f
.tell())
2421 checksum
= self
.save_segment(f
, pad_segment
, checksum
)
2424 # done writing segments
2425 self
.append_checksum(f
, checksum
)
2426 image_length
= f
.tell()
2429 assert ((image_length
+ space_after_checksum
) % self
.IROM_ALIGN
) == 0
2431 # kinda hacky: go back to the initial header and write the new segment count
2432 # that includes padding segments. This header is not checksummed
2435 f
.write(chr(total_segments
))
2436 except TypeError: # Python 3
2437 f
.write(bytes([total_segments
]))
2439 if self
.append_digest
:
2440 # calculate the SHA256 of the whole file and append it
2442 digest
= hashlib
.sha256()
2443 digest
.update(f
.read(image_length
))
2444 f
.write(digest
.digest())
2446 with
open(filename
, 'wb') as real_file
:
2447 real_file
.write(f
.getvalue())
2449 def save_flash_segment(self
, f
, segment
, checksum
=None):
2450 """ Save the next segment to the image file, return next checksum value if provided """
2451 segment_end_pos
= f
.tell() + len(segment
.data
) + self
.SEG_HEADER_LEN
2452 segment_len_remainder
= segment_end_pos
% self
.IROM_ALIGN
2453 if segment_len_remainder
< 0x24:
2454 # Work around a bug in ESP-IDF 2nd stage bootloader, that it didn't map the
2455 # last MMU page, if an IROM/DROM segment was < 0x24 bytes over the page boundary.
2456 segment
.data
+= b
'\x00' * (0x24 - segment_len_remainder
)
2457 return self
.save_segment(f
, segment
, checksum
)
2459 def load_extended_header(self
, load_file
):
2461 return (n
& 0x0F, (n
>> 4) & 0x0F)
2463 fields
= list(struct
.unpack(self
.EXTENDED_HEADER_STRUCT_FMT
, load_file
.read(16)))
2465 self
.wp_pin
= fields
[0]
2467 # SPI pin drive stengths are two per byte
2468 self
.clk_drv
, self
.q_drv
= split_byte(fields
[1])
2469 self
.d_drv
, self
.cs_drv
= split_byte(fields
[2])
2470 self
.hd_drv
, self
.wp_drv
= split_byte(fields
[3])
2473 if chip_id
!= self
.ROM_LOADER
.IMAGE_CHIP_ID
:
2474 print(("Unexpected chip id in image. Expected %d but value was %d. "
2475 "Is this image for a different chip model?") % (self
.ROM_LOADER
.IMAGE_CHIP_ID
, chip_id
))
2477 # reserved fields in the middle should all be zero
2478 if any(f
for f
in fields
[6:-1] if f
!= 0):
2479 print("Warning: some reserved header fields have non-zero values. This image may be from a newer esptool.py?")
2481 append_digest
= fields
[-1] # last byte is append_digest
2482 if append_digest
in [0, 1]:
2483 self
.append_digest
= (append_digest
== 1)
2485 raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", append_digest
)
2487 def save_extended_header(self
, save_file
):
2488 def join_byte(ln
, hn
):
2489 return (ln
& 0x0F) + ((hn
& 0x0F) << 4)
2491 append_digest
= 1 if self
.append_digest
else 0
2493 fields
= [self
.wp_pin
,
2494 join_byte(self
.clk_drv
, self
.q_drv
),
2495 join_byte(self
.d_drv
, self
.cs_drv
),
2496 join_byte(self
.hd_drv
, self
.wp_drv
),
2497 self
.ROM_LOADER
.IMAGE_CHIP_ID
,
2499 fields
+= [0] * 8 # padding
2500 fields
+= [append_digest
]
2502 packed
= struct
.pack(self
.EXTENDED_HEADER_STRUCT_FMT
, *fields
)
2503 save_file
.write(packed
)
2506 ESP32ROM
.BOOTLOADER_IMAGE
= ESP32FirmwareImage
2509 class ESP32S2FirmwareImage(ESP32FirmwareImage
):
2510 """ ESP32S2 Firmware Image almost exactly the same as ESP32FirmwareImage """
2511 ROM_LOADER
= ESP32S2ROM
2514 ESP32S2ROM
.BOOTLOADER_IMAGE
= ESP32S2FirmwareImage
2517 class ESP32S3BETA2FirmwareImage(ESP32FirmwareImage
):
2518 """ ESP32S3 Firmware Image almost exactly the same as ESP32FirmwareImage """
2519 ROM_LOADER
= ESP32S3BETA2ROM
2522 ESP32S3BETA2ROM
.BOOTLOADER_IMAGE
= ESP32S3BETA2FirmwareImage
2525 class ESP32C3FirmwareImage(ESP32FirmwareImage
):
2526 """ ESP32C3 Firmware Image almost exactly the same as ESP32FirmwareImage """
2527 ROM_LOADER
= ESP32C3ROM
2530 ESP32C3ROM
.BOOTLOADER_IMAGE
= ESP32C3FirmwareImage
2533 class ELFFile(object):
2534 SEC_TYPE_PROGBITS
= 0x01
2535 SEC_TYPE_STRTAB
= 0x03
2537 LEN_SEC_HEADER
= 0x28
2539 def __init__(self
, name
):
2540 # Load sections from the ELF file
2542 with
open(self
.name
, 'rb') as f
:
2543 self
._read
_elf
_file
(f
)
2545 def get_section(self
, section_name
):
2546 for s
in self
.sections
:
2547 if s
.name
== section_name
:
2549 raise ValueError("No section %s in ELF file" % section_name
)
2551 def _read_elf_file(self
, f
):
2552 # read the ELF file header
2553 LEN_FILE_HEADER
= 0x34
2555 (ident
, _type
, machine
, _version
,
2556 self
.entrypoint
, _phoff
, shoff
, _flags
,
2557 _ehsize
, _phentsize
, _phnum
, shentsize
,
2558 shnum
, shstrndx
) = struct
.unpack("<16sHHLLLLLHHHHHH", f
.read(LEN_FILE_HEADER
))
2559 except struct
.error
as e
:
2560 raise FatalError("Failed to read a valid ELF header from %s: %s" % (self
.name
, e
))
2562 if byte(ident
, 0) != 0x7f or ident
[1:4] != b
'ELF':
2563 raise FatalError("%s has invalid ELF magic header" % self
.name
)
2564 if machine
not in [0x5e, 0xf3]:
2565 raise FatalError("%s does not appear to be an Xtensa or an RISCV ELF file. e_machine=%04x" % (self
.name
, machine
))
2566 if shentsize
!= self
.LEN_SEC_HEADER
:
2567 raise FatalError("%s has unexpected section header entry size 0x%x (not 0x%x)" % (self
.name
, shentsize
, self
.LEN_SEC_HEADER
))
2569 raise FatalError("%s has 0 section headers" % (self
.name
))
2570 self
._read
_sections
(f
, shoff
, shnum
, shstrndx
)
2572 def _read_sections(self
, f
, section_header_offs
, section_header_count
, shstrndx
):
2573 f
.seek(section_header_offs
)
2574 len_bytes
= section_header_count
* self
.LEN_SEC_HEADER
2575 section_header
= f
.read(len_bytes
)
2576 if len(section_header
) == 0:
2577 raise FatalError("No section header found at offset %04x in ELF file." % section_header_offs
)
2578 if len(section_header
) != (len_bytes
):
2579 raise FatalError("Only read 0x%x bytes from section header (expected 0x%x.) Truncated ELF file?" % (len(section_header
), len_bytes
))
2581 # walk through the section header and extract all sections
2582 section_header_offsets
= range(0, len(section_header
), self
.LEN_SEC_HEADER
)
2584 def read_section_header(offs
):
2585 name_offs
, sec_type
, _flags
, lma
, sec_offs
, size
= struct
.unpack_from("<LLLLLL", section_header
[offs
:])
2586 return (name_offs
, sec_type
, lma
, size
, sec_offs
)
2587 all_sections
= [read_section_header(offs
) for offs
in section_header_offsets
]
2588 prog_sections
= [s
for s
in all_sections
if s
[1] == ELFFile
.SEC_TYPE_PROGBITS
]
2590 # search for the string table section
2591 if not (shstrndx
* self
.LEN_SEC_HEADER
) in section_header_offsets
:
2592 raise FatalError("ELF file has no STRTAB section at shstrndx %d" % shstrndx
)
2593 _
, sec_type
, _
, sec_size
, sec_offs
= read_section_header(shstrndx
* self
.LEN_SEC_HEADER
)
2594 if sec_type
!= ELFFile
.SEC_TYPE_STRTAB
:
2595 print('WARNING: ELF file has incorrect STRTAB section type 0x%02x' % sec_type
)
2597 string_table
= f
.read(sec_size
)
2599 # build the real list of ELFSections by reading the actual section names from the
2600 # string table section, and actual data for each section from the ELF file itself
2601 def lookup_string(offs
):
2602 raw
= string_table
[offs
:]
2603 return raw
[:raw
.index(b
'\x00')]
2605 def read_data(offs
, size
):
2609 prog_sections
= [ELFSection(lookup_string(n_offs
), lma
, read_data(offs
, size
)) for (n_offs
, _type
, lma
, size
, offs
) in prog_sections
2610 if lma
!= 0 and size
> 0]
2611 self
.sections
= prog_sections
2614 # return SHA256 hash of the input ELF file
2615 sha256
= hashlib
.sha256()
2616 with
open(self
.name
, 'rb') as f
:
2617 sha256
.update(f
.read())
2618 return sha256
.digest()
2621 def slip_reader(port
, trace_function
):
2622 """Generator to read SLIP packets from a serial port.
2623 Yields one full SLIP packet at a time, raises exception on timeout or invalid data.
2625 Designed to avoid too many calls to serial.read(1), which can bog
2626 down on slow systems.
2628 partial_packet
= None
2631 waiting
= port
.inWaiting()
2632 read_bytes
= port
.read(1 if waiting
== 0 else waiting
)
2633 if read_bytes
== b
'':
2634 waiting_for
= "header" if partial_packet
is None else "content"
2635 trace_function("Timed out waiting for packet %s", waiting_for
)
2636 raise FatalError("Timed out waiting for packet %s" % waiting_for
)
2637 trace_function("Read %d bytes: %s", len(read_bytes
), HexFormatter(read_bytes
))
2638 for b
in read_bytes
:
2640 b
= bytes([b
]) # python 2/3 compat
2642 if partial_packet
is None: # waiting for packet header
2644 partial_packet
= b
""
2646 trace_function("Read invalid data: %s", HexFormatter(read_bytes
))
2647 trace_function("Remaining data in serial buffer: %s", HexFormatter(port
.read(port
.inWaiting())))
2648 raise FatalError('Invalid head of packet (0x%s)' % hexify(b
))
2649 elif in_escape
: # part-way through escape sequence
2652 partial_packet
+= b
'\xc0'
2654 partial_packet
+= b
'\xdb'
2656 trace_function("Read invalid data: %s", HexFormatter(read_bytes
))
2657 trace_function("Remaining data in serial buffer: %s", HexFormatter(port
.read(port
.inWaiting())))
2658 raise FatalError('Invalid SLIP escape (0xdb, 0x%s)' % (hexify(b
)))
2659 elif b
== b
'\xdb': # start of escape sequence
2661 elif b
== b
'\xc0': # end of packet
2662 trace_function("Received full packet: %s", HexFormatter(partial_packet
))
2663 yield partial_packet
2664 partial_packet
= None
2665 else: # normal byte in packet
2669 def arg_auto_int(x
):
2673 def div_roundup(a
, b
):
2674 """ Return a/b rounded up to nearest integer,
2675 equivalent result to int(math.ceil(float(int(a)) / float(int(b))), only
2676 without possible floating point accuracy errors.
2678 return (int(a
) + int(b
) - 1) // int(b
)
2681 def align_file_position(f
, size
):
2682 """ Align the position in the file to the next block of specified size """
2683 align
= (size
- 1) - (f
.tell() % size
)
2687 def flash_size_bytes(size
):
2688 """ Given a flash size of the type passed in args.flash_size
2689 (ie 512KB or 1MB) then return the size in bytes.
2692 return int(size
[:size
.index("MB")]) * 1024 * 1024
2694 return int(size
[:size
.index("KB")]) * 1024
2696 raise FatalError("Unknown size %s" % size
)
2699 def hexify(s
, uppercase
=True):
2700 format_str
= '%02X' if uppercase
else '%02x'
2702 return ''.join(format_str
% c
for c
in s
)
2704 return ''.join(format_str
% ord(c
) for c
in s
)
2707 class HexFormatter(object):
2709 Wrapper class which takes binary data in its constructor
2710 and returns a hex string as it's __str__ method.
2712 This is intended for "lazy formatting" of trace() output
2713 in hex format. Avoids overhead (significant on slow computers)
2714 of generating long hex strings even if tracing is disabled.
2716 Note that this doesn't save any overhead if passed as an
2717 argument to "%", only when passed to trace()
2719 If auto_split is set (default), any long line (> 16 bytes) will be
2720 printed as separately indented lines, with ASCII decoding at the end
2723 def __init__(self
, binary_string
, auto_split
=True):
2724 self
._s
= binary_string
2725 self
._auto
_split
= auto_split
2728 if self
._auto
_split
and len(self
._s
) > 16:
2733 ascii_line
= "".join(c
if (c
== ' ' or (c
in string
.printable
and c
not in string
.whitespace
))
2734 else '.' for c
in line
.decode('ascii', 'replace'))
2736 result
+= "\n %-16s %-16s | %s" % (hexify(line
[:8], False), hexify(line
[8:], False), ascii_line
)
2739 return hexify(self
._s
, False)
2742 def pad_to(data
, alignment
, pad_character
=b
'\xFF'):
2743 """ Pad to the next alignment boundary """
2744 pad_mod
= len(data
) % alignment
2746 data
+= pad_character
* (alignment
- pad_mod
)
2750 class FatalError(RuntimeError):
2752 Wrapper class for runtime errors that aren't caused by internal bugs, but by
2753 ESP8266 responses or input content.
2755 def __init__(self
, message
):
2756 RuntimeError.__init
__(self
, message
)
2759 def WithResult(message
, result
):
2761 Return a fatal error object that appends the hex values of
2762 'result' as a string formatted argument.
2764 message
+= " (result was %s)" % hexify(result
)
2765 return FatalError(message
)
2768 class NotImplementedInROMError(FatalError
):
2770 Wrapper class for the error thrown when a particular ESP bootloader function
2771 is not implemented in the ROM bootloader.
2773 def __init__(self
, bootloader
, func
):
2774 FatalError
.__init
__(self
, "%s ROM does not support function %s." % (bootloader
.CHIP_NAME
, func
.__name
__))
2777 class NotSupportedError(FatalError
):
2778 def __init__(self
, esp
, function_name
):
2779 FatalError
.__init
__(self
, "Function %s is not supported for %s." % (function_name
, esp
.CHIP_NAME
))
2781 # "Operation" commands, executable at command line. One function each
2783 # Each function takes either two args (<ESPLoader instance>, <args>) or a single <args>
2787 class UnsupportedCommandError(RuntimeError):
2789 Wrapper class for when ROM loader returns an invalid command response.
2791 Usually this indicates the loader is running in Secure Download Mode.
2793 def __init__(self
, esp
, op
):
2794 if esp
.secure_download_mode
:
2795 msg
= "This command (0x%x) is not supported in Secure Download Mode" % op
2797 msg
= "Invalid (unsupported) command 0x%x" % op
2798 RuntimeError.__init
__(self
, msg
)
2801 def load_ram(esp
, args
):
2802 image
= LoadFirmwareImage(esp
.CHIP_NAME
, args
.filename
)
2804 print('RAM boot...')
2805 for seg
in image
.segments
:
2806 size
= len(seg
.data
)
2807 print('Downloading %d bytes at %08x...' % (size
, seg
.addr
), end
=' ')
2809 esp
.mem_begin(size
, div_roundup(size
, esp
.ESP_RAM_BLOCK
), esp
.ESP_RAM_BLOCK
, seg
.addr
)
2812 while len(seg
.data
) > 0:
2813 esp
.mem_block(seg
.data
[0:esp
.ESP_RAM_BLOCK
], seq
)
2814 seg
.data
= seg
.data
[esp
.ESP_RAM_BLOCK
:]
2818 print('All segments done, executing at %08x' % image
.entrypoint
)
2819 esp
.mem_finish(image
.entrypoint
)
2822 def read_mem(esp
, args
):
2823 print('0x%08x = 0x%08x' % (args
.address
, esp
.read_reg(args
.address
)))
2826 def write_mem(esp
, args
):
2827 esp
.write_reg(args
.address
, args
.value
, args
.mask
, 0)
2828 print('Wrote %08x, mask %08x to %08x' % (args
.value
, args
.mask
, args
.address
))
2831 def dump_mem(esp
, args
):
2832 with
open(args
.filename
, 'wb') as f
:
2833 for i
in range(args
.size
// 4):
2834 d
= esp
.read_reg(args
.address
+ (i
* 4))
2835 f
.write(struct
.pack(b
'<I', d
))
2836 if f
.tell() % 1024 == 0:
2837 print_overwrite('%d bytes read... (%d %%)' % (f
.tell(),
2838 f
.tell() * 100 // args
.size
))
2840 print_overwrite("Read %d bytes" % f
.tell(), last_line
=True)
2844 def detect_flash_size(esp
, args
):
2845 if args
.flash_size
== 'detect':
2846 if esp
.secure_download_mode
:
2847 raise FatalError("Detecting flash size is not supported in secure download mode. Need to manually specify flash size.")
2848 flash_id
= esp
.flash_id()
2849 size_id
= flash_id
>> 16
2850 args
.flash_size
= DETECTED_FLASH_SIZES
.get(size_id
)
2851 if args
.flash_size
is None:
2852 print('Warning: Could not auto-detect Flash size (FlashID=0x%x, SizeID=0x%x), defaulting to 4MB' % (flash_id
, size_id
))
2853 args
.flash_size
= '4MB'
2855 print('Auto-detected Flash size:', args
.flash_size
)
2858 def _update_image_flash_params(esp
, address
, args
, image
):
2859 """ Modify the flash mode & size bytes if this looks like an executable bootloader image """
2861 return image
# not long enough to be a bootloader image
2863 # unpack the (potential) image header
2864 magic
, _
, flash_mode
, flash_size_freq
= struct
.unpack("BBBB", image
[:4])
2865 if address
!= esp
.BOOTLOADER_FLASH_OFFSET
:
2866 return image
# not flashing bootloader offset, so don't modify this
2868 if (args
.flash_mode
, args
.flash_freq
, args
.flash_size
) == ('keep',) * 3:
2869 return image
# all settings are 'keep', not modifying anything
2871 # easy check if this is an image: does it start with a magic byte?
2872 if magic
!= esp
.ESP_IMAGE_MAGIC
:
2873 print("Warning: Image file at 0x%x doesn't look like an image file, so not changing any flash settings." % address
)
2876 # make sure this really is an image, and not just data that
2877 # starts with esp.ESP_IMAGE_MAGIC (mostly a problem for encrypted
2878 # images that happen to start with a magic byte
2880 test_image
= esp
.BOOTLOADER_IMAGE(io
.BytesIO(image
))
2883 print("Warning: Image file at 0x%x is not a valid %s image, so not changing any flash settings." % (address
, esp
.CHIP_NAME
))
2886 if args
.flash_mode
!= 'keep':
2887 flash_mode
= {'qio': 0, 'qout': 1, 'dio': 2, 'dout': 3}[args
.flash_mode
]
2889 flash_freq
= flash_size_freq
& 0x0F
2890 if args
.flash_freq
!= 'keep':
2891 flash_freq
= {'40m': 0, '26m': 1, '20m': 2, '80m': 0xf}[args
.flash_freq
]
2893 flash_size
= flash_size_freq
& 0xF0
2894 if args
.flash_size
!= 'keep':
2895 flash_size
= esp
.parse_flash_size_arg(args
.flash_size
)
2897 flash_params
= struct
.pack(b
'BB', flash_mode
, flash_size
+ flash_freq
)
2898 if flash_params
!= image
[2:4]:
2899 print('Flash params set to 0x%04x' % struct
.unpack(">H", flash_params
))
2900 image
= image
[0:2] + flash_params
+ image
[4:]
2904 def write_flash(esp
, args
):
2905 # set args.compress based on default behaviour:
2906 # -> if either --compress or --no-compress is set, honour that
2907 # -> otherwise, set --compress unless --no-stub is set
2908 if args
.compress
is None and not args
.no_compress
:
2909 args
.compress
= not args
.no_stub
2911 # For encrypt option we do few sanity checks before actual flash write
2915 if not esp
.secure_download_mode
:
2916 if esp
.get_encrypted_download_disabled():
2917 raise FatalError("This chip has encrypt functionality in UART download mode disabled. "
2918 "This is the Flash Encryption configuration for Production mode instead of Development mode.")
2920 crypt_cfg_efuse
= esp
.get_flash_crypt_config()
2922 if crypt_cfg_efuse
is not None and crypt_cfg_efuse
!= 0xF:
2923 print('Unexpected FLASH_CRYPT_CONFIG value: 0x%x' % (crypt_cfg_efuse
))
2926 enc_key_valid
= esp
.is_flash_encryption_key_valid()
2928 if not enc_key_valid
:
2929 print('Flash encryption key is not programmed')
2932 for address
, argfile
in args
.addr_filename
:
2933 if address
% esp
.FLASH_ENCRYPTED_WRITE_ALIGN
:
2934 print("File %s address 0x%x is not %d byte aligned, can't flash encrypted" %
2935 (argfile
.name
, address
, esp
.FLASH_ENCRYPTED_WRITE_ALIGN
))
2938 if not do_write
and not args
.ignore_flash_encryption_efuse_setting
:
2939 raise FatalError("Can't perform encrypted flash write, consult Flash Encryption documentation for more information")
2941 # verify file sizes fit in flash
2942 if args
.flash_size
!= 'keep': # TODO: check this even with 'keep'
2943 flash_end
= flash_size_bytes(args
.flash_size
)
2944 for address
, argfile
in args
.addr_filename
:
2945 argfile
.seek(0, 2) # seek to end
2946 if address
+ argfile
.tell() > flash_end
:
2947 raise FatalError(("File %s (length %d) at offset %d will not fit in %d bytes of flash. "
2948 "Use --flash-size argument, or change flashing address.")
2949 % (argfile
.name
, argfile
.tell(), address
, flash_end
))
2953 erase_flash(esp
, args
)
2955 if args
.encrypt
and args
.compress
:
2956 print('\nWARNING: - compress and encrypt options are mutually exclusive ')
2957 print('Will flash uncompressed')
2958 args
.compress
= False
2960 for address
, argfile
in args
.addr_filename
:
2962 print('Erasing flash...')
2963 image
= pad_to(argfile
.read(), esp
.FLASH_ENCRYPTED_WRITE_ALIGN
if args
.encrypt
else 4)
2965 print('WARNING: File %s is empty' % argfile
.name
)
2967 image
= _update_image_flash_params(esp
, address
, args
, image
)
2968 calcmd5
= hashlib
.md5(image
).hexdigest()
2969 uncsize
= len(image
)
2972 image
= zlib
.compress(uncimage
, 9)
2973 ratio
= uncsize
/ len(image
)
2974 blocks
= esp
.flash_defl_begin(uncsize
, len(image
), address
)
2977 blocks
= esp
.flash_begin(uncsize
, address
, begin_rom_encrypted
=args
.encrypt
)
2978 argfile
.seek(0) # in case we need it again
2982 while len(image
) > 0:
2983 print_overwrite('Writing at 0x%08x... (%d %%)' % (address
+ seq
* esp
.FLASH_WRITE_SIZE
, 100 * (seq
+ 1) // blocks
))
2985 block
= image
[0:esp
.FLASH_WRITE_SIZE
]
2987 esp
.flash_defl_block(block
, seq
, timeout
=DEFAULT_TIMEOUT
* ratio
* 2)
2989 # Pad the last block
2990 block
= block
+ b
'\xff' * (esp
.FLASH_WRITE_SIZE
- len(block
))
2992 esp
.flash_encrypt_block(block
, seq
)
2994 esp
.flash_block(block
, seq
)
2995 image
= image
[esp
.FLASH_WRITE_SIZE
:]
2997 written
+= len(block
)
3002 speed_msg
= " (effective %.1f kbit/s)" % (uncsize
/ t
* 8 / 1000)
3003 print_overwrite('Wrote %d bytes (%d compressed) at 0x%08x in %.1f seconds%s...' % (uncsize
, written
, address
, t
, speed_msg
), last_line
=True)
3006 speed_msg
= " (%.1f kbit/s)" % (written
/ t
* 8 / 1000)
3007 print_overwrite('Wrote %d bytes at 0x%08x in %.1f seconds%s...' % (written
, address
, t
, speed_msg
), last_line
=True)
3009 if not args
.encrypt
and not esp
.secure_download_mode
:
3011 res
= esp
.flash_md5sum(address
, uncsize
)
3013 print('File md5: %s' % calcmd5
)
3014 print('Flash md5: %s' % res
)
3015 print('MD5 of 0xFF is %s' % (hashlib
.md5(b
'\xFF' * uncsize
).hexdigest()))
3016 raise FatalError("MD5 of file does not match data in flash!")
3018 print('Hash of data verified.')
3019 except NotImplementedInROMError
:
3022 print('\nLeaving...')
3025 # skip sending flash_finish to ROM loader here,
3026 # as it causes the loader to exit and run user code
3027 esp
.flash_begin(0, 0)
3029 esp
.flash_defl_finish(False)
3031 esp
.flash_finish(False)
3034 print('Verifying just-written flash...')
3035 print('(This option is deprecated, flash contents are now always read back after flashing.)')
3036 verify_flash(esp
, args
)
3039 def image_info(args
):
3040 image
= LoadFirmwareImage(args
.chip
, args
.filename
)
3041 print('Image version: %d' % image
.version
)
3042 print('Entry point: %08x' % image
.entrypoint
if image
.entrypoint
!= 0 else 'Entry point not set')
3043 print('%d segments' % len(image
.segments
))
3046 for seg
in image
.segments
:
3048 seg_name
= ", ".join([seg_range
[2] for seg_range
in image
.ROM_LOADER
.MEMORY_MAP
if seg_range
[0] <= seg
.addr
< seg_range
[1]])
3049 print('Segment %d: %r [%s]' % (idx
, seg
, seg_name
))
3050 calc_checksum
= image
.calculate_checksum()
3051 print('Checksum: %02x (%s)' % (image
.checksum
,
3052 'valid' if image
.checksum
== calc_checksum
else 'invalid - calculated %02x' % calc_checksum
))
3054 digest_msg
= 'Not appended'
3055 if image
.append_digest
:
3056 is_valid
= image
.stored_digest
== image
.calc_digest
3057 digest_msg
= "%s (%s)" % (hexify(image
.calc_digest
).lower(),
3058 "valid" if is_valid
else "invalid")
3059 print('Validation Hash: %s' % digest_msg
)
3060 except AttributeError:
3061 pass # ESP8266 image has no append_digest field
3064 def make_image(args
):
3065 image
= ESP8266ROMFirmwareImage()
3066 if len(args
.segfile
) == 0:
3067 raise FatalError('No segments specified')
3068 if len(args
.segfile
) != len(args
.segaddr
):
3069 raise FatalError('Number of specified files does not match number of specified addresses')
3070 for (seg
, addr
) in zip(args
.segfile
, args
.segaddr
):
3071 with
open(seg
, 'rb') as f
:
3073 image
.segments
.append(ImageSegment(addr
, data
))
3074 image
.entrypoint
= args
.entrypoint
3075 image
.save(args
.output
)
3078 def elf2image(args
):
3079 e
= ELFFile(args
.input)
3080 if args
.chip
== 'auto': # Default to ESP8266 for backwards compatibility
3081 print("Creating image for ESP8266...")
3082 args
.chip
= 'esp8266'
3084 if args
.chip
== 'esp32':
3085 image
= ESP32FirmwareImage()
3087 image
.secure_pad
= '1'
3088 elif args
.secure_pad_v2
:
3089 image
.secure_pad
= '2'
3090 image
.min_rev
= int(args
.min_rev
)
3091 elif args
.chip
== 'esp32s2':
3092 image
= ESP32S2FirmwareImage()
3093 if args
.secure_pad_v2
:
3094 image
.secure_pad
= '2'
3096 elif args
.chip
== 'esp32s3beta2':
3097 image
= ESP32S3BETA2FirmwareImage()
3098 if args
.secure_pad_v2
:
3099 image
.secure_pad
= '2'
3101 elif args
.chip
== 'esp32c3':
3102 image
= ESP32C3FirmwareImage()
3103 if args
.secure_pad_v2
:
3104 image
.secure_pad
= '2'
3106 elif args
.version
== '1': # ESP8266
3107 image
= ESP8266ROMFirmwareImage()
3109 image
= ESP8266V2FirmwareImage()
3110 image
.entrypoint
= e
.entrypoint
3111 image
.segments
= e
.sections
# ELFSection is a subclass of ImageSegment
3112 image
.flash_mode
= {'qio': 0, 'qout': 1, 'dio': 2, 'dout': 3}[args
.flash_mode
]
3113 image
.flash_size_freq
= image
.ROM_LOADER
.FLASH_SIZES
[args
.flash_size
]
3114 image
.flash_size_freq
+= {'40m': 0, '26m': 1, '20m': 2, '80m': 0xf}[args
.flash_freq
]
3116 if args
.elf_sha256_offset
:
3117 image
.elf_sha256
= e
.sha256()
3118 image
.elf_sha256_offset
= args
.elf_sha256_offset
3122 if args
.output
is None:
3123 args
.output
= image
.default_output_name(args
.input)
3124 image
.save(args
.output
)
3127 def read_mac(esp
, args
):
3128 mac
= esp
.read_mac()
3130 def print_mac(label
, mac
):
3131 print('%s: %s' % (label
, ':'.join(map(lambda x
: '%02x' % x
, mac
))))
3132 print_mac("MAC", mac
)
3135 def chip_id(esp
, args
):
3137 chipid
= esp
.chip_id()
3138 print('Chip ID: 0x%08x' % chipid
)
3139 except NotSupportedError
:
3140 print('Warning: %s has no Chip ID. Reading MAC instead.' % esp
.CHIP_NAME
)
3144 def erase_flash(esp
, args
):
3145 print('Erasing flash (this may take a while)...')
3148 print('Chip erase completed successfully in %.1fs' % (time
.time() - t
))
3151 def erase_region(esp
, args
):
3152 print('Erasing region (may be slow depending on size)...')
3154 esp
.erase_region(args
.address
, args
.size
)
3155 print('Erase completed successfully in %.1f seconds.' % (time
.time() - t
))
3162 def flash_id(esp
, args
):
3163 flash_id
= esp
.flash_id()
3164 print('Manufacturer: %02x' % (flash_id
& 0xff))
3165 flid_lowbyte
= (flash_id
>> 16) & 0xFF
3166 print('Device: %02x%02x' % ((flash_id
>> 8) & 0xff, flid_lowbyte
))
3167 print('Detected flash size: %s' % (DETECTED_FLASH_SIZES
.get(flid_lowbyte
, "Unknown")))
3170 def read_flash(esp
, args
):
3171 if args
.no_progress
:
3172 flash_progress
= None
3174 def flash_progress(progress
, length
):
3175 msg
= '%d (%d %%)' % (progress
, progress
* 100.0 / length
)
3176 padding
= '\b' * len(msg
)
3177 if progress
== length
:
3179 sys
.stdout
.write(msg
+ padding
)
3182 data
= esp
.read_flash(args
.address
, args
.size
, flash_progress
)
3184 print_overwrite('Read %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...'
3185 % (len(data
), args
.address
, t
, len(data
) / t
* 8 / 1000), last_line
=True)
3186 with
open(args
.filename
, 'wb') as f
:
3190 def verify_flash(esp
, args
):
3193 for address
, argfile
in args
.addr_filename
:
3194 image
= pad_to(argfile
.read(), 4)
3195 argfile
.seek(0) # rewind in case we need it again
3197 image
= _update_image_flash_params(esp
, address
, args
, image
)
3199 image_size
= len(image
)
3200 print('Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size
, image_size
, address
, argfile
.name
))
3201 # Try digest first, only read if there are differences.
3202 digest
= esp
.flash_md5sum(address
, image_size
)
3203 expected_digest
= hashlib
.md5(image
).hexdigest()
3204 if digest
== expected_digest
:
3205 print('-- verify OK (digest matched)')
3209 if getattr(args
, 'diff', 'no') != 'yes':
3210 print('-- verify FAILED (digest mismatch)')
3213 flash
= esp
.read_flash(address
, image_size
)
3214 assert flash
!= image
3215 diff
= [i
for i
in range(image_size
) if flash
[i
] != image
[i
]]
3216 print('-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff
), address
+ diff
[0]))
3218 flash_byte
= flash
[d
]
3219 image_byte
= image
[d
]
3221 flash_byte
= ord(flash_byte
)
3222 image_byte
= ord(image_byte
)
3223 print(' %08x %02x %02x' % (address
+ d
, flash_byte
, image_byte
))
3225 raise FatalError("Verify failed.")
3228 def read_flash_status(esp
, args
):
3229 print('Status value: 0x%04x' % esp
.read_status(args
.bytes
))
3232 def write_flash_status(esp
, args
):
3233 fmt
= "0x%%0%dx" % (args
.bytes
* 2)
3234 args
.value
= args
.value
& ((1 << (args
.bytes
* 8)) - 1)
3235 print(('Initial flash status: ' + fmt
) % esp
.read_status(args
.bytes
))
3236 print(('Setting flash status: ' + fmt
) % args
.value
)
3237 esp
.write_status(args
.value
, args
.bytes
, args
.non_volatile
)
3238 print(('After flash status: ' + fmt
) % esp
.read_status(args
.bytes
))
3241 def get_security_info(esp
, args
):
3242 (flags
, flash_crypt_cnt
, key_purposes
) = esp
.get_security_info()
3243 # TODO: better display
3244 print('Flags: 0x%08x (%s)' % (flags
, bin(flags
)))
3245 print('Flash_Crypt_Cnt: 0x%x' % flash_crypt_cnt
)
3246 print('Key_Purposes: %s' % (key_purposes
,))
3253 # End of operations functions
3257 def main(custom_commandline
=None):
3259 Main function for esptool
3261 custom_commandline - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments
3262 as strings. Arguments and their values need to be added as individual items to the list e.g. "-b 115200" thus
3263 becomes ['-b', '115200'].
3265 parser
= argparse
.ArgumentParser(description
='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__
, prog
='esptool')
3267 parser
.add_argument('--chip', '-c',
3268 help='Target chip type',
3269 type=lambda c
: c
.lower().replace('-', ''), # support ESP32-S2, etc.
3270 choices
=['auto', 'esp8266', 'esp32', 'esp32s2', 'esp32s3beta2', 'esp32c3'],
3271 default
=os
.environ
.get('ESPTOOL_CHIP', 'auto'))
3273 parser
.add_argument(
3275 help='Serial port device',
3276 default
=os
.environ
.get('ESPTOOL_PORT', None))
3278 parser
.add_argument(
3280 help='Serial port baud rate used when flashing/reading',
3282 default
=os
.environ
.get('ESPTOOL_BAUD', ESPLoader
.ESP_ROM_BAUD
))
3284 parser
.add_argument(
3286 help='What to do before connecting to the chip',
3287 choices
=['default_reset', 'no_reset', 'no_reset_no_sync'],
3288 default
=os
.environ
.get('ESPTOOL_BEFORE', 'default_reset'))
3290 parser
.add_argument(
3292 help='What to do after esptool.py is finished',
3293 choices
=['hard_reset', 'soft_reset', 'no_reset'],
3294 default
=os
.environ
.get('ESPTOOL_AFTER', 'hard_reset'))
3296 parser
.add_argument(
3298 help="Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available.",
3299 action
='store_true')
3301 parser
.add_argument(
3303 help="Enable trace-level output of esptool.py interactions.",
3304 action
='store_true')
3306 parser
.add_argument(
3307 '--override-vddsdio',
3308 help="Override ESP32 VDDSDIO internal voltage regulator (use with care)",
3309 choices
=ESP32ROM
.OVERRIDE_VDDSDIO_CHOICES
,
3312 parser
.add_argument(
3313 '--connect-attempts',
3314 help=('Number of attempts to connect, negative or 0 for infinite. '
3315 'Default: %d.' % DEFAULT_CONNECT_ATTEMPTS
),
3317 default
=os
.environ
.get('ESPTOOL_CONNECT_ATTEMPTS', DEFAULT_CONNECT_ATTEMPTS
))
3319 subparsers
= parser
.add_subparsers(
3321 help='Run esptool {command} -h for additional help')
3323 def add_spi_connection_arg(parent
):
3324 parent
.add_argument('--spi-connection', '-sc', help='ESP32-only argument. Override default SPI Flash connection. '
3325 'Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers to use for SPI flash (CLK,Q,D,HD,CS).',
3326 action
=SpiConnectionAction
)
3328 parser_load_ram
= subparsers
.add_parser(
3330 help='Download an image to RAM and execute')
3331 parser_load_ram
.add_argument('filename', help='Firmware image')
3333 parser_dump_mem
= subparsers
.add_parser(
3335 help='Dump arbitrary memory to disk')
3336 parser_dump_mem
.add_argument('address', help='Base address', type=arg_auto_int
)
3337 parser_dump_mem
.add_argument('size', help='Size of region to dump', type=arg_auto_int
)
3338 parser_dump_mem
.add_argument('filename', help='Name of binary dump')
3340 parser_read_mem
= subparsers
.add_parser(
3342 help='Read arbitrary memory location')
3343 parser_read_mem
.add_argument('address', help='Address to read', type=arg_auto_int
)
3345 parser_write_mem
= subparsers
.add_parser(
3347 help='Read-modify-write to arbitrary memory location')
3348 parser_write_mem
.add_argument('address', help='Address to write', type=arg_auto_int
)
3349 parser_write_mem
.add_argument('value', help='Value', type=arg_auto_int
)
3350 parser_write_mem
.add_argument('mask', help='Mask of bits to write', type=arg_auto_int
)
3352 def add_spi_flash_subparsers(parent
, is_elf2image
):
3353 """ Add common parser arguments for SPI flash properties """
3354 extra_keep_args
= [] if is_elf2image
else ['keep']
3355 auto_detect
= not is_elf2image
3358 extra_fs_message
= ", detect, or keep"
3360 extra_fs_message
= ""
3362 parent
.add_argument('--flash_freq', '-ff', help='SPI Flash frequency',
3363 choices
=extra_keep_args
+ ['40m', '26m', '20m', '80m'],
3364 default
=os
.environ
.get('ESPTOOL_FF', '40m' if is_elf2image
else 'keep'))
3365 parent
.add_argument('--flash_mode', '-fm', help='SPI Flash mode',
3366 choices
=extra_keep_args
+ ['qio', 'qout', 'dio', 'dout'],
3367 default
=os
.environ
.get('ESPTOOL_FM', 'qio' if is_elf2image
else 'keep'))
3368 parent
.add_argument('--flash_size', '-fs', help='SPI Flash size in MegaBytes (1MB, 2MB, 4MB, 8MB, 16M)'
3369 ' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)' + extra_fs_message
,
3370 action
=FlashSizeAction
, auto_detect
=auto_detect
,
3371 default
=os
.environ
.get('ESPTOOL_FS', '1MB' if is_elf2image
else 'keep'))
3372 add_spi_connection_arg(parent
)
3374 parser_write_flash
= subparsers
.add_parser(
3376 help='Write a binary blob to flash')
3378 parser_write_flash
.add_argument('addr_filename', metavar
='<address> <filename>', help='Address followed by binary filename, separated by space',
3379 action
=AddrFilenamePairAction
)
3380 parser_write_flash
.add_argument('--erase-all', '-e',
3381 help='Erase all regions of flash (not just write areas) before programming',
3382 action
="store_true")
3384 add_spi_flash_subparsers(parser_write_flash
, is_elf2image
=False)
3385 parser_write_flash
.add_argument('--no-progress', '-p', help='Suppress progress output', action
="store_true")
3386 parser_write_flash
.add_argument('--verify', help='Verify just-written data on flash '
3387 '(mostly superfluous, data is read back during flashing)', action
='store_true')
3388 parser_write_flash
.add_argument('--encrypt', help='Apply flash encryption when writing data (required correct efuse settings)',
3389 action
='store_true')
3390 parser_write_flash
.add_argument('--ignore-flash-encryption-efuse-setting', help='Ignore flash encryption efuse settings ',
3391 action
='store_true')
3393 compress_args
= parser_write_flash
.add_mutually_exclusive_group(required
=False)
3394 compress_args
.add_argument('--compress', '-z', help='Compress data in transfer (default unless --no-stub is specified)',
3395 action
="store_true", default
=None)
3396 compress_args
.add_argument('--no-compress', '-u', help='Disable data compression during transfer (default if --no-stub is specified)',
3397 action
="store_true")
3399 subparsers
.add_parser(
3401 help='Run application code in flash')
3403 parser_image_info
= subparsers
.add_parser(
3405 help='Dump headers from an application image')
3406 parser_image_info
.add_argument('filename', help='Image file to parse')
3408 parser_make_image
= subparsers
.add_parser(
3410 help='Create an application image from binary files')
3411 parser_make_image
.add_argument('output', help='Output image file')
3412 parser_make_image
.add_argument('--segfile', '-f', action
='append', help='Segment input file')
3413 parser_make_image
.add_argument('--segaddr', '-a', action
='append', help='Segment base address', type=arg_auto_int
)
3414 parser_make_image
.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int
, default
=0)
3416 parser_elf2image
= subparsers
.add_parser(
3418 help='Create an application image from ELF file')
3419 parser_elf2image
.add_argument('input', help='Input ELF file')
3420 parser_elf2image
.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str)
3421 parser_elf2image
.add_argument('--version', '-e', help='Output image version', choices
=['1', '2'], default
='1')
3422 parser_elf2image
.add_argument('--min-rev', '-r', help='Minimum chip revision', choices
=['0', '1', '2', '3'], default
='0')
3423 parser_elf2image
.add_argument('--secure-pad', action
='store_true',
3424 help='Pad image so once signed it will end on a 64KB boundary. For Secure Boot v1 images only.')
3425 parser_elf2image
.add_argument('--secure-pad-v2', action
='store_true',
3426 help='Pad image to 64KB, so once signed its signature sector will start at the next 64K block. '
3427 'For Secure Boot v2 images only.')
3428 parser_elf2image
.add_argument('--elf-sha256-offset', help='If set, insert SHA256 hash (32 bytes) of the input ELF file at specified offset in the binary.',
3429 type=arg_auto_int
, default
=None)
3431 add_spi_flash_subparsers(parser_elf2image
, is_elf2image
=True)
3433 subparsers
.add_parser(
3435 help='Read MAC address from OTP ROM')
3437 subparsers
.add_parser(
3439 help='Read Chip ID from OTP ROM')
3441 parser_flash_id
= subparsers
.add_parser(
3443 help='Read SPI flash manufacturer and device ID')
3444 add_spi_connection_arg(parser_flash_id
)
3446 parser_read_status
= subparsers
.add_parser(
3447 'read_flash_status',
3448 help='Read SPI flash status register')
3450 add_spi_connection_arg(parser_read_status
)
3451 parser_read_status
.add_argument('--bytes', help='Number of bytes to read (1-3)', type=int, choices
=[1, 2, 3], default
=2)
3453 parser_write_status
= subparsers
.add_parser(
3454 'write_flash_status',
3455 help='Write SPI flash status register')
3457 add_spi_connection_arg(parser_write_status
)
3458 parser_write_status
.add_argument('--non-volatile', help='Write non-volatile bits (use with caution)', action
='store_true')
3459 parser_write_status
.add_argument('--bytes', help='Number of status bytes to write (1-3)', type=int, choices
=[1, 2, 3], default
=2)
3460 parser_write_status
.add_argument('value', help='New value', type=arg_auto_int
)
3462 parser_read_flash
= subparsers
.add_parser(
3464 help='Read SPI flash content')
3465 add_spi_connection_arg(parser_read_flash
)
3466 parser_read_flash
.add_argument('address', help='Start address', type=arg_auto_int
)
3467 parser_read_flash
.add_argument('size', help='Size of region to dump', type=arg_auto_int
)
3468 parser_read_flash
.add_argument('filename', help='Name of binary dump')
3469 parser_read_flash
.add_argument('--no-progress', '-p', help='Suppress progress output', action
="store_true")
3471 parser_verify_flash
= subparsers
.add_parser(
3473 help='Verify a binary blob against flash')
3474 parser_verify_flash
.add_argument('addr_filename', help='Address and binary file to verify there, separated by space',
3475 action
=AddrFilenamePairAction
)
3476 parser_verify_flash
.add_argument('--diff', '-d', help='Show differences',
3477 choices
=['no', 'yes'], default
='no')
3478 add_spi_flash_subparsers(parser_verify_flash
, is_elf2image
=False)
3480 parser_erase_flash
= subparsers
.add_parser(
3482 help='Perform Chip Erase on SPI flash')
3483 add_spi_connection_arg(parser_erase_flash
)
3485 parser_erase_region
= subparsers
.add_parser(
3487 help='Erase a region of the flash')
3488 add_spi_connection_arg(parser_erase_region
)
3489 parser_erase_region
.add_argument('address', help='Start address (must be multiple of 4096)', type=arg_auto_int
)
3490 parser_erase_region
.add_argument('size', help='Size of region to erase (must be multiple of 4096)', type=arg_auto_int
)
3492 subparsers
.add_parser(
3493 'version', help='Print esptool version')
3495 subparsers
.add_parser('get_security_info', help='Get some security-related data')
3497 # internal sanity check - every operation matches a module function of the same name
3498 for operation
in subparsers
.choices
.keys():
3499 assert operation
in globals(), "%s should be a module function" % operation
3501 expand_file_arguments()
3503 args
= parser
.parse_args(custom_commandline
)
3505 print('esptool.py v%s' % __version__
)
3507 # operation function can take 1 arg (args), 2 args (esp, arg)
3508 # or be a member function of the ESPLoader class.
3510 if args
.operation
is None:
3514 operation_func
= globals()[args
.operation
]
3517 # This function is depreciated in Python3
3518 operation_args
= inspect
.getargspec(operation_func
).args
3520 operation_args
= inspect
.getfullargspec(operation_func
).args
3522 if operation_args
[0] == 'esp': # operation function takes an ESPLoader connection object
3523 if args
.before
!= "no_reset_no_sync":
3524 initial_baud
= min(ESPLoader
.ESP_ROM_BAUD
, args
.baud
) # don't sync faster than the default baud rate
3526 initial_baud
= args
.baud
3528 if args
.port
is None:
3529 if list_ports
is None:
3530 raise FatalError("Listing all serial ports is currently not available on this operating system version. "
3531 "Specify the port when running esptool.py")
3532 ser_list
= sorted(ports
.device
for ports
in list_ports
.comports())
3533 print("Found %d serial ports" % len(ser_list
))
3535 ser_list
= [args
.port
]
3537 for each_port
in reversed(ser_list
):
3538 print("Serial port %s" % each_port
)
3540 if args
.chip
== 'auto':
3541 esp
= ESPLoader
.detect_chip(each_port
, initial_baud
, args
.before
, args
.trace
,
3542 args
.connect_attempts
)
3545 'esp8266': ESP8266ROM
,
3547 'esp32s2': ESP32S2ROM
,
3548 'esp32s3beta2': ESP32S3BETA2ROM
,
3549 'esp32c3': ESP32C3ROM
,
3551 esp
= chip_class(each_port
, initial_baud
, args
.trace
)
3552 esp
.connect(args
.before
, args
.connect_attempts
)
3554 except (FatalError
, OSError) as err
:
3555 if args
.port
is not None:
3557 print("%s failed to connect: %s" % (each_port
, err
))
3560 raise FatalError("Could not connect to an Espressif device on any of the %d available serial ports." % len(ser_list
))
3562 if esp
.secure_download_mode
:
3563 print("Chip is %s in Secure Download Mode" % esp
.CHIP_NAME
)
3565 print("Chip is %s" % (esp
.get_chip_description()))
3566 print("Features: %s" % ", ".join(esp
.get_chip_features()))
3567 print("Crystal is %dMHz" % esp
.get_crystal_freq())
3570 if not args
.no_stub
:
3571 if esp
.secure_download_mode
:
3572 print("WARNING: Stub loader is not supported in Secure Download Mode, setting --no-stub")
3575 esp
= esp
.run_stub()
3577 if args
.override_vddsdio
:
3578 esp
.override_vddsdio(args
.override_vddsdio
)
3580 # if args.baud > initial_baud:
3582 # esp.change_baud(args.baud)
3583 # except NotImplementedInROMError:
3584 # print("WARNING: ROM doesn't support changing baud rate. Keeping initial baud rate %d" % initial_baud)
3586 # override common SPI flash parameter stuff if configured to do so
3587 if hasattr(args
, "spi_connection") and args
.spi_connection
is not None:
3588 if esp
.CHIP_NAME
!= "ESP32":
3589 raise FatalError("Chip %s does not support --spi-connection option." % esp
.CHIP_NAME
)
3590 print("Configuring SPI flash mode...")
3591 esp
.flash_spi_attach(args
.spi_connection
)
3593 print("Enabling default SPI flash mode...")
3594 # ROM loader doesn't enable flash unless we explicitly do it
3595 esp
.flash_spi_attach(0)
3597 if hasattr(args
, "flash_size"):
3598 print("Configuring flash size...")
3599 detect_flash_size(esp
, args
)
3600 if args
.flash_size
!= 'keep': # TODO: should set this even with 'keep'
3601 esp
.flash_set_parameters(flash_size_bytes(args
.flash_size
))
3604 operation_func(esp
, args
)
3606 try: # Clean up AddrFilenamePairAction files
3607 for address
, argfile
in args
.addr_filename
:
3609 except AttributeError:
3612 # Handle post-operation behaviour (reset or other)
3613 if operation_func
== load_ram
:
3614 # the ESP is now running the loaded image, so let it run
3615 print('Exiting immediately.')
3616 elif args
.after
== 'hard_reset':
3617 print('Hard resetting via RTS pin...')
3619 elif args
.after
== 'soft_reset':
3620 print('Soft resetting...')
3621 # flash_finish will trigger a soft reset
3622 esp
.soft_reset(False)
3624 print('Staying in bootloader.')
3626 esp
.soft_reset(True) # exit stub back to ROM loader
3631 operation_func(args
)
3634 def expand_file_arguments():
3635 """ Any argument starting with "@" gets replaced with all values read from a text file.
3636 Text file arguments can be split by newline or by space.
3637 Values are added "as-is", as if they were specified in this order on the command line.
3641 for arg
in sys
.argv
:
3642 if arg
.startswith("@"):
3644 with
open(arg
[1:], "r") as f
:
3645 for line
in f
.readlines():
3646 new_args
+= shlex
.split(line
)
3648 new_args
.append(arg
)
3650 print("esptool.py %s" % (" ".join(new_args
[1:])))
3654 class FlashSizeAction(argparse
.Action
):
3655 """ Custom flash size parser class to support backwards compatibility with megabit size arguments.
3657 (At next major relase, remove deprecated sizes and this can become a 'normal' choices= argument again.)
3659 def __init__(self
, option_strings
, dest
, nargs
=1, auto_detect
=False, **kwargs
):
3660 super(FlashSizeAction
, self
).__init
__(option_strings
, dest
, nargs
, **kwargs
)
3661 self
._auto
_detect
= auto_detect
3663 def __call__(self
, parser
, namespace
, values
, option_string
=None):
3674 print("WARNING: Flash size arguments in megabits like '%s' are deprecated." % (values
[0]))
3675 print("Please use the equivalent size '%s'." % (value
))
3676 print("Megabit arguments may be removed in a future release.")
3680 known_sizes
= dict(ESP8266ROM
.FLASH_SIZES
)
3681 known_sizes
.update(ESP32ROM
.FLASH_SIZES
)
3682 if self
._auto
_detect
:
3683 known_sizes
['detect'] = 'detect'
3684 known_sizes
['keep'] = 'keep'
3685 if value
not in known_sizes
:
3686 raise argparse
.ArgumentError(self
, '%s is not a known flash size. Known sizes: %s' % (value
, ", ".join(known_sizes
.keys())))
3687 setattr(namespace
, self
.dest
, value
)
3690 class SpiConnectionAction(argparse
.Action
):
3691 """ Custom action to parse 'spi connection' override. Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas.
3693 def __call__(self
, parser
, namespace
, value
, option_string
=None):
3694 if value
.upper() == "SPI":
3696 elif value
.upper() == "HSPI":
3699 values
= value
.split(",")
3700 if len(values
) != 5:
3701 raise argparse
.ArgumentError(self
, '%s is not a valid list of comma-separate pin numbers. Must be 5 numbers - CLK,Q,D,HD,CS.' % value
)
3703 values
= tuple(int(v
, 0) for v
in values
)
3705 raise argparse
.ArgumentError(self
, '%s is not a valid argument. All pins must be numeric values' % values
)
3706 if any([v
for v
in values
if v
> 33 or v
< 0]):
3707 raise argparse
.ArgumentError(self
, 'Pin numbers must be in the range 0-33.')
3708 # encode the pin numbers as a 32-bit integer with packed 6-bit values, the same way ESP32 ROM takes them
3709 # TODO: make this less ESP32 ROM specific somehow...
3710 clk
, q
, d
, hd
, cs
= values
3711 value
= (hd
<< 24) |
(cs
<< 18) |
(d
<< 12) |
(q
<< 6) | clk
3713 raise argparse
.ArgumentError(self
, '%s is not a valid spi-connection value. '
3714 'Values are SPI, HSPI, or a sequence of 5 pin numbers CLK,Q,D,HD,CS).' % value
)
3715 setattr(namespace
, self
.dest
, value
)
3718 class AddrFilenamePairAction(argparse
.Action
):
3719 """ Custom parser class for the address/filename pairs passed as arguments """
3720 def __init__(self
, option_strings
, dest
, nargs
='+', **kwargs
):
3721 super(AddrFilenamePairAction
, self
).__init
__(option_strings
, dest
, nargs
, **kwargs
)
3723 def __call__(self
, parser
, namespace
, values
, option_string
=None):
3724 # validate pair arguments
3726 for i
in range(0, len(values
), 2):
3728 address
= int(values
[i
], 0)
3730 raise argparse
.ArgumentError(self
, 'Address "%s" must be a number' % values
[i
])
3732 argfile
= open(values
[i
+ 1], 'rb')
3733 except IOError as e
:
3734 raise argparse
.ArgumentError(self
, e
)
3736 raise argparse
.ArgumentError(self
, 'Must be pairs of an address and the binary filename to write there')
3737 pairs
.append((address
, argfile
))
3739 # Sort the addresses and check for overlapping
3741 for address
, argfile
in sorted(pairs
, key
=lambda x
: x
[0]):
3742 argfile
.seek(0, 2) # seek to end
3743 size
= argfile
.tell()
3745 sector_start
= address
& ~
(ESPLoader
.FLASH_SECTOR_SIZE
- 1)
3746 sector_end
= ((address
+ size
+ ESPLoader
.FLASH_SECTOR_SIZE
- 1) & ~
(ESPLoader
.FLASH_SECTOR_SIZE
- 1)) - 1
3747 if sector_start
< end
:
3748 message
= 'Detected overlap at address: 0x%x for file: %s' % (address
, argfile
.name
)
3749 raise argparse
.ArgumentError(self
, message
)
3751 setattr(namespace
, self
.dest
, pairs
)
3754 # Binary stub code (see flasher_stub dir for source & details)
3755 ESP8266ROM
.STUB_CODE
= eval(zlib
.decompress(base64
.b64decode(b
"""
3756 eNq9PHt/1Da2X8WehCQzJEWyPR6ZxzKZJNNQoIVwSeluehtbtunlVygM6ZJ2YT/79XnJsmeSkL7+yEO2LB2dc3Te0n82z6rzs83bQbF5cp6bk3OtTs6Vmja/9Ml5XcPP/AwetT9Z82Pw7f3mgZGuTcMo+pGeJvHb\
3757 06n8d7jLH2SJGwp+ZzSljk7OLbRVEMDcUd78ipue45PzagLzNR1ygK1qhkgX8PZp00rgcxg6hX+0PGkGUWMA5KvnzbgqAAh+hG9mzVRjhExRX13sAZDwL/ebPYfft1P3YLCHv+XLZpKqoEnguwa4LLofNg8FBPqn\
3758 AarCxd2OuiA8lR4nm7AUWrtJuwiXH/5w2PxqIfwOhpkDljqdvut0gk/iBpoSYb3dgK8s4ZQ7REc8DVBD8N/wwgKoQK9ybDkmMD4TCEdU97853H1AnJRbfpsnrrHVLFfBwA2WK0sUxwaCg0OfCtt1165X4AOwv+qZ\
3759 sV02pBl6HdtJei95IYQ/12jm3/RGTFaByyB3Fq+MN0jRedPZLGbY22C1P0DMDcCCa8BIbrTM8pao78MIpexI4x4TzXTRQ4VpV+L2+ZPmV+U1dCSNux6YhfLmLxKvUUIjx8Yd74O6IzisDxkMVXlSRBVd0ruX2FNW\
3760 t5IBVBdC2qcMgO4yVubTAxu5LMcKPaeERNfI28YLpOJ0f45/th/hn/NDx1Nf8X9F8oD/s/YL/q80Gf7X9C5laFhbhUuaPtqQufnbkGAC6DOQfrQ98ROtYRsP8rUBblJaXZQ3gspGeSPjyigH+RPlINqinPFWsbC1\
3761 Dl8wRcRiq4gZU5b2gUp9bANI0cPBBHo36LBjoonSDAFsQGX3RuEBQ6S5EzzX4UeeWf/Gs+UolkbbThw1/wB6opDw3UKCT7X/9IiGL5eWA71QtA4IXQgEDQ8kioP1oCsfEfiAh4v7w/Hz6HOfv5Nd2Ij4rGIlQP9o\
3762 +adgyBQvL2IoyxWkyZD6mjC15iA39JlO38s3jMCS3/QEfdY+1dFgFxhsgHId4LDr+GQ8e7oX5YMNZLVGKGgbT6B7wKrJ+LuMvo4j/APKC5WjVoOgBv2qt3bc3FvQY5APuuyk7WDwdI8ZRPlcBBo5Z11lWP9nMfVY\
3763 0Krq/rwkZeooaFA2YcFcT4izdcwjW9Uwpqm8uaqKADAlAzYmGindbO7S+mIjatGFdN9koCJaVobLmkRf10xRm5IgQgGUvg/qWJ5X8hBsClOvyXOUG3MSj0rVezL4f7D5jNebkpJANZLSHhJGypagIpMCNmwz0fsW\
3764 MGO9EbBPLR/OiQIyZuGNOf9VIIyEhp0ZbWpouq2aRAkBPJPO8KCB5Q2NXPeg3eFJAZl5+4nudDPpQ8c+HmCWAcvGbKYBcUsNPXS83cx5Js8UPWt+DKEi81iauvQmXPffxd6k/wV+AXR5JACILfyFPZk+IY5CSkxk\
3765 mg0moJAiEVJIb/3LsrCpcxo3a5ZNn3V0XrC9Cx8u+h8eHxEoDa5R3+AmUdvUxdpbMO13PK0K0Bw+JvSAjV3pCQ2IbBRjH7B3EchXS3ORwaBLMvbkpZuunvyjeZN3RiOw7YqhQNuh1FuG/Fi8gPlXDLolw8VGss8d\
3766 juc/CXalr2JuL2oh8KFQ6XDpVUKvbMoklhmU3mi7qRTZdQAMnOg1WkwVtVrZwYWcVbjd8gNK8u9RVI7fsRJIt31AZzIfgqUinCMEAXnZNCz4aJZjlMH3QOuBMI1gwhnqn/HPMLImVV/XsxDtAximjG+CLl4LviYR\
3767 DKoJ7WISUiHxB/wQ7iPPEREoUvLa2o2EFo2BxZojIqx1hEVN5cQ0D5OB4IaptbkHgxQstGsanTTJTJgJ+CWeNs7jnvDbOph+JLfHR/iHlR7un5j0Bnl1+sleMI0Cej1pWQrViwK1FmzAsLI4zejM4nniaetqfE2s\
3768 2PQWYiXyuhjqovuSsYpYkiL+VHqzFZImakFmMbRJO59G2GrFPfheaNqp+huW96jk0NoLeztAiUs69lHudtE3rU5yYyztRXqvq86XMgXMXra2pkYF8pR1r0PkYbvPdeyzzg5NVqs1QOn0H/Ab6bkK5dFRs2nKlGUb\
3769 zBqd07SuK1iTk8kBjCju3or1gGwitvQoVeFQ6CrfHqLJ8zBGl/3hvthditQAMWdMMKCyADRAPECh1Q/2SNbq7yoRgjHmTN2ivTIt2lHBCrjpspu0Slaw7Qgu4Ph/2UPAph1/LyYR6Gt9TGPbycC3g2qyEBtFC7tp\
3770 DKZfx/ZJwNYVWAsgYbIRtX10woyTkkRzrp9dmxCapSd4aCqJREPjrF+ygUAwMDchO9RzGS9sI0YVCJESJSgb3BgWqXoGN3qZVdfQDtlfrII14q0KmAw2XalAsBohmUY5tcN00OQSd6cAIRcz4TQaKb0OtGAnX/HZ\
3771 EQw5nqH0x+HjrZ2D/2M6pGQeUG8Sd/GgtY9RzgVxEJHEqpUTqgeHonOAkv58OKd0O8rXL7b2B8RLzaj5iNkQDYZfWFFluL53xA8wQRGBRFX5I2oaYcoY7TkYPIvCEbzIUVsyPhr8bGYer+dghVKPCC3Y8W1aTBGF\
3772 6TvaaHV1FK4X4ejtQzZ48v1XzynIYJKj/AZOcpNts0SY7WtofGgGQtadP6Z3ECaA/ZoD+jUSRI+3XgO0+RbCsnGUD+8+A+n8CfbaDrO3QQm36RvEpMJUrP8NMJLa26KXiIqI/NgTXwSKDCEPHtQH/DUgYkr4hTzV\
3773 AMHytMLWFmvuai6ifBEilnHbvMU91XjlNjndgzFfo6tdwMYvFuH6nMMSrF1NFK4jcW6EjzkGO6HYVok71YgSPs+IrGjnsQLJI554Tb0C/H0kvwsBSU7BLevMTh+X0CNuIDlq5pzBnN82E05g4x6xmlaEYRN9R/LC\
3774 qFuk1tGojP85aCydI4hEEpeARVlOYMN+aIWYjhvL5yhMiHfYjGUXMQieA7jHtMcpmhUkwvQmGHNgDk3nXfIFJGyho/yw3VS6nvKuyvW3aRs2VDXGnhW7kJY3NOIgVnUANv+83VlqhWAvG8qEQPlqe88hEP0oIL7i\
3775 B0V6N+DvO0FWYAkgB/ODwH66JkRB2yJmKZ16I8K8c89HKVlpNSxCm6ooScgi2uFtsTNobSKS9FMRipqwZ20AfnmAAIP2AxDqd0QVlOMqWB8CHwTh7hA0EvkbVbxLVAGNWpfHMwrzrJ9s3h2xtumhLYtk5eAFXrb4\
3776 ZyGp5brKik9iQaKvGftDXo6WHNGSC1r070ULL4o2JzY49DdlRCArDVjxmYBtDEV2kxgAQMjMelECe32e4M8r9hJh3bJ7OyyAsf/PWquskVYMLECxiioR47r0iAyiFQTLeY0kh/CYs5ERE2Z31eKY8q09ycQnSZjI\
3777 EoG09j2xTpksLRHIGVK8DYBydC13SbzXZSSJkzoffDUQwAQRmiVFnXpWNIWcQpYB1UdOakXsWoPzTz52UKtTyEEkLxvwaxKG1jOzHaDbuIJeroPQOmDkXFMa3GVRUOACPJ5nq7OfcFktFbLfLxWEJV4T7Mjv6kw0\
3778 sSN8h00QCJcuu7vH6GaV7LAVsjgnhT0mSjaUBu1c/Az/HggVn9MeQgxOjjlQa9jZsV5QLmYDBvAZXSYiwl87M+e+Br2aLNuW41mmm+y4cFeWoMH1G5q9hLykVU9AoKqXHD7QOPBL9tWwVT8miMDufXIjaFRrkY+d\
3779 DSYGb+nbs0U4dsr1FVD81fPTnzGOA9yfzcmXAzIQGtBBMHPf6emsAjNIccgmXokSec6aKea9Xm+ISwBICVr5MngJegCjKhAqhkBjXc7gYSTCcUyLWoBF1a6rqPrrWoQxLYoWCJb/hCMYmYvbmNneCwB7gNEJCMdR\
3780 YkK9penOwItBX4C6fKAuxEJZsgCgXwCdXjN67Pnc3yu/DWAR6IygfNkhJOgCxgXWq3VI1lgNGscIli0HHtswihNPA3a9IHxu0lNM3XBQvURZ1m5W0EK6nPdlCJt7rFrzS1Ur28Xps56ADc/cfEV44+UqW+Je1FXA\
3781 LDVgSvTRqsALwJAQmaDaDH+CsXd/cjN4/cTKxgHjVgxNv2GKAp0qijEoEjCOJeKOBj7EcOABaqZ1BYlbNbBsnDrZf9+T/ei5hj8gR7IypCyOZ8Binlv1WZFsEmR8t9Xm3RwoW/COKuYKqlQi5VFELtzuy1CGoOU/\
3782 Ec3+AV9tXkuvo2kXPkRCjFawVjO0Wh/th4c9nd/gsqPiweojdIZrqHQHGBG4T8Jd2xiihqDkkWcmKMPmLKGR8R95gQWE1up9X6yhHFD6Xyu3P5ZNoFmCyzzlWhjYOdFuiuBu4cKElOw5aPRZMI2in/VHRkJFEIwl\
3783 RsBqmovHUfrx8giQKAWxCiOBNzFC9uNUmeHgceO07gzyLx4z3zRyzMk01uUx40TVL1qu1eSxRgNhZsKxjsIvprcADMg3VWJ2RUN4NyR0Y7o4ai2vSu3RIBhS0/tfUXwyw2T7V7ujIccreJ4h+dQgtfOcc0zVmCMo\
3784 tYUCF8P7t05Ho5ASfLWdUZarVNMv2TWF6cwLCDMYltmFHa0jUbYRvDOwveJZng0ohrh3lYG/zXo+y5ZE4TZO+EZoC6Yimg6GHHUNzn+uzjmlW5DorTNPKZo2U8z4GORmFpq3AQa181sEWF1PB8Hbd7vHP7ShA5jN\
3785 TCZ33p4zptUH1IcfoPn2rZ6FaoHfY1Sl8bNsRQY17mHDliPE33IN+EreEuQZV3ZA6ElD5imPvWSRkwOz8BZ8PZi9aBNZzeebJD9qjDEHtJ+ygLYPVofltI1y3pmF2uXiMEvAGDMVOBbMMJh6exnBRPYThaso4lUF\
3786 w10yJdFmtewJJS66hKTh2VXSbmLbgJ99ZFWIzxSDlnBZi6EXuVoJzAcCRr13wTeMeIUTtsdICkxmIWccCtP4tDQ1IMGaAOkbfABQPqIACLO3v6nfFgOBf/Qh5IIHC90y9G6+heFmwHfATRna2vuzfHsRfkGyGxJ7\
3787 LlDLZQcNXDsbW15GO2ujkcYrV4Awsu1kmFqv6gZssiGJojwVaZ5uSJ0Jo7/C7hAvASe6tqO1Kdgxit0bctcijDAGmgrkkFOUGoIgSCN0x8H6UNF8vc1taE/9kJnIoMb7FF7BIKT9SJa6p7NP4TU4VA2yt9RoA40q\
3788 B1MmEqt4TwkETLekNy3afC+pRAf0y1LE6zNMIC2FGhAy9SOwzhTy7J9qID6lLu5drWaFXKj7EBdeSL3M2+D7qtoO9LzudiwhrEBiEG7ysH0Q1gIXqIgk9BBShYVH+vwl0f0UcRz5dI87dKdSA5VpGNYk85Oz5bI9\
3789 3I283Dzh/aoLcR8SJDEUWmmsRU2Ck02Fwj4fnHZp/JjwlAHrOlp0zTpn9A3A26QkyMkm5AWSEGx3uwi3KC7xb4JKancWM2HUNqCKhRKGwtng+0/I8nfOrB/t81wgSnuEXwozp1kxhyBipX8itLZReZHFg3yDzHWK\
3790 rS6uy6RQpZJydnMFZ14U4lmEG1e59B84lNWgY0N/RzjLyOW2EnB0mqim7zM0yora5TQAAvD50EH0g3KmQ7xRHT6lGYyj4+iWs/6AGtnJQt9gLQHWiSH7yt5OnLuBPnDf9WXR1vd7uUyCLXJfOFFQMyP7BLK1zRDw\
3791 J3pVvvQzsL+21UwZBhs8B7DDE89IAFkuiav1bRg7vAO/76GNt2zWft2HurEAIZJTU60CuMoI020sH3zQ7+07wJwqqO0WEaXxlIZMHi7Dq+05WaVl+pL43qb3EHegOJywUqkoEDC6ql02SYoniTxfE9w89rdURy/N\
3792 v2AObzvDHGBGQP0K5CUrUPlZ0lE9xQrVQ+lCVj0zT/W46iCOvUW96FdXA7HWyTzT46/UQJ8TwtWd+Gb5WUGjP1MDFX+bBtqluorLyY6GNRQ4KaY8FdoFQykv5OpE68OLREadU7SE1cVah7qkOdi6xKEmbAvXMUqI\
3793 Kdf4cpQeQ7pIXGhAjYjTRt0wf+C0UZvPr9luJjRPW/Oo651TqFNJGFT1wqARYssLg9YU++SoKwZAsbQi75uGwFgZl0s6bpE89FpwEdMwOVuaafYpWpqhJ6GWTUUinNJIKdgernbGEk10sX6RMaAydRstUWYPk8fT\
3794 mI0SrNJBoyBiKzTmUEXpqZkLKPIBEPyRa5awJmOCZQ6zJczsI/jrwcXbqeSKExX1mBqqDvoIIs6e+QjCGaaBnj4QBEUegjAxKtopXRJHw0Yc5f8V7PRNptecH2cbvS4lRO6hW3Az9XCjOGeMjIT4jOZdFm1wAEPp\
3795 m8/nXOVcA1wmqSkt4upKJEpBpwVGtQR2ES/Aq/rVgIuQN0KhdGOZvCrYEeDEJnhGavzhLhUxolSqfl8ETXPgX6UcN/IEqhdBuzQ31thmG1enQ3IKaRbY149dpv43ftTytBe1TLsWUpu/7jp6czYPbkgRbcfHM6xd\
3796 H62WscC/qr7Evauu5d51FOsBgP0zs6ecEKv/avfuOpyAsEK53gUqtssRf5KKnf+t+jXnOuOW9qdd2l/i4pmui9fVr0bv07B/r3OHtnMhe0aPYoMBpXxDs5qA3TlaY6myhfLjDef5YUfqai7S4/MMMRJjWIk1aeNv\
3797 V9tj5UXiI/ss8ZFN2PtiaeNLkLz9rKAMaCtERrTB3nSwxxWSiMAi33rHAUsCeuvtL1I9Gd6UQ6Y5OmIsTEipq9uDRT68RyKAiwaprG6Xkr9oNeWIOTzhkfzEEjySIlw0rbafZVgFg7G9u1DBUWKO4dPJAl/YDaoN\
3798 vzQjy2eUcmcHEaaGDT4W4c3TEbIKH6rK3xJm1jwiAGkajXwgEj0fssJTxc/HvGVEsBS8/+jbgpmB1ak819h02ju6M8AH0R1QomlKeRuIgdepG4pGgJSoGgtsmlTrq+d+fYqEWj9S9Nk4T2XRHlhyEcPKPz8GE8Iu\
3799 QFUxYXEuccRUvEasWwm8dOHnCdFttrVSrsK0n1dv05Oq2V9bb/MRVuNqbSgl3anTgiyZX5LQsNE6VBnmvEu4rAHztSVysJZ/HuOBtzxxKekDti4kHwlOeOO4N054QCkP7WIMIJkeXVTmcw0KZLFfO/bn5wOlqAO9\
3800 pbMuqvxanjfXCVxtc6UAJq/zrFhd8NKJZU2knHEiO/jD7q+c5UB1uiUZOamAHdIDquPhMhwUNbUMHS5QIK1lRVvgZ1xkT3phIG+DLFGdPITjBhat8vgCDjLMQabPQaA1f4QpxdjFkJnhU0TZufCTVDlQJpICWXga\
3801 LmnTkBKLY/0A3AaJgQojGeGQiRPxcd3oR/gHs4jA3y4ZXYRjPucP5MRe4DPgP3z+r+TKeEzJjLlKXrYyHmLBIOGYFQCUnRoptB5/ak8ao/RPHkuyjH+wBxpL5wgLxuNu9KvCfONbJCx5uFh0G7Wl4/AM8AB+BuYY\
3802 uQDbCb6Y3skPOvc5HS50fZJL3o0veZde8m7SfQewVdw2xeA2rOLLDLA7XQN9ClxcMNYzddrxwCJfj8Gn7WCjjKSqir6EFGytIZyf42mMWWMtLPHVAUbt8dBSLmcvdmgn2vF7yhNql3yefuBzIw3/7f4TviH+YQcY\
3803 z/lPdriqFQxFK8c80uUbBDBjrcOQp84pmAH0LKOWw0p7LGKZ2ajinFvFJWaYA4yXXFQvnstegpL8Iip3DB7nR+Foa62AwGqJJQZ4EvE5/wMdS8iQ1/lwzaDtXdw6ykfvwOrALZs/C24FRb7+3ckigFTt+O1YjvAB\
3804 xDMK4RgsLsbTYtMbFN1Br1aOIGkqDyQ6gUIeb7lD1wvE9ojqUhVvMpQmZusejVNEssluaTlGAOCjCyh5Qo7XlC54Jme6JkMQcukd74gfdqhgeD4E84pLHOQUVHshhjzMYBSbojiHY3OS7VdpxfIONgDArrD4Pu8f\
3805 2Z4sP8QaJ3xoBBQspftfgcad1vhi+WOrPJ2Kzr6Ew7Tq9w64JIPtfLYsm2l3AM338HxjAD4QODfuXJDrlsL0BZ3+GPApFjOOxGtT/iFUOewXz8GfL84//fj6xfeHj829rZ2WWUGOrUJI5RdpRMT9VqJhoKHQHdN8\
3806 7LqPYhkcsvrYUW3tIGKXDqJjTKx0R6fYgRQDPjv83uw84NM3WBuVZa38o7te5KBYJvcEGD6q5o7SwS+s6JVS3exeC6O2eNwKJ3EdGRZF0Hfi1TULDMvH6OpS9gaI31rzcT5kgSjc617ZYKMQL2UI8VKGEC9lCO+T\
3807 lG4Q6d240r+foy0nhUYrdk7961FOpQy6c5EOCTrvCgRm5ejkDJ5lIRvGYHTWpneVgGXDAgUNFthaur6l1HxlRNar0sTbF+qkMw7ImMZ7XuCdPsgpzp4BLpdYE1e70schR5xrvpmmBZ5ZwBqmJ7CgHKVafX+N0wNy\
3808 MYLDW+RjNFpCL8ztIdU/D6bU+vEeA0q3F+2yCVB3GV2zO98+ftC5lgFvpDg+W0KYK5GiAhA1WFqSWbr3ZNpeSeN0YOKv2eMKG7HbAQ+MkWojvHBpsE0farxhCQ9D8sq0eNkTwiAmS+zYu8EpLYR8cecupv7295F5\
3809 jMFd84g1p5wKinblvCqkM+BpYbafxLyZLNT9iWFDNwuYbTneWU+fyfUobprU0czdzgSSQsNhUzxY0IVxLM7XZ1DOPArwefbIbI/WhtvCtMA9q3jykVwQIy9RwIIcsOhiADLx2JwBpzPbPTl7B9v0aSuZMe4Rc1KV\
3810 w35aPJuEd4alEg84PA8rKe3u6tNDSEAk19YjTgagcbq1DfYHHoeM+BKuquUDrBAGZwgPWqlvwKNT/+BrVKRjR83aSLR4Mjw5wS8P77KOrSFDYaFyqJHJEJE0UIgGlValecrOX93eURUIMv37l5R6eshXS7WcfiZn\
3811 vJIZRkHUo90HN9xmhb7j4Rjz2MlXg9FasL07PJBau0ElFzL8RuN29JzRomTGwRopx8sEkLrTIzoC5w4Vc821lotJSlaxddHHpHSwS7LXswTKQs7Pyj1t6UXj8M0n7T7trPEqqdoRKq06IfWC3HoblF7HbB60JpO4\
3812 s3JTkEgacAYzKq0hAwB3Hv4TtYL/ItBe+IrxbfcSMYjfYoEe0sLibSLTxHuGnmAmVzN5JFjarbA1cae6/dleyyR7dcAnvRSjQzbteMUVH5qgQ05Lpc5JPArMddR8xqKkkxgLLJ7gM/BKt1uiM6yNHgN6tNKBBw1u\
3813 03K5e8lOY+kiuceQ0ynl/BXex8Fj0C09rIGXbi6qIk86x9j7QFa+0wZCuuIIudIS4suq9WPx7N5nCoUuX7pLJUgWSBHodVn9J5+NfvQbZ37j3G987LKe6d1nl/Xb/n1jxt5ZoSUy3RokpCNK3iBWzAzAFjAjMCVy\
3814 qM+UDQ2cXYLk2eb8Qx6jettteajsEHrfu/tEHZWye1/zOfuVvJeLhg75ChcsdKvhAsT0pV8/ekgnVzglVUxW3VCWiOpG/hnttjDP7/l0yrnIE/qWbArJpPgN24sxXxODW9UlOUGLRUEuAbx7bFjm9XdSbYS3Tdxi\
3815 PZevun2sNDJr/IIvsLQcUEIfZfaafQZ3p0q/dGi3vVjMmTj5Pl7teCC32QFo1U57a1XF8hsDZIgAhJZXUKodBjmzK8hk83Y2dDxzqPfH/Ec2FgAohY6ZEIjYAm9gcVf9ZFuYi7Jkbcq43cMmlbXIySg1e/xTSPFv\
3816 d6jAyKVxasWNQGj4gIKgTwYnC9yTMDhZeAfemXDOQaCHiif6oYysiBwyAZqELvWkwG7Fl2YQdt1FoxM5mrDx9TD8xDsD73zoAGyWAD4QqRieL4lB0nVSfyvXm7rNiBjg0oRuoEJuBsrRZMY7CPLungLn13x7t3WU\
3817 3QV5qedTSbZO/x4BC3GcaCZSFd27L/k0NODQepEDP2HuDoMoqJaqIhpMzumNN/iUh3WpsJmYMnj3BU4BX9vBsM0HkZvsTCK8nGvcnpfQNB9em9GKdBm4hIh7JLAXnU9aM8x99lGunas7J2nXsCIqegKMhif5Yzhk\
3818 UoyHT/Zb8umkPZomqJjghS+KuUYXA3e2Q2kw1Yv9Y4pJNFzIehI6eQAYqjLBJ5PUi2tEq0w1+tl/cNxeO8i9mkVsAfyRDz/Ehi5aAgVFKALYADtjOOtjuUrK7yCzWChQvRyQPrg4JzhrzfBnQSznEChNt/RN5GO3\
3819 fb25HeBtxz+8P8sXcOexVpPEJJNJkjRvqjdni1/9h6Z5WOZnOV+O3LnIFXff2LO7pSRYLneL+afga4zwdiBU5xOvUYxd439ITNBVtWMubsA+ufdGc+gDGiftv/4XA5Kv+DirXeOULipeHr/TwKzMym5giFNCUcat\
3820 5Y3xGhcN/QsRof/4X2ztugunMX9E3Ccg1V6jlIuaL1/GJQusyPJc8SYh56hp3CKdDI83HfJn7sOHPobNaipwMCXlhq29xu+B+/c0rMcspNWp8U8fBf0bdPs5jbjX7juavZOlbgPQT/eMxqK3qXtz686BubAXTexY\
3821 RR0zr38KpBPT0CuujNa9/rr3Puq141476bXTXtv02rbb1j14dKd/4Dc6Pf27G/Tp5Tcf/6k/+op2dE0euoqnruKxfju9oj25om0ubZ9d0npzSatzh/XKtr20vbhs71z5c919m14LR2fXWHcf8voKKdCDXPcg6V9g\
3822 rjvjrfmNm36jM+wdv7HnNzqmSYcg73uSpgdn3mvbXruKV+wS/Tfu4r9aCvxRKfFHpcgflTJ/VApd1b7mj1ZtbNPtwAnuPCp+El8lcXd88518EgR0O22VjrtwpZts9vpWcjyJVGLMp/8HHp1i9w==\
3824 ESP32ROM
.STUB_CODE
= eval(zlib
.decompress(base64
.b64decode(b
"""
3825 eNqNWntz2zYS/yo063fTG4CkSNDTTiTXle2kd7XTVnE6urkjQbLpTOqxHfWsuMl99sO+CJBS2/uDNgmCi93F7m8f0O8Hq3a9OjiJ6oPlWhl3qeW6y54v19oGD3DTP1TZct3W7qGBaf5NPoPbHXdfuatbrq2KYASo\
3826 Ju5dVw6GD92fLIpWy3XplmoT95i7a+JXUwq+mtBXRrv/+YCCYwVoO3aMIe4rGFOOZKu8OKqOO2DBjRZuKtDIgA5wqgcES5qmGzeqAqlNxKJ3JhTVcQ7fNyOmHDOOA5hp1O7igt7izOr/mTleHS6ton4notGe4GWE\
3827 oxbUZUW8mkgqS9rwC7OkyFUdKLgccVgmb+nGj6CqFx82RXEUP7rRBKSJVRTR1mwTR6kp8dsKs26e25ey8qy0TaA4O2arHAk05Gr7mnxpf2+U/9oqtmggIBdOzKKReSM3Sczy5V+D1YIkxkvSVvS2moiCzSntA8yC\
3828 /zq7FkMs2JBrEwNPKXmVtek1qROJWrH0eOrmar3nxtNg5xTfg1hIIRgc7nvq3jTJ4M0rO9jlG5i1+I3YnqYwXp6a+MXXl/FQuaUKFKfMlO9MoFtcNgufp1O5u6Bh/KbMelJiy7UWpUbo1k7HFW9KKTqeDJGhDO57\
3829 MCh5i01ox3VyFPgwa7JkSx7MLAESjBe4VLRx2u2rLYlry2P9Rza54S8cl2UdYlZyOXapYAE0/cpzI4uJSvG+AA+Y8+TMS94yVlZwz9aI64euYhF06uBTpAcmCTQBFpT6SATgjXYEWj2Hj0I/Cm3qNtRruVz1ZIbj\
3830 t8OvVsR0EzBqyDlWA+WwIodOffUFxAuGEfenxh28ya5Syx6YghHfgKP99P3Vcjkj6KevnfO0jCnGnDmF5bwD6GG7JDj6bkL/RVUhSoHP6gxkTAHs6iRiW2TfCmOQsScxWaTNjn44hA9P4iP4d5iBqpyDjbHSDIEe\
3831 neaOAmVXPb/YRflhfkyaqNi8HLcNY2fVEN6ZAEM9V1/BhiAUJaSOVnZAk01WiTd6GNeCILplPsTjEm934kqjIFfhXRSOJ7+IJ+4w62CT3SamhYqs1GcMcOMgDcggkK0EQoAM7CVymhAbJN4FTADh7EzCXBKGaRzR\
3832 RwY5zGDX4+NUfTnjaJoc3ZQXbCNowF+ANg1os5Kdnoy5fEZM9OEPlMBzFe9Wwu4I01raAnjf1KySeotKZI5lE0+HtPFboWmYTvEndBqek23O2YysJMmJpG+Jf4fmw8+6jhmeao54wE2X/VG6I/c34YMDpQYxfwqo\
3833 8Td2AECufhjCJMjrHvKdHeKh0Wy6QQo28M3cY9u1Dx81Os/V146ibTiayw4FUSak1NljP7lm59tgIR1/+CKmGLuwlE2iH7C71sHXgMRVxbDfbtlAGC+DfKGWb/a8lZJ55MNESCm0WfvHG+zNw7Ic1v6VebwLN+9t\
3834 +HAXPqzCh3X4ABr9mcGvUb3zwHpv2Y12Kp+1hhmsrrpLklMjqtVejei/2bPl7RsgdNrxlK17eu1rBJS5Eeo/QlSavHYbZNjK84L11NC6OH+Lu/rk9j7YLmTy6RpZmu8FM3Hbpu9J75oRWuodsrG7tdhoAYmSxCG7\
3835 NQ65j6p7GuxLg8krDG1P9wwgNqglMKVw+1Uj7UbQHzd/z5dntLxw9G8IqcxGbcZsPMVPZwWhasNiNqj5q9V2MU0B4bggvUpUULSVtyDx/B2T0aE64c2hV6W89IwsONdqKR+qmFMErvwdkalrQPnf2RwLTjtB/Pyb\
3836 5eonUAx88VJw7kcuMVPvv5C04hoFJQ/WdN8AC6/2YQnQBBS9yWtSCXABnlyijThN1qBJMFz0fRam7Lb4/8SXTUjBbMMC2tdWUGgim/kMA5imLfwzx8Zc1z7/7mJ2SdxyMwByRsCUGnA44+/hQflWApYI2fNRhbWl\
3837 PANDNYOQMB3Uj+NkFFki4O0fnM4OAgpZ0MMQIxIWAjGksmQitS9xPr7lpVtGpRvJKafvjjEamYSDknb4QnfW0t239A8SzAmTAQQtSZw1RTNFCZCLXjc92n1LkRzQzn2iuQht2t5/b+MKgYyzG/VHAQK+QrjRFDDx\
3838 8z4QnELUVC/jAlCj2KO9pBVekktYHXF6iclDKyACi4HFtztyM5MC8/izcW+l7h3RzQZUBjpoIHj9dOkjbLNh4jNB4Fdk4MB52E1yJnwV+xzziBN6/d/tKNyYLSqy+UaXKqGtqityJZtNoQyGkIkQ2xf0EfXGIDtV\
3839 7HLbcYeCSs3yNfoFLxkMIh5ZUg+k2pUOEW97/HXc1zaE9eMUUiDYc7DtJvl8IBYk0fnDhrSpiNOPQlBKT2cg8ykHO42TDnBQP1wvV2+u96mGhyCgbfFIFCBWoI0hg/J1+sA32Cs6Axp3Z1GHNxdxvy6k6Nnl9XyY\
3840 q2i7e3oNGRtAl/QxgGOwJrJT4LSl4rzr/nzRe/IaF+LuABrOCaV1EuY7QCrzoQEG23ZPBvcoinXd3JusUg8DRaHjlQVdyEBOEK7UY/mP7mdJIYhnNJD8Mep4ss3vZfAcVNkhrCXz16yUfB9uunMcFHzpXvuVKoS+\
3841 edybEDbQQn7A6vHe8YNLPDKxCvFtThFAQYE1EKH0JOsBybmgFidhpWzeaGGVn9Kqxx2pnrj5TqYvV8gQAwRkdxDhoO0zVCeX9iCH7g2F1h0u97q3ovNw+Ne+FkC/lbYM1kPJWFeJKEqH0xRN0cVuMKhlUBNzKhtG\
3842 rn5iOpboJCjEYUI2nnDBWRrq40HsGPYs9buii0VzCICx2lZLrwitcCvbkLF9atoht0iFtrHESH4KhpQ8wN/0Drw+8r2qOluQKQBwQbCoMAW+O6Nwjm2mihM5E8RfuKASN/rtRpZ2AtH3geMO1A4VR3kHgQfA/X1Q\
3843 dPZ9sgW1dLp27rVe8dVh23CjFlwcU4Fq9Evppj5KwfOC82Ba+9FQT8gG9fZIjputcpSbciwot3WMVowcBDuyB7jZn8LNnn8/2ivIG0Emlf8QkFCaXxGJR2m3xMRzhTcJAWmt+4SgL4a3kVEQMahtioESbSG7AiKR\
3844 cJ6ckwnQ/Fte1kDQhg43GRSbBzVqfyM7tPkvgeUCPtbZswtIbPQz1mZo7LRQJQuhAa8Tv9TdikAIUKrl9miFAWNGEA82Cklyq980p+Bin3/YJdIlGEj6CXWRL5d9p/iBIzJjkKO2CvcM0Cd/AX/Wb4B0fMpRAtK9\
3845 knvFYSFdqif3J5W4Ls4OSaAZt1MqqibgwmzeUAsax/FMRJ0fc8dSOi8TCX7cQYa5Wk/hJjr1QUfEURQW2YyzfkrBERPbGeos6oXhnBMibomddgSTs/DorgkQOxFPHOjrknHUZDJsFhwIsWuH5NZg2PlXYRpAzcie\
3846 d4YpRNtMkJrDTouZpgHfA9uwkCzX2B/DIxdNLjrGR0f6trfO+QBU989kBdkdIFQ3/kRCqa2dpqBHObZmNXCzzzEDitdJnw598His6CATq5vuTEK12eYjGIB3A7wg/mWp+Q5vVluIP7xaxxzZsxk3AVpc+xNLl/vT\
3847 YTxGSHwWDzvQ4FlWb/lUyWJ3DuNXCqHyN7i5o2X0hiZyOMgTRTaYBcurEg8wnEbPv/x2SmO6txuEWOBTGtsbbvREVliaX14+4uq3zF73BN2NOyqGrToviCcEuZJT8JIcr+XDR2zyVINmhJO/I9TWxYxT9HbN/oev\
3848 exN/E0TXakZSde0doaJJ3/SCkGru5GA7qQCEcJLU6ckODLUU0ffkxR5pt+vAmQr2VspJBdg7zNKn5+gybEcf0KYanxYWKN5+5rO+jss2NISud8eDR64AcNp7GAfKiFUoe/BeYXoDeSWCRBuAQpMgV9/JY4aP7+fc\
3849 iWuH+RN5MeBSi7qOKfRYPvWoub0zKJIq5r8MaqxhuQc9K1funk3gRUyYWOKNinYjwlvAYVxc9gc6RZZr11qP12XcT/lgred49FuFnKvqQMwG4zSwImfOPoSbeI9b6Vh+1P7LWmJAehrWPcQmxoC6jmgadimZQctn\
3850 kdXkwXcIGtyjvyikngDsQ6/HMwd1xudxkOvAIR3EW82NMLCGUs5gwuODMqn4/GPyTzm82elPRA64G8/NXUVNswNKo8BLW+zZ/bjlyI4+BultJtKzxNhV27JtGNC5QY7Hd6/h+K54gcd3xWExBZnVZUHeUteMVqQq\
3851 Dnq9th7Flh4huNLSD+SfnUAIQGsup5/6ETsrTxxJ6dD6oaIQ0GIPQmH/Jz/cFzQBGbGUwuLzxCdAFXsGIFij9xb+HNPqnVvO2Uv6EKwUqpdK/8rdSz7XsFJiW0o28N7QsRG1bv6zqUSLobQ2+7DcvWRdpFL0Gzwh\
3852 hreScdd0bFjB6azhxiXMBDgBp6VMO6IDZ37E1lnkKWKDraIKDk/BRMUtlWvggXiWKL8mCE7hRGdWdDbhXr6wblFtR/gLHv0V7M+hIZSvCk7uOs03nPk1+RG3ncHw4LQB+t6VlZaUYRdCQysub+bBTyjsl1x+MSxL\
3853 7wx4t5jzzaCl24idmqMf5tQEF0QwWoUTyqMbbhbQhMN4wdmjaAED8PdbgEw/5wCg/7751uir8eD8U79IwjE1oYrTr/PyrwDzm80JeN93GdjshmdQ/S+1xDr75Jt7XfRjCsrLLChSTsQxcSh8aFfoe+lHSgbwbcvl\
3854 l8YkeT8m2cyoJtw4i1VHn8m66LOxEO4gjaM14/5M98D/3IlYw9lf8MnItvPeRn6GJaLlg09jz8pQVwfPIvw54L/er6oH+FGgVkU2SZwSM/emvV09fOgHdVbmbrCpVlXw60Humh/wm5BQmqvJJMs+/Q8JS3S9\
3856 ESP32S2ROM
.STUB_CODE
= eval(zlib
.decompress(base64
.b64decode(b
"""
3857 eNqNW/9X3DYS/1d2nQBLSO8kr9eW095jSdp9pOn1Ak0pzeNdsWUb0pdysN3Akkv+99N8s2SvSe8HB68sjUaj+fKZkfLfnVW9Xu08G5U7Z2tl3KPgOT9baxv8oBf+Udi9s3VT77s+vjk9gD9j96FwT3O2tmoELUAy\
3858 dt+avNM8cf8kI/eaJ+5xU9Wxa0ndMwtng4EzGmi0+5t2iDhWgLyjYAxxX0CbWjlyKlhOGTXAhWvNXFegkQAdYFZ3CObUTVeuteXhzWi+/0bN92mFjlsYU/UYcQy4WQ28qccnh/QVexb/T8/ujPA8dbPCX/4TPEYY\
3859 qUEyVlZSEiVlaeF+Pl4UMlMGssx7jOXxJb34FpTqyf3mChzFT641hkVECvYRdmFzFfDMid9amHX93BbkhWelrgJ52T5beW9BXa6G5+RH+3ejgtGK9RcIyIMdk5Hs81hYiSNeXPoCtBOWYfwy6oK+FjORrnlOmwC9\
3860 4K9OjkThMlbY0kTA0JQMyNrpEckSiVrR6Gju+mq95dqnwbYpfoc1IYWgsbvpU/elijtfjm1ni0+h18kHYns+hfb8uYm+f/Ey6ko2V4HUYDdg+qbaF0UO5JyEv+dzeTsE4jwGbJ6piS6XWuQ6Qgt2Yq54p3IR86zr\
3861 BPLgvbX7nLfYhHpcxruB6bIwc9bkTs8crN/4NcMDe6fd1tqclmC5rR1k41Me4bjMy9A9xS/7JhVMgKpfeG5kMhEpvmdgAQvunPiV1+wWC3hnhcT5Q1Ox6GvKYCjSA60EmuAWlPpEBOCLdgRqvYBBoR2FanUVyjU/\
3862 W7Vkuu1X3VErYroKGDVkH6uOcFiQfaNGzUBrBI1LYD49551AG3c/yiT4kSvqQ+oVuOHcRmyE064bDANGEdMjmyQG3wkqKdnpYP90gGY452zze7jkRkmALds3Y3WworF3lKEWWUO7UXA4LIOVm8D/dxbCAcP0gp9O\
3863 JMztz/eCqZkSu2wTC6VmgnFN+6AqQdlY0vli5rl2s149vAHEw6Q7bVEBg2Ox4EgUr4k4ukF053lXYLKTXdG7Og2CIwStguJKa5+wDBAeChnNA0xwF1zsCN5ASy06ZTeomT9x/xbkdUBs4IdhkaDeaJfMCOpIvBmX\
3864 cMvqL+sAPa3IY5rNtnJgU47Plqx/7ktV1n6/20a7IM3rcNCOaOlwbMt7oytekhkKt8Tes3hzqWgO/FuXURv8ea4mGSblJ8aVzrwthb0LI1ZRJPKmlHiFmi0F1+zUp2AnB/vbkd30K9exYJOwPewp9ora4J6yIjyB\
3865 Kptt7p3RkZecAA+xgAcdwXSTEOgq+GGQvGPqKtw40KnpNusxhGtmStm9uPiybiHuYf4pXmBkQfVBLhuaVpnAXoJA9qKLxmQ7rL0JjPQA4exp8npqGR6BBKen4E3e/vT67OyA8DetBmJ86yq+dZOkHBsR/jymXUId\
3866 iEkJbb6JH4F5nQAnU4ChZTxi0cYDe2SfRaxdye6bCQx8Fu3Cn0kCWuHQT0cvryktaQoEPQESnwvWKVnnCn5LCw/NLXIQeDiNOGcE4pwKl0Wfy3/ijoP4YNGgeBIrNZmOBBrBL1rgHiBFmwXYKPYIoYkHsxB0YGa0\
3867 EatLng/NhXW1bgaCmnrMKLQfsEFTmw0vpglJIYds57SsQ+gAi7IHkojEYf6ELXrXILqAjLGInkzVNwfi0ndP88MWmX+FoQVEWMh2z4YTBZ+/noY/3h/zJhu75A02VtqU/YmymvGYNgN0WKuH9hMVvsVTR96hkUN5\
3868 /cKyGSeBd3oAQzT2ie8sDmmDhQ2f8n1E0P7EUtxGyMhxuAxGg/lDWHvIheC4PEhTSj8GFL5WJH3ym2k3/1IK98IObcT7UPiX4Y/r8Mcq/LEOfzBkQj80Lnp5binWh1nTc9TKgx+8SVISUHo5ADZZCrr7lQsLMfrH\
3869 5gzKJOkWwYHNGP+UUM3TvvCOxH6ct7QsWl38DHB39ovbhYyI2PTrAOuktACZqRtt3O+SCYq31ugpPh6xUSTI+mIrGIFJwPxPiq6aHYsEKVKo67UoZNZVSDsdcqjgn24oWLUAa3aMPvrjDTt7K84endM1LHfEtDU0\
3870 Sybj/lYSeJgB4glqTil7zHIDLn6MPn6bkVuoeKEV8vp6NbxQk0kinvrUmaHwFWz14j0vuQ4FC18mXpi26jNywkC8JuBdBFBKpe+JTFmSrZia9TbDQUsw+O/Ort6SLhTxK4FOP3PFaurZBJstGp4oo1Bos+Y74ON4\
3871 G+YBcQCWiX8huUADWG9eB74n7Vp8ofrrAS1vfAyRiNuavuLBEu9QT2sRmwavRzB9SjCdthRdQOFolwMWROhvFCh4/VcQmeVY7f/r8OAlIEtChJ+Ihornh9+gZ6goUrmGIPcx55ToYMUCv/iqp5nP93vloYHakpPC\
3872 jrROYM5+vc6wnZhO3Jl3KmSD6/H5Jf7QSVCCFa0VzhqPg00wpgzKNmeEAnC2KkycizBxrji5PhU0DWpRJ8Jlcs3NSn2QyGikVAM/1EtB4WbW4vGvpWsrO2wmWu9vhKSVN5Ps4tv6VvqqO37Lk9uWA5LdZUsz5fwN\
3873 smMBlmDSEcLa54w3xBduxNexqHBg3D6KPQeAp15FGSCpDNS3lhlekd5aPWq1uiYbc7Q+g/TH+O8BAZGmefKoW3EeP4LPLzm9hTUggTaFavZKwBpTardS8KvZi8VsVLMA+dabSX5uvyHD9bm3SCnsWgZO1sZeaJyY\
3874 rbqu8Utlk7zYZASpJx66t9GleKBkwt8BmPdpdcZvpGQH7CR7Zw6vIw93d9nEOllWGSSF6A3wecvRpxqaBlHnMXlJ0JZwPocIBqYEWmZgSTiHGdDMQm8sJSZ9hfwAXLJN5lC0BZiFmUdbfh6RiRtOZkEDcJqBvW8C\
3875 N49oiHfZBu2lnjDfMa9YhSpV2AHuaezBNgx8Mj0GN7O3oDxuqDZSsuPnxZZC6fwcIGB6y2g5UDfuGR0Kkd8H1AVkHgDDvBnGVZvtN+TlmoZLpTzbJYMkTZkqVeUZVHKXd9QFyeYPTLex3bBhksbmA6WGQAemLMSY\
3876 Uo/uF9xtibhp+/UevpYHwGfJ3gNLCBNsg8XER2er+6NtKr0DBW2zO6KhKy6VZLIzMH665JdYRKCvm1EDW6wuo47A0ndH3eRA2+3SzVezg2Org40ipwo0am8ARrzitAzn5FwYoKJLaIsL6Hx+7mvoZUoZdVheAtCS\
3877 2269C/KeImyfeWQEXFdt0O3IDsDtHcsrJsRWYDHpIvsRu8cL8ploZentqGl7fpDGBVZhtiUTOJU68zaGgAUTwVRfNSfBRFhzWESBpw95gd3KK+IFZ7gNhiLaWdC2YnkpXEHuYbHDmS3JBUlUiuA6l30MZ1V4Wuam\
3878 3GtI+MTKkfQFDbrIvIdt5L3piJHngTVItgdjdXeBb9svOx0WbtoEnOIeUlhyYTPuTDRtBdRIB4Uq/0h+avyZMLmkT27aIQeL1/Ip8aL7Iai5y0QN7G2R+y86g0zCQPUZq3o1uIKDAe8BlUVE7mtw7wuyIGJrm9Od\
3879 REjSZpG/LrF2vkRofg3sjvyhU5mccAgCUyBfeM3njXhwVHDeZDz6xNM3qNwYvXGycfIMsOiSsz9I6IuUz9EsIGeD7lx5QnTydUKlwKZeBMcs/DQIdP62MdMTSvYR9tfij+9oMte45OyT5r8zhGvRmU27LPBatgbX\
3880 km+u5YQyLMdsE6iEbTeB7cnE4e4vTsPAt81CB6eR/hrqAn8hTf/EGAXr9yYqPTyrA0dVqFuK9zZdBwwpHdBq5W7k0L0u+aS7aVGfrCS+CAcuhYljZEICTO1jnEQeZCRHRv7w55/EC/gFo2TO9tyo/vL8C4T769hP\
3881 f31LkoW5KwAsOSL74gMVu+R4C8IsQBqTg45U6d79NhHH0+LpZzyITP8d7knxn4AElywxcrV8peS48lxEg55ofQIxT46UGsUx0QbLt+r8HiTDGwi1IdM7QYF4Dt3dsyJjaEunCmlmfydR5RIRZ0F05JwWOMOQju+j\
3882 oEPq16Xa6Cnn52HHzIdXpaXsPArW1J5N6fM17bbBWKaKEzZ9kZVpBciCNQxMpIzdlovEN6IAMz4WQAvYlwOsBYl68Q8fFky4KDSei3DoMzlMXoJ7BS0AFbKQGYpBBRW3Hnp0/F4Jzm3UR7Gv3rkam+yhTNkeJkVd\
3883 8G2nA9g/DWvmfUGowHZVuodwKlrHHVSXfiYKjhLWJJpDjtchsgpIwpDHG8y3pjbGTeT8BoKQOV5HjEDgoAOcX1PfB8rE16v81TECcJK5yt7Uxgd+iEzeVP7gBagL0iSQTwYqP71GYN03vPSEEhmEa7V8zbkigYeb\
3884 /3jF6o9n2sHayXL5to5ugosMeVFeNq/g67uzK2YJUpgCvIv6zGqf5XRzCTQY6pY11/yUvee5QeVnXvI640NxjWUz8HT1mkEU71ig9lyMFGGD1DHjz728dcohKHf+60rke81XYRoEDxaQKGetDZQXEG3RdZktbN+6\
3885 hH9PACQ3AagVs1Z8a0SnLy7wrE0kZVDdVAtvMcFU24IR8ZIDaE36aBCe2fSuxVzlIKybe5BZc7mzC990+tsmxoIBI4a1Uo7tJZhQCqvarFIgN2wXVoVQ1TG5Ra0iZ94Csdu+5Y4vqCXXl520lXN0QmlwNJlAkRTy\
3886 c3K0mK2P9tCVcrzAmnh2TrUfi6WN1UAiG5NJ4a2doUwXzKOadZde4T02PJbkkFvGXJt13qn+HKQ42o8sH8q2IEXHbKssR8xuyXrFrGuzVfmjdazv1F/OF2E1G573hqv5QN5yvd4YDEoN57WQXpQSwzK63YG2h5VX\
3887 OXLW/mZcjfenpv6WSk1nqztcWJCsJkF0sENZOHjButp6OnAETSNBGjYd+c3TuD9vBorY6fftgRieRf8CZ9HZ73gWnU2yc7xD9g4LBz8OFPNSX/9HgyCZBjE7ZuRLof9uVApDS66UKX/NRaXj0DiwsDjmi4N4LxfP\
3888 PJYFufca60sKS6rpZKsls8OHWJgN517MhMro3NBqkR6BsTGMwsXxzRuXnXCLHFAgsuKaJpYCDJ01KRYxtkHk12ZTTjmG7NJswebdhPkS6a/Fq2rwVbKEUq4RF1ie5NMR6AsuClwvpgcApMo8uHEMljMbeaoAIPBU\
3889 JuYrNiLvyl/hMVy7wYRKtzUfcTR5jKdCxeynnpqi6KCMaCYJnSxA7oGwrNH+WgBMU6UTPpcClWw4TlEFgZGnzd69Ce9kyLneSz7cY8SWNd4naEZyeRP5aOUpSGO+i4Q/wsBJdHJMp0/F7OvgVsKMcKBzyVfDtVA9\
3890 G1L/Vd+rT+KALVDaWXiNqXWVXCjr0cN3KVtDntKPGMMXlXI5G20hPZfdjGQE4Pps7G9zmLZu1l5bgBGfqJSKX2vOBTUi7+2Il5X+xQ0utftI5sXbQZEQbhAmZ8G+VJh1yzUeYg17f8WHo8Fc7RyVXPaWpaWdoZFn\
3891 pSurnacj/P8Fv/25Kpbwvwy0yqa5mqVp4r7UV6vlfduYzXTqGqtiVfT+O0JT7e/wlw6hNI6VSj7/D3TrM/g=\
3893 ESP32S3BETA2ROM
.STUB_CODE
= eval(zlib
.decompress(base64
.b64decode(b
"""
3894 eNqNWntz2zYS/yoy6/iV9IYgKRL05aaS68p2cm3s1FWcnmZaECTb3uQ8tqqcFTf57od9ESClpvcHbRIEF4t9/PYB/bG/atar/eNRtb9Yx9pdMVw/L9bKBg90ww8me7pY2+orN8cP51P4t7NYt8ZdrZsQj2AESCbu\
3895 XVv2hg/cn2zkbsvMXW6pJnEjubvG4Wrw4Zg+1Mr9z3tEHCtA3lHQmrg3MBavHLk42E4VtcCFGy3cVKCRAR1gVvUIljRN1W604+EaX/18He7T8Qxf1gN2HBtubQ138e78nN7iTPP/zOyvC9ezUaeA0YYqYIfCTgNS\
3896 srKriujFloTgV+UNIktVINdywF6Z/Eo3fgQlPP+wuQ9H8aMbTWArUQw6BY1s7gWuCfHbCLNunlNHaTwrTR1IzQ7ZKgcb6nO1fU2+lL/XcfB1zLYMBOTCidloYNjITRLx/vKvwVhhJ9rvpDH01oxFwPqE9ACz4L/K\
3897 rsT+CrbfSkfAU0r+ZG16ReJEolYMPJq4uUo9ceNpoLmY72FbSCEY7Os9dW/qpPfmte1p+QZmzd8T25MUxssTHb34+iLqC7eMA8GBQmB5a74Siw5EnYXPk4ncnQNx/gYggKmJOVdK5DpihwaJVrK8SHrch4UyuO+Q\
3898 oGRF69Caq+QwcGOWZ8n23JtZAh5ov224QH3KadeWvAse6z6yyQ1/4bgsqxCwkouhYwULoAMYz40sJlLF+wL8YMaTM7/zhoHSwD3bJK4fOoxF3KmCT5EeGCbQBHCI449EAN4oR6BRM/go9KbQsm5DuZaLVUemP37b\
3899 /2pFTNcBo5pcZNUTDgty6NqNhIyMIcX9qVCPN9llatkbUzDoG3C6H7+/XCymhP5E4wkRQRHoUye2nPWA3rZL20c/Tui/CCxELPBflcFOUwC+KhmxRbKfhWFI2+OI7NJmh9cH8OFxdAj/DjIQmHO2Hm7e0Q5bgz7W\
3900 h/8Ju2tNIlh3d7lhO3MM1wilAbwr9KwRvE6FUTNk9FvQFCJVQhKqRDWKjNUk3htgXAnAsA02KvDGxNtkm2yNgQbvRhvWUfGSpgYlsrm3m2I18S5D38BEEMgFzGNBFiCjBS8SWp52dg4TYF92KgEwCaM3jqhDjfYM\
3901 WYuJjtL4+ZTjbHJ4U5534eBLkKIGKRpR+njI4ogjkJiw+4AZAkDBfSfsnyDyhkQP7+uKtVdtkYfMsWztaZ82fis0NdMpPkOn5jnZ5pzNgEs7OZZkLvHv0Gz4WVUR41XFgRC4af8kbfBZ5k34AOz9F/Y3gaDJ3p7B\
3902 Aw9PHvBfvrNDq9eKjXWr3aO0Opi78pGkAkWoy6/dErbm8C66CQJOSKm1R34yfb+FhXT44YuIgu7cUm6JSM4YVQVfAygbwy7RbFEdjJdBAlHJN0+8fZJh5P3MKI7RWu2fq9YbhuV9WPtXhvEuVNuv4cNd+LAKH9bh\
3903 w/k5qxYAGpPAbHJ9zq6zYzzChcmsMu0F7VAhglVegOiw2bPF7Vtg+aTlKVu1eeWrBNxtLdR/gNA0fsNIhRZfsIRqWhfnb3FRn+feB4pCJh+vkKXZk2AmKmzyO0lcMRpLxUPWdbcW6ywgYZIwZLeGIYD0exrsqoTx\
3904 a4xsj/cMGjYoKzCvcJqqkDau14hhPvEFGi0vHEGdmDMblR6y8Rg9nhYEozVvs0bJX662b1MXEI0LkqvktzGp8hZ2PHvHZFQoTnhz4EUpLz0jc064GkqKDHOKYJW/IzJVBfH0I7t2wbknbD//ZrH6EQQDX7wUbPuB\
3905 I0zqPde0vEZBuYPV7TfAwus9WAIkAWVv8oZEAlyAD5doI06SFUgSDBe9njdTbguGY19BIQW9DQU4Tgv+jEWZzzBoKVLhX2G9S91fnU8vgFtqB3yEbwtwUsxY4S72PQQ94QSmV2NtKdDAPnUP/Se9CnLzSywi4ix4\
3906 cKLaDyhkQfNCbEdYEO79RpFCFVY4rf4WsUYT5Lw7ZjRCD1H4AMlazsOQKPLwustSiUN+OKe3DgrLMb8FvbeUDSwWFJ9wHNyDx59dYzy77NIG0Nu/CAUdp4rr1Np2fn0bGQQ4TnMEUDYAG74qOFmUjNyHhpMK/r6M\
3907 ioTMH42sA4+X5C1WjZ4IFbKpumWKaGjNjtxMeVPt0RfDxgu4oG25iwHeCz6DRoTXjxc+7NYbJjoVsH1Ntg/Mh90mZ92Xkc8zDznVVx+3A3Sdb5GSzTa6WAlFQMiSwctsNoFiGeIoom9X9gN2ZpSpxuyNutvuIH0I\
3908 XLBW3ByywSBCVUniAZMyKgRDJGu2cF+ZEPGP0h2qetoGQmPytLctSKjz5cZuU9lONwrxKj2Zwp5POA4qnLSPg2p5tVi9vdrjMh9KSls8EAUII2hmyKB8nS75BjtKp0Dj7nTU4s151K2LvnhxNesnMMrunrgFG9/q\
3909 AHYh9pOREoyCeVq0888v6qJhifnV3R2kp2cE4CrpJ0FILfWBA8YhLTPh+FhUPRPPAIaXPYmta6fTsqALOckJ5uP4ofyu/UXSDOo8oKXkD6OWJ9v8XgbPQKYtYmAye8PSyffgpj3DQUcbG63tG7+SQZycRZ0tYaoV\
3910 8mNzvnf84BIPTMxgWT2jKBFD1dXbQulJVj2SM6pLiD/oQYgWBwvH+QmtetSSDoibVzJ9sUKGGCkgA4QoCP2hvji5+od9qM5iaN3+cm86czoLh//TVQrowNK/wTopGcoqEUGpcFpMU1SxGwwqGVTEXJz1Q1w3MR3u\
3911 6HlQmMOEbDjhnOMUymNJs9AKTeq1oop5fQDIsdxWYK8ItlCVTcjYHjX4kFukQmosMeyfgCElS/ib3oH7j3xTq8rmZAqIYGNKSpybnVLsx36U4WRPB8EaLijPtdqAzfkxFE1LjkFQWZiM23MWPEGLewghaqjNqaho\
3912 m5mXuuGrxf7iTxsrHVHhqtWFNF8fpBw651yZ1n7QlA3YoA4f7GO+dR/l5j7mlP86Rg0jB+GP6ACV/SlU9uz7ga4wxwC3z68DErHiV0TiQTqkEfFs8CbhBJkzg65O3kYjhrhBzVUMl2gI2SUoeiRsJ2ekf5p/y2tq\
3913 CN3QDRdrQtPIpKP7nuzQ5r8Flgv4WGXPziHJUUcszdDYaS0ja6EBrxO/2t2KQAhQqlHcZWnbKXWPwEAh3WrU2/oE/Ovph12iC6mbTj+hLHLI2biffMtWzQDkqK1ChQH05C/gz/otkI5OOK2A1LbkjnIYXsr40f1J\
3914 JbqLp0MvTA97LIbKDbgw3dfUqMZxPD+Jz464oyntmLGEQO4zw1ylJnAzOvERR7YTU3BkG866KQXHTex0xKejbjOcfELoLbEfj0hyKqd7CbU6OrhOxA178rpgENWZDOs5R0Hs4yG5NVh1/o8wGaDOZMc7WxVCbSYw\
3915 zTGngSSh1eB4YBgWsuYKm2Z4PKMYjQbg6EjfdqY56yHq3qmsINoBQlUdnFs0bCr9JlTQtRyactxzs6eYB0XrpEuKPngwjumsE+ug9lTitN7mIBh9dwOwIP5lqdkOKwu7AegPr9eRNGKmktfj2p94d7k/QMbDhtjn\
3916 8qCBGs+9OsunUjceTzh4pRAn38PNHS2jNiSRw6GfCLLGEl5elZTcxfrs+T8nNKY6u0F8BT6ly73hRo9khaX+7eUDrn7L7LWP0P64owLKxmcF8QTnAZhxJJSUg+M1fFCJXSDT61a4/bcE2aqYcqLerNn/8HVn4m+D\
3917 0Gqm5Attc0fZpE7fdhsh0dzJ2XdiFktXjGkpkZKdxZJ00B2laevzUmoSgD8V7LCUkwq2t5iuT87Qa9iU/kCzqn1aiA4S72U+68PebsO20HYeuf/ApQBOew/jQBnhCrcfvLeY3kBe2bLpdbhQJ8jVK3nM8PH3GXfr\
3918 mn7+RI4M0GRR3BFFHwClrkHVDKolKbDgBMBwj6hf98Fnru49hdweCj6FGIfl32h3RJALUIyLi4qgm2S5iJW20EbfPeUTuI7jwS8a8sCleIs1xmlgRY6ofQgH4EFNK6lAKv9xJZEgPQlrIOIUI0FVjWga1tfMo+Vz\
3919 y2Z87xsGNarp80UVd682sO8eDp7rEBPwmCI+xdO8UzrfA1tV3ETDn47IgY0OOtkSyRd8zKOpH+O43uf+PTeFY2q27VNqZThUmPH1lpM++hjEYTMRB4sAz5S2qBLjPLfU8dTvDZz6FS/w1K84KCaw2fiiYArlkMLM\
3920 58i+VEw5SHZyfRDDe4BgTDwtyZlbgRw78z5YYpLf7Kw48urF6gO2g7G2PjQHewI5sGMstrA8PRbBkqQsHzLUeOx37c9Drdr5NzFt5FRQ0zSjfuM2KB+NWKnJLWUCeK+puUONntWmVC2G3ErvwXL3gXrZZC2eN8Nb\
3921 ScsrOmg0cMqruQMKMwFzwL0oHR/R8TU/grDGI08RejxgC1Dm4RGaiLahms40fAopv00IjvBEbJbFZsamb5kWxXaIPwnCaqQ+0ITRpuAksFV8wxlinR9K/zqhYwtoWBkrDayUnQktr7i4mQW/ybDPuUYT7GYjU1Bl\
3922 m2T6N/hWrFYfXs8Y0Bsh/jScUB4CcZ3KhINozqBsulznagvOqb9zfMAyapgGqe82vOGPboWEm1MAIn6Ri78C0+nmBLzvOhBsbf1Wd/eLLzHKLjfnhhj9IoPSNgsmLafniEmFj/wx/uok/Ug6w7cNl2YKc+i9iAxI\
3923 D+rFjfPb+PALWRe9NRLCLWR5tGbUnQPv+19OEWs4+0s+Wdl2RlzLL7pka3nv08iz0pfV/rMR/qDwp99XZgk/K1RxUaRFGReJe9PcrpYfZFDHY5W7wdqszOD3h9Z8tc9vQkJxUpTjMvn0P3ZbiIQ=\
3925 ESP32C3ROM
.STUB_CODE
= eval(zlib
.decompress(base64
.b64decode(b
"""
3926 eNrFWmt727YV/iuOndhttvUBxCu8xJFaybLsOE37dPXch1lDgqSXrtMWR2mcrf7vw3suIiVbSr7tg2wJAIFzfc8F/O/BorlZHBzuVAfFjbHFjQ2fKgvf8TGvT4sbn4dvUXFTuuImp9H9MFi+CH/S78OfOAyl4X+z\
3927 G/54eTqmp4ubtr7MaI9n4Y95HvaPFmEU021xXdw0JvwaDKvxXjggf8g0VINZcVMPxl/PdsOzJinDwYPwCWvzfBj+RMVBMccJ2O992CGh/WiVy27DaDigCTRbF760YcYH4qs2Kw6Irt/Pwro6rK/42bbNsg0TevSI\
3928 RUOchk9dZ8Qp7wfiU5HZYCm88Amic+HjI/z/5lZoyS/A4xDET7pzTPifuxGL4P5D3bNbOZpPGPZo0JO639Z/AwXw7uG8la1V26S0bAwJBRW5iLcOSg1qcv5MdUsqJ0W+YFqq8LTPzrMH4V8gvLYZ2GHN89M2PwnL\
3929 6mkwiTqsaMQsrB9jmGUMm2qi0Yz4WAhdRhaBGOjPizTLhGV+02YiMdMx20B6bVFABHs7mbDXl4D1oCciIz6AZD3bdjjrKBzk9h6K+ZE9igGKMa7YoEmW9BqRoxevsVFP+R4SHIW/tmL6MJpbFkWeTDGNRx/A9GFC\
3930 ho0Ay1p3cYRF/VMhSThgIwfk7hgjgb1aRtr6gvkFLRAftEJb2o62ysDxQDFtFrGNgb62waZT9ZaeOYRHwEcqrmbE2Gy3RDlubXc6TKem04gwOmrA1tD6u1uAsH/ywVU2IYsUB8CKPJmQxMkXvnvmp8IZbDGb9uwX\
3931 XKnJ5FHPMwXHaqzGjx50fI0lI15vhXKSncFMiplB0JAbyNZ5CqDZE7tU9vubO3vVkUPHx2C5EfUNhEgCRtXM0tDxbFXiCIHeHgsEr6nwu5lz+i24QUfbINYGP4ygFTMidlfrD7DIRz3gmWCJrDoj2ofq1tFEtqz7\
3932 WzZCcC32+Cm8IYjB16mCTh9v+tgCMwM2iCmWMNuYwcSTHr4cywy81u3Du7HDJVs2A8yJ/0vYpsMb/wq8QjUIG08JaE+G+yLFhp3RiXSBG8AU8mSzE77UAgSJMjUkfyhobTFk+YTHC6KxGAsUxRgcjjmMfgp4bJ28\
3933 Z//QSL0SeL2NBGN98+xXDY/YY8zU3k89jzVeMMkmDAbVYMqstGTAO0esh9b+uR9hpmqQw3vOqxmTGWnh4IPJZiLIZIA7YKIUqkgiAoQ9UYw0T1HrN4kaTRqsL2866+v5xYLJg5H6PooRRl7dsseTICMmDzMwibw+\
3934 ZGuDPeE/gh+APMfiao8nGAVHGdOGE1gYLxkY7wvAExF1uxboV8MInNdIBBnororjm8QJR6ijbrWn1R0RVqCFn7uSTSCewXqoINzOuxCx9UjbHcnQD0FU2Uh9P4abD5TVx+wClTh3RWrxTJ2L+ZhA8y6ygcF4XX7I\
3935 noysolgQTzJ2xSp7/xboYW/fYeoNTk72RbOBhbphRmskJwCuUijKbmElUHMXmBYsjFwAWZEIhLflERPKSLPLlqqAtNnU99c3N8kv3QmEDOU0sFs5TpGDffZCLX1AqBNJMykbSHRC4urjvdOg0mR3G8CBiD1Z4WG1\
3936 efJM7NckvhNYVQ4fQ1XluJgH8GrTy/YnCPin2dJ1AajOv8MiVdybUwZZKCJPXnyKEDYyGEJTrzy5lYXXHAERYZxT8H04+tjL2xJQkzZ9hCVkFSNVs9ZMh7H3K/bYjYEBth5wj2h7kAHeW8781zYDuN3rkyUGzNu3\
3937 t+9+BNj8BMT7Gyy1EhijuLsLtN2Hy59CPgiaLYqzGjxHv3Ci1Yjll2IqqrYVYgZfcWpeQV1VyiAH3PGDTWwOmfQ8uQpLG/uBd8yTWm0015Jwuxt9wgYpvqS3/9m8J5m4P2TUJrv2dxeHg6/5EcJ2TbPs7Ehqv2Q9\
3938 c8vWXJMyFCvZZQ2V4pzWhOTVVOFb1rLnGgi4zDV92JeE3mUv2GzLT5sth0IKKGAHVbdzfvGGDaVSnHYjz8lMnvVn/jBihedEX/RBymsaWaHhx+00MLq/Yc/7XPkgLHoWe5sjXs4QSc/ZonOnM+22o1HgDm4lMYMj\
3939 JDH/aEp+rLGp/7azXoSqZvBUCvfNhNIgaf17TuTnnMYToQlAWeuYZfqLloKmv9ZOeRC7IWmhhsb/F6Nf44kOoy+Tdb/eImNatArkLx//AHv7oZhfgu7ZL8CV8vT0DJNnj59j8nkxPwfKvzrvJalVdjGaXb7tJI/8\
3940 EUyGcHEkriCQXSICx1I6DBica8NrvERoLxGa5kqmHSYN0G0GnDejrAE6wSi8mfOCjYhcVpo55s+yD2vlk2ZdmgFhrIIZN7IFClhnJ39HdkmpYL+QWy3CHlwdkXHtSA6txVuSD7XHhm/80JRzLGOPtdxV3S37ZzaZ\
3941 0F4SOLelYW3ZtfCKYnrXFCraVTknxjJKMwumfhsSwP+2YPRcxMs9Kf+z8FOyDkW482X/TnoPIBDuRaKDGVoaTPgLd04mW0y4pALoKjsTttAFsWsdGWTRedKOWlVE18ChXCbQuUCMpU5U/Y/suap1i6RLqQ5dpeGH\
3942 bXbZfciE75z5Q0Cm8bgbD3UXF9BzKZ8JGS1rCoshFMuJ7gJLqUaT+TJaXY9PnX5JzaJU6qD0nH72ivL1/GNbukWVj518wQJ0VKgQUXHHps8eilXadhcSf8Wl39Kv0HmwEqQaGficSua1NLJWyphtsdL1SiRKnZtP\
3943 cGc/Vxo7vLikik37ddpugVCy99LZ7EvH9KVTSneldlIZayBBIdpIAHLU/PTfHEGRlwIxTvWuesZBVbtuHwm1BKk3+9hfAZxZAtZ1E2Y5kRfXNCxtrRBLS5lJiwXNUOW+S+lRF7Koa9JqAy2W3nuS6ojjkRJR7XMN\
3944 jQyplFDbO2eVvadkx1iWPfG/Ale/IiF6DjENXNY6+kkt5xfFtQpYYA45cK6ZxB3rtYK8HK9EXwn3sNBoRRZNeGSfSJKJeGyP5cA6gwu75FjOlMYaENtbalhOPLdDKCB40XWdn+w9VGBHndUIUKKjhWS9TLpO746X\
3945 W5NUgnqtp0kjGBN59OiUuhEAQek7mmTHaxa8qtHXTEsp4axkW6FWCeLl8gAvB0DSJHNqCGfMUe2RE+TPEdJPwPsJgHCMK5vxFtzOqbxyAHpu+lC19Qi2fU5kONU/UJWYjkfHvouzwWh/lQlkH3ekQf1UEGsqIbZc\
3946 M+dlDWbZozxLu5F+ZjybdupsMjXLqUYK2ERd9dDeSRODk7mdPfZAHK8t6DJGa88+EsSi5uoOtdhzMRlrPEP8Us3SgTXciodYaoFRnbLLbo2TXiyaeqvM0xbJ5LGa+Eya/dq2TGV7UvWRDg6XG2eycbkiAhJ2S9Y8\
3947 6spY4XLpm73Mqif13E47FghZQLWv5YlGEfSHvruONXLP+sGG52qxtMGdGbmwadZAuJF6BKJueq1mKxSWtXSmkvG5dJ7FCny2nhD8HsVqyN9JIyHiHXLh2Rvq/V6xP6tEHGVMdoT9HxwC5usRulauRl8SxNW3WkjU\
3948 Qx5qcslbKnJc6Uluoq0xH2mbOVcajTh7FX14JNdeODUbvemO8XMp1Mztx270IwBr62Gv0QHArZs75cNa7QFufmbnN3mGpf9wJJdqrUBnI1YqODqWSFHLbaDpwObjocboO6uTbrXzJ17cOdWs7UTAqkYnKNdri+XT\
3949 4kJNs3y6pqfnolTdQPr6lPagKnGGS+GFXr7E0mGR68Aqk7uadpkyHPMANRkSqfGtNLZrjv3ku8GVudXAcWgqI0RuI+SWwtUyf75HYddP+6KOuhjVxMsYNe7usvlsO2bqUPPT2bkQQvfzFKYJB5u0S/lc9CHrSnVE\
3950 FPBGHhl9oc9IGRSQQayupYpJpaRN4iZXVEFnokTgrDmEPpSOvGEMvSNga15oysawTmCBsN2KzZWrsnSdNPrMdelNrumNlcsyOwlUzCWg0/8uxLHdLpXIFr/DG+DOhHtHvQilu7dy97Ay6UzvSTvrMiRo0SvuxxON\
3951 YjJXNdsSVatG3E+EephJeX3NY/zywuyeCBis41ryY4TxyI93kK75v/L7AVqd/RsMyC1K43rmIQl25bvOCHNbMkX8uETOSqzB63gXteT1A1ypEpfx3dwPcSR+xZFvM7y/6l6FYSZHlJm8ozcHdtkDSP1USVYr4d4Q\
3952 GFqpo1lUCwqQP3YXkSpChl3/kmx2zu0HSmXgpO17zkhp70T3ztOuc6Bqu5+T4SXlLatXlSL/1vUJmUnMKuW6G0JfXaGC4Bh6MKJC9sttp+Nz8acgnVBjNL0CIXnbE64qyIw3YtZs5UUlINRZdzvefzHDkmAupGlr\
3953 B1KpwYz1PRQ1a309hCnh4BrJRWbWNdHuEelpHwuONvNuzLFUDv7+TJk1/bPcO1teyIPfsiZyqy9J/KbXn2o1KRv5lqYUu2LeHnF7bWlvFI/w6lTYcM5tOG6Uh0xMu/hxd4JJTuQWvuUs5vrkazTlDqUjJ+bqYa7p\
3954 7nRwIi90sAkFEy2kmyCJn7ZMrH4igV8krptkWRqAzuCCBHAgIRtW4zVcIEBTulQLz9RkHVwgQlAgpXJDLwsSKXhN78UEoYsuBmq8MqAQTi9pELo4BuYmlVY2M/8vWKR0CZy6Y8IBUuLzQmJjJJcsGUtHz2bUX/FL\
3955 PK8RuZHXo/Qxszm+g6cnd71tc6qYb/S6J3L1HkvSQ2hnOBKVZisVw8PP9JHcaNETS1hDvyN9uY+WdIpCAG2RNp21aEqnp8dw/PRsHwVo+pz6Xbhme9X0X9qiz8Efd+iFx5/fLcprvPZoTZbF1uaxCTPNfHH9cTkY\
3956 RXEaButyUer7kbCr4FMHMtzfxdg0dia+/R/imbus\
3963 except FatalError
as e
:
3964 print('\nA fatal error occurred: %s' % e
)
3968 if __name__
== '__main__':