Skip to content

Commit fe72928

Browse files
committed
formatting, strict write_flash opts order, atexit & traceback
replace temporaries tracking write_flash / erase_region with an append to a generic write_flash_args list. first are actual files, erased ones at the end using atexit for cleanup
1 parent b93715e commit fe72928

File tree

1 file changed

+98
-49
lines changed

1 file changed

+98
-49
lines changed

tools/upload.py

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,74 +7,123 @@
77
# i.e. upload.py tools/pyserial tools/esptool write_flash file 0x0
88

99
import os
10+
import atexit
11+
import pathlib
1012
import sys
1113
import tempfile
14+
import traceback
1215

13-
sys.argv.pop(0) # Remove executable name
14-
toolspath = os.path.dirname(os.path.realpath(__file__))
16+
from typing import List
17+
18+
# Add neighbouring pyserial & esptool to search path
19+
MODULES = [
20+
"pyserial",
21+
"esptool",
22+
]
23+
24+
PWD = pathlib.Path(__file__).resolve().parent
25+
for m in MODULES:
26+
sys.path.insert(0, (PWD / m).as_posix())
27+
28+
# If this fails, we can't continue and will bomb below
1529
try:
16-
sys.path.insert(0, os.path.join(toolspath, "pyserial")) # Add pyserial dir to search path
17-
sys.path.insert(0, os.path.join(toolspath, "esptool")) # Add esptool dir to search path
18-
import esptool # If this fails, we can't continue and will bomb below
19-
except ImportError:
20-
sys.stderr.write("pyserial or esptool directories not found next to this upload.py tool.\n")
30+
import esptool
31+
except (ImportError, ModuleNotFoundError) as e:
32+
sys.stderr.write(
33+
"\n*** pyserial or esptool directories not found next to upload.py tool (this script) ***\n"
34+
)
35+
traceback.print_exc(file=sys.stderr)
36+
sys.stderr.flush()
37+
2138
sys.exit(1)
2239

23-
cmdline = []
24-
write_option = ''
25-
write_addr = '0x0'
26-
erase_addr = ''
27-
erase_len = ''
2840

29-
while sys.argv:
30-
thisarg = sys.argv.pop(0)
41+
def make_erase_pair(addr: str, dest_size: int, block_size=2**16):
42+
dest, path = tempfile.mkstemp()
43+
44+
buffer = b"\xff" * block_size
45+
while dest_size:
46+
unaligned = dest_size % block_size
47+
48+
src_size = block_size
49+
if unaligned:
50+
src = buffer[unaligned:]
51+
src_size = unaligned
52+
else:
53+
src = buffer
54+
55+
os.write(dest, src)
56+
dest_size -= src_size
57+
58+
os.close(dest)
59+
60+
def maybe_remove(path):
61+
try:
62+
os.remove(path)
63+
except:
64+
pass
65+
66+
atexit.register(maybe_remove, path)
67+
return [addr, path]
3168

32-
# We silently replace the 921kbaud setting with 460k to enable backward
69+
70+
argv = sys.argv[1:] # Remove executable name
71+
72+
cmdline = [] # type: List[str]
73+
write_options = ["--flash_size", "detect"] # type: List[str]
74+
erase_options = []
75+
76+
thisarg = ""
77+
lastarg = ""
78+
while argv:
79+
lastarg = thisarg
80+
thisarg = argv.pop(0)
81+
82+
# We silently replace the high-speed setting with 460k to enable backward
3383
# compatibility with the old esptool-ck.exe. Esptool.py doesn't seem
34-
# work reliably at 921k, but is still significantly faster at 460kbaud.
35-
if thisarg == "921600":
84+
# work reliably, but 460kbaud is still plenty fast.
85+
if lastarg == "--baud" and thisarg in ("921600", "3000000"):
3686
thisarg = "460800"
3787

3888
# 'erase_flash' command is translated to the write_flash --erase-all option
3989
# https://github.com/esp8266/Arduino/issues/6755#issuecomment-553208688
4090
if thisarg == "erase_flash":
41-
write_option = '--erase-all'
42-
# 'erase_region' is using a temporary file filled with 0xff
43-
elif thisarg == 'erase_region':
44-
erase_addr = sys.argv.pop(0)
45-
erase_len = sys.argv.pop(0)
46-
# 'write_flash' and everything else is used as-is
47-
elif thisarg == 'write_flash':
48-
write_addr = sys.argv.pop(0)
49-
binary = sys.argv.pop(0)
50-
elif thisarg:
51-
cmdline = cmdline + [thisarg]
91+
write_options.append("--erase-all")
5292

53-
cmdline = cmdline + ['write_flash']
54-
if write_option:
55-
cmdline = cmdline + [write_option]
56-
cmdline = cmdline + ['--flash_size', 'detect']
57-
cmdline = cmdline + [write_addr, binary]
93+
# instead of providing esptool with separate targets,
94+
# everything below becomes 'write_flash' [<addr> <path>] pairs
95+
96+
# 'erase_region' becomes a temporary file filled with 0xff
97+
# this pair is appended *after* 'write_flash' pairs
98+
elif thisarg == "erase_region":
99+
addr = argv.pop(0)
100+
size = int(argv.pop(0), 0)
101+
erase_options.extend(make_erase_pair(addr, size))
102+
103+
# 'write_flash' pair taken in order it was specified
104+
elif thisarg == "write_flash":
105+
addr = argv.pop(0)
106+
path = argv.pop(0)
107+
write_options.extend([addr, path])
108+
109+
# everything else is used as-is
110+
elif thisarg:
111+
cmdline.append(thisarg)
58112

59-
erase_file = ''
60-
if erase_addr:
61-
erase_fd, erase_file = tempfile.mkstemp()
62-
os.write(erase_fd, b"\xff" * int(erase_len, 0))
63-
os.close(erase_fd)
64-
cmdline = cmdline + [erase_addr, erase_file]
65113

66-
exit_code = 0
114+
cmdline.append("write_flash")
115+
for opts in (write_options, erase_options):
116+
if opts:
117+
cmdline.extend(opts)
67118

68119
try:
69120
esptool.main(cmdline)
70-
except Exception as e:
71-
sys.stderr.write(f"\nA fatal upload.py error occurred: {repr(e)}\n")
72-
exit_code = 2
121+
except:
122+
etype, evalue, _ = sys.exc_info()
123+
estring = "\n".join(traceback.format_exception_only(etype, value=evalue))
73124

74-
if erase_file:
75-
try:
76-
os.remove(erase_file)
77-
except:
78-
pass
125+
sys.stderr.write(f"\n*** A fatal upload.py error occurred ***\n")
126+
sys.stderr.write(estring)
127+
sys.stderr.flush()
79128

80-
sys.exit(exit_code)
129+
sys.exit(2)

0 commit comments

Comments
 (0)