esptool.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #!/usr/bin/env python
  2. #
  3. # ESP8266 ROM Bootloader Utility
  4. # https://github.com/themadinventor/esptool
  5. #
  6. # Copyright (C) 2014 Fredrik Ahlberg
  7. #
  8. # This program is free software; you can redistribute it and/or modify it under
  9. # the terms of the GNU General Public License as published by the Free Software
  10. # Foundation; either version 2 of the License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful, but WITHOUT
  13. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  14. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License along with
  17. # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
  18. # Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. import sys
  20. import struct
  21. import serial
  22. import math
  23. import time
  24. import argparse
  25. import os
  26. import subprocess
  27. class ESPROM:
  28. # These are the currently known commands supported by the ROM
  29. ESP_FLASH_BEGIN = 0x02
  30. ESP_FLASH_DATA = 0x03
  31. ESP_FLASH_END = 0x04
  32. ESP_MEM_BEGIN = 0x05
  33. ESP_MEM_END = 0x06
  34. ESP_MEM_DATA = 0x07
  35. ESP_SYNC = 0x08
  36. ESP_WRITE_REG = 0x09
  37. ESP_READ_REG = 0x0a
  38. # Maximum block sized for RAM and Flash writes, respectively.
  39. ESP_RAM_BLOCK = 0x1800
  40. ESP_FLASH_BLOCK = 0x400
  41. # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
  42. ESP_ROM_BAUD = 115200
  43. # First byte of the application image
  44. ESP_IMAGE_MAGIC = 0xe9
  45. # Initial state for the checksum routine
  46. ESP_CHECKSUM_MAGIC = 0xef
  47. # OTP ROM addresses
  48. ESP_OTP_MAC0 = 0x3ff00050
  49. ESP_OTP_MAC1 = 0x3ff00054
  50. # Sflash stub: an assembly routine to read from spi flash and send to host
  51. SFLASH_STUB = "\x80\x3c\x00\x40\x1c\x4b\x00\x40\x21\x11\x00\x40\x00\x80" \
  52. "\xfe\x3f\xc1\xfb\xff\xd1\xf8\xff\x2d\x0d\x31\xfd\xff\x41\xf7\xff\x4a" \
  53. "\xdd\x51\xf9\xff\xc0\x05\x00\x21\xf9\xff\x31\xf3\xff\x41\xf5\xff\xc0" \
  54. "\x04\x00\x0b\xcc\x56\xec\xfd\x06\xff\xff\x00\x00"
  55. def __init__(self, port = 0, baud = ESP_ROM_BAUD):
  56. self._port = serial.Serial(port, baud)
  57. """ Read bytes from the serial port while performing SLIP unescaping """
  58. def read(self, length = 1):
  59. b = ''
  60. while len(b) < length:
  61. c = self._port.read(1)
  62. if c == '\xdb':
  63. c = self._port.read(1)
  64. if c == '\xdc':
  65. b = b + '\xc0'
  66. elif c == '\xdd':
  67. b = b + '\xdb'
  68. else:
  69. raise Exception('Invalid SLIP escape')
  70. else:
  71. b = b + c
  72. return b
  73. """ Write bytes to the serial port while performing SLIP escaping """
  74. def write(self, packet):
  75. buf = '\xc0'+(packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc'))+'\xc0'
  76. self._port.write(buf)
  77. """ Calculate checksum of a blob, as it is defined by the ROM """
  78. @staticmethod
  79. def checksum(data, state = ESP_CHECKSUM_MAGIC):
  80. for b in data:
  81. state ^= ord(b)
  82. return state
  83. """ Send a request and read the response """
  84. def command(self, op = None, data = None, chk = 0):
  85. if op:
  86. # Construct and send request
  87. pkt = struct.pack('<BBHI', 0x00, op, len(data), chk) + data
  88. self.write(pkt)
  89. # Read header of response and parse
  90. if self._port.read(1) != '\xc0':
  91. raise Exception('Invalid head of packet')
  92. hdr = self.read(8)
  93. (resp, op_ret, len_ret, val) = struct.unpack('<BBHI', hdr)
  94. if resp != 0x01 or (op and op_ret != op):
  95. raise Exception('Invalid response')
  96. # The variable-length body
  97. body = self.read(len_ret)
  98. # Terminating byte
  99. if self._port.read(1) != chr(0xc0):
  100. raise Exception('Invalid end of packet')
  101. return val, body
  102. """ Perform a connection test """
  103. def sync(self):
  104. self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20'+32*'\x55')
  105. for i in xrange(7):
  106. self.command()
  107. """ Try connecting repeatedly until successful, or giving up """
  108. def connect(self):
  109. print 'Connecting...'
  110. for _ in xrange(4):
  111. # issue reset-to-bootloader:
  112. # RTS = either CH_PD or nRESET (both active low = chip in reset)
  113. # DTR = GPIO0 (active low = boot to flasher)
  114. self._port.setDTR(False)
  115. self._port.setRTS(True)
  116. time.sleep(0.05)
  117. self._port.setDTR(True)
  118. self._port.setRTS(False)
  119. time.sleep(0.05)
  120. self._port.setDTR(False)
  121. self._port.timeout = 0.3 # worst-case latency timer should be 255ms (probably <20ms)
  122. for _ in xrange(4):
  123. try:
  124. self._port.flushInput()
  125. self._port.flushOutput()
  126. self.sync()
  127. self._port.timeout = 5
  128. return
  129. except:
  130. time.sleep(0.05)
  131. # this is a workaround for the CH340 serial driver on current versions of Linux,
  132. # which seems to sometimes set the serial port up with wrong parameters
  133. self._port.close()
  134. self._port.open()
  135. raise Exception('Failed to connect')
  136. """ Read memory address in target """
  137. def read_reg(self, addr):
  138. res = self.command(ESPROM.ESP_READ_REG, struct.pack('<I', addr))
  139. if res[1] != "\0\0":
  140. raise Exception('Failed to read target memory')
  141. return res[0]
  142. """ Write to memory address in target """
  143. def write_reg(self, addr, value, mask, delay_us = 0):
  144. if self.command(ESPROM.ESP_WRITE_REG,
  145. struct.pack('<IIII', addr, value, mask, delay_us))[1] != "\0\0":
  146. raise Exception('Failed to write target memory')
  147. """ Start downloading an application image to RAM """
  148. def mem_begin(self, size, blocks, blocksize, offset):
  149. if self.command(ESPROM.ESP_MEM_BEGIN,
  150. struct.pack('<IIII', size, blocks, blocksize, offset))[1] != "\0\0":
  151. raise Exception('Failed to enter RAM download mode')
  152. """ Send a block of an image to RAM """
  153. def mem_block(self, data, seq):
  154. if self.command(ESPROM.ESP_MEM_DATA,
  155. struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
  156. raise Exception('Failed to write to target RAM')
  157. """ Leave download mode and run the application """
  158. def mem_finish(self, entrypoint = 0):
  159. if self.command(ESPROM.ESP_MEM_END,
  160. struct.pack('<II', int(entrypoint == 0), entrypoint))[1] != "\0\0":
  161. raise Exception('Failed to leave RAM download mode')
  162. """ Start downloading to Flash (performs an erase) """
  163. def flash_begin(self, size, offset):
  164. old_tmo = self._port.timeout
  165. num_blocks = (size + ESPROM.ESP_FLASH_BLOCK - 1) / ESPROM.ESP_FLASH_BLOCK
  166. self._port.timeout = 10
  167. if self.command(ESPROM.ESP_FLASH_BEGIN,
  168. struct.pack('<IIII', size, num_blocks, ESPROM.ESP_FLASH_BLOCK, offset))[1] != "\0\0":
  169. raise Exception('Failed to enter Flash download mode')
  170. self._port.timeout = old_tmo
  171. """ Write block to flash """
  172. def flash_block(self, data, seq):
  173. if self.command(ESPROM.ESP_FLASH_DATA,
  174. struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
  175. raise Exception('Failed to write to target Flash')
  176. """ Leave flash mode and run/reboot """
  177. def flash_finish(self, reboot = False):
  178. pkt = struct.pack('<I', int(not reboot))
  179. if self.command(ESPROM.ESP_FLASH_END, pkt)[1] != "\0\0":
  180. raise Exception('Failed to leave Flash mode')
  181. """ Run application code in flash """
  182. def run(self, reboot = False):
  183. # Fake flash begin immediately followed by flash end
  184. self.flash_begin(0, 0)
  185. self.flash_finish(reboot)
  186. """ Read MAC from OTP ROM """
  187. def read_mac(self):
  188. mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
  189. mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
  190. if ((mac1 >> 16) & 0xff) == 0:
  191. oui = (0x18, 0xfe, 0x34)
  192. elif ((mac1 >> 16) & 0xff) == 1:
  193. oui = (0xac, 0xd0, 0x74)
  194. else:
  195. raise Exception("Unknown OUI")
  196. return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
  197. """ Read SPI flash manufacturer and device id """
  198. def flash_id(self):
  199. self.flash_begin(0, 0)
  200. self.write_reg(0x60000240, 0x0, 0xffffffff)
  201. self.write_reg(0x60000200, 0x10000000, 0xffffffff)
  202. flash_id = esp.read_reg(0x60000240)
  203. self.flash_finish(False)
  204. return flash_id
  205. """ Read SPI flash """
  206. def flash_read(self, offset, size, count = 1):
  207. # Create a custom stub
  208. stub = struct.pack('<III', offset, size, count) + self.SFLASH_STUB
  209. # Trick ROM to initialize SFlash
  210. self.flash_begin(0, 0)
  211. # Download stub
  212. self.mem_begin(len(stub), 1, len(stub), 0x40100000)
  213. self.mem_block(stub, 0)
  214. self.mem_finish(0x4010001c)
  215. # Fetch the data
  216. data = ''
  217. for _ in xrange(count):
  218. if self._port.read(1) != '\xc0':
  219. raise Exception('Invalid head of packet (sflash read)')
  220. data += self.read(size)
  221. if self._port.read(1) != chr(0xc0):
  222. raise Exception('Invalid end of packet (sflash read)')
  223. return data
  224. """ Abuse the loader protocol to force flash to be left in write mode """
  225. def flash_unlock_dio(self):
  226. # Enable flash write mode
  227. self.flash_begin(0, 0)
  228. # Reset the chip rather than call flash_finish(), which would have
  229. # write protected the chip again (why oh why does it do that?!)
  230. self.mem_begin(0,0,0,0x40100000)
  231. self.mem_finish(0x40000080)
  232. """ Perform a chip erase of SPI flash """
  233. def flash_erase(self):
  234. # Trick ROM to initialize SFlash
  235. self.flash_begin(0, 0)
  236. # This is hacky: we don't have a custom stub, instead we trick
  237. # the bootloader to jump to the SPIEraseChip() routine and then halt/crash
  238. # when it tries to boot an unconfigured system.
  239. self.mem_begin(0,0,0,0x40100000)
  240. self.mem_finish(0x40004984)
  241. # Yup - there's no good way to detect if we succeeded.
  242. # It it on the other hand unlikely to fail.
  243. class ESPFirmwareImage:
  244. def __init__(self, filename = None):
  245. self.segments = []
  246. self.entrypoint = 0
  247. self.flash_mode = 0
  248. self.flash_size_freq = 0
  249. if filename is not None:
  250. f = file(filename, 'rb')
  251. (magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))
  252. # some sanity check
  253. if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
  254. raise Exception('Invalid firmware image')
  255. for i in xrange(segments):
  256. (offset, size) = struct.unpack('<II', f.read(8))
  257. if offset > 0x40200000 or offset < 0x3ffe0000 or size > 65536:
  258. raise Exception('Suspicious segment %x,%d' % (offset, size))
  259. self.segments.append((offset, size, f.read(size)))
  260. # Skip the padding. The checksum is stored in the last byte so that the
  261. # file is a multiple of 16 bytes.
  262. align = 15-(f.tell() % 16)
  263. f.seek(align, 1)
  264. self.checksum = ord(f.read(1))
  265. def add_segment(self, addr, data):
  266. # Data should be aligned on word boundary
  267. l = len(data)
  268. if l % 4:
  269. data += b"\x00" * (4 - l % 4)
  270. self.segments.append((addr, len(data), data))
  271. def save(self, filename):
  272. f = file(filename, 'wb')
  273. f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments),
  274. self.flash_mode, self.flash_size_freq, self.entrypoint))
  275. checksum = ESPROM.ESP_CHECKSUM_MAGIC
  276. for (offset, size, data) in self.segments:
  277. f.write(struct.pack('<II', offset, size))
  278. f.write(data)
  279. checksum = ESPROM.checksum(data, checksum)
  280. align = 15-(f.tell() % 16)
  281. f.seek(align, 1)
  282. f.write(struct.pack('B', checksum))
  283. class ELFFile:
  284. def __init__(self, name):
  285. self.name = name
  286. self.symbols = None
  287. def _fetch_symbols(self):
  288. if self.symbols is not None:
  289. return
  290. self.symbols = {}
  291. try:
  292. tool_nm = "xtensa-lx106-elf-nm"
  293. if os.getenv('XTENSA_CORE')=='lx106':
  294. tool_nm = "xt-nm"
  295. proc = subprocess.Popen([tool_nm, self.name], stdout=subprocess.PIPE)
  296. except OSError:
  297. print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?"
  298. sys.exit(1)
  299. for l in proc.stdout:
  300. fields = l.strip().split()
  301. self.symbols[fields[2]] = int(fields[0], 16)
  302. def get_symbol_addr(self, sym):
  303. self._fetch_symbols()
  304. return self.symbols[sym]
  305. def get_entry_point(self):
  306. tool_readelf = "xtensa-lx106-elf-readelf"
  307. if os.getenv('XTENSA_CORE')=='lx106':
  308. tool_objcopy = "xt-readelf"
  309. try:
  310. proc = subprocess.Popen([tool_readelf, "-h", self.name], stdout=subprocess.PIPE)
  311. except OSError:
  312. print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?"
  313. sys.exit(1)
  314. for l in proc.stdout:
  315. fields = l.strip().split()
  316. if fields[0] == "Entry":
  317. return int(fields[3], 0);
  318. def load_section(self, section):
  319. tool_objcopy = "xtensa-lx106-elf-objcopy"
  320. if os.getenv('XTENSA_CORE')=='lx106':
  321. tool_objcopy = "xt-objcopy"
  322. subprocess.check_call([tool_objcopy, "--only-section", section, "-Obinary", self.name, ".tmp.section"])
  323. f = open(".tmp.section", "rb")
  324. data = f.read()
  325. f.close()
  326. os.remove(".tmp.section")
  327. return data
  328. def arg_auto_int(x):
  329. return int(x, 0)
  330. if __name__ == '__main__':
  331. parser = argparse.ArgumentParser(description = 'ESP8266 ROM Bootloader Utility', prog = 'esptool')
  332. parser.add_argument(
  333. '--port', '-p',
  334. help = 'Serial port device',
  335. default = '/dev/ttyUSB0')
  336. parser.add_argument(
  337. '--baud', '-b',
  338. help = 'Serial port baud rate',
  339. type = arg_auto_int,
  340. default = ESPROM.ESP_ROM_BAUD)
  341. subparsers = parser.add_subparsers(
  342. dest = 'operation',
  343. help = 'Run esptool {command} -h for additional help')
  344. parser_load_ram = subparsers.add_parser(
  345. 'load_ram',
  346. help = 'Download an image to RAM and execute')
  347. parser_load_ram.add_argument('filename', help = 'Firmware image')
  348. parser_dump_mem = subparsers.add_parser(
  349. 'dump_mem',
  350. help = 'Dump arbitrary memory to disk')
  351. parser_dump_mem.add_argument('address', help = 'Base address', type = arg_auto_int)
  352. parser_dump_mem.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
  353. parser_dump_mem.add_argument('filename', help = 'Name of binary dump')
  354. parser_read_mem = subparsers.add_parser(
  355. 'read_mem',
  356. help = 'Read arbitrary memory location')
  357. parser_read_mem.add_argument('address', help = 'Address to read', type = arg_auto_int)
  358. parser_write_mem = subparsers.add_parser(
  359. 'write_mem',
  360. help = 'Read-modify-write to arbitrary memory location')
  361. parser_write_mem.add_argument('address', help = 'Address to write', type = arg_auto_int)
  362. parser_write_mem.add_argument('value', help = 'Value', type = arg_auto_int)
  363. parser_write_mem.add_argument('mask', help = 'Mask of bits to write', type = arg_auto_int)
  364. parser_write_flash = subparsers.add_parser(
  365. 'write_flash',
  366. help = 'Write a binary blob to flash')
  367. parser_write_flash.add_argument('addr_filename', nargs = '+', help = 'Address and binary file to write there, separated by space')
  368. parser_write_flash.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
  369. choices = ['40m', '26m', '20m', '80m'], default = '40m')
  370. parser_write_flash.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
  371. choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
  372. parser_write_flash.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
  373. choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
  374. parser_run = subparsers.add_parser(
  375. 'run',
  376. help = 'Run application code in flash')
  377. parser_image_info = subparsers.add_parser(
  378. 'image_info',
  379. help = 'Dump headers from an application image')
  380. parser_image_info.add_argument('filename', help = 'Image file to parse')
  381. parser_make_image = subparsers.add_parser(
  382. 'make_image',
  383. help = 'Create an application image from binary files')
  384. parser_make_image.add_argument('output', help = 'Output image file')
  385. parser_make_image.add_argument('--segfile', '-f', action = 'append', help = 'Segment input file')
  386. parser_make_image.add_argument('--segaddr', '-a', action = 'append', help = 'Segment base address', type = arg_auto_int)
  387. parser_make_image.add_argument('--entrypoint', '-e', help = 'Address of entry point', type = arg_auto_int, default = 0)
  388. parser_elf2image = subparsers.add_parser(
  389. 'elf2image',
  390. help = 'Create an application image from ELF file')
  391. parser_elf2image.add_argument('input', help = 'Input ELF file')
  392. parser_elf2image.add_argument('--output', '-o', help = 'Output filename prefix', type = str)
  393. parser_elf2image.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
  394. choices = ['40m', '26m', '20m', '80m'], default = '40m')
  395. parser_elf2image.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
  396. choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
  397. parser_elf2image.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
  398. choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
  399. parser_read_mac = subparsers.add_parser(
  400. 'read_mac',
  401. help = 'Read MAC address from OTP ROM')
  402. parser_flash_id = subparsers.add_parser(
  403. 'flash_id',
  404. help = 'Read SPI flash manufacturer and device ID')
  405. parser_read_flash = subparsers.add_parser(
  406. 'read_flash',
  407. help = 'Read SPI flash content')
  408. parser_read_flash.add_argument('address', help = 'Start address', type = arg_auto_int)
  409. parser_read_flash.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
  410. parser_read_flash.add_argument('filename', help = 'Name of binary dump')
  411. parser_erase_flash = subparsers.add_parser(
  412. 'erase_flash',
  413. help = 'Perform Chip Erase on SPI flash')
  414. args = parser.parse_args()
  415. # Create the ESPROM connection object, if needed
  416. esp = None
  417. if args.operation not in ('image_info','make_image','elf2image'):
  418. esp = ESPROM(args.port, args.baud)
  419. esp.connect()
  420. # Do the actual work. Should probably be split into separate functions.
  421. if args.operation == 'load_ram':
  422. image = ESPFirmwareImage(args.filename)
  423. print 'RAM boot...'
  424. for (offset, size, data) in image.segments:
  425. print 'Downloading %d bytes at %08x...' % (size, offset),
  426. sys.stdout.flush()
  427. esp.mem_begin(size, math.ceil(size / float(esp.ESP_RAM_BLOCK)), esp.ESP_RAM_BLOCK, offset)
  428. seq = 0
  429. while len(data) > 0:
  430. esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq)
  431. data = data[esp.ESP_RAM_BLOCK:]
  432. seq += 1
  433. print 'done!'
  434. print 'All segments done, executing at %08x' % image.entrypoint
  435. esp.mem_finish(image.entrypoint)
  436. elif args.operation == 'read_mem':
  437. print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))
  438. elif args.operation == 'write_mem':
  439. esp.write_reg(args.address, args.value, args.mask, 0)
  440. print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)
  441. elif args.operation == 'dump_mem':
  442. f = file(args.filename, 'wb')
  443. for i in xrange(args.size/4):
  444. d = esp.read_reg(args.address+(i*4))
  445. f.write(struct.pack('<I', d))
  446. if f.tell() % 1024 == 0:
  447. print '\r%d bytes read... (%d %%)' % (f.tell(), f.tell()*100/args.size),
  448. sys.stdout.flush()
  449. print 'Done!'
  450. elif args.operation == 'write_flash':
  451. assert len(args.addr_filename) % 2 == 0
  452. flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
  453. flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
  454. flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
  455. flash_info = struct.pack('BB', flash_mode, flash_size_freq)
  456. while args.addr_filename:
  457. address = int(args.addr_filename[0], 0)
  458. filename = args.addr_filename[1]
  459. args.addr_filename = args.addr_filename[2:]
  460. image = file(filename, 'rb').read()
  461. print 'Erasing flash...'
  462. blocks = math.ceil(len(image)/float(esp.ESP_FLASH_BLOCK))
  463. esp.flash_begin(blocks*esp.ESP_FLASH_BLOCK, address)
  464. seq = 0
  465. while len(image) > 0:
  466. print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks),
  467. sys.stdout.flush()
  468. block = image[0:esp.ESP_FLASH_BLOCK]
  469. # Fix sflash config data
  470. if address == 0 and seq == 0 and block[0] == '\xe9':
  471. block = block[0:2] + flash_info + block[4:]
  472. # Pad the last block
  473. block = block + '\xff' * (esp.ESP_FLASH_BLOCK-len(block))
  474. esp.flash_block(block, seq)
  475. image = image[esp.ESP_FLASH_BLOCK:]
  476. seq += 1
  477. print
  478. print '\nLeaving...'
  479. if args.flash_mode == 'dio':
  480. esp.flash_unlock_dio()
  481. else:
  482. esp.flash_finish(False)
  483. elif args.operation == 'run':
  484. esp.run()
  485. elif args.operation == 'image_info':
  486. image = ESPFirmwareImage(args.filename)
  487. print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set'
  488. print '%d segments' % len(image.segments)
  489. print
  490. checksum = ESPROM.ESP_CHECKSUM_MAGIC
  491. for (idx, (offset, size, data)) in enumerate(image.segments):
  492. print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset)
  493. checksum = ESPROM.checksum(data, checksum)
  494. print
  495. print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')
  496. elif args.operation == 'make_image':
  497. image = ESPFirmwareImage()
  498. if len(args.segfile) == 0:
  499. raise Exception('No segments specified')
  500. if len(args.segfile) != len(args.segaddr):
  501. raise Exception('Number of specified files does not match number of specified addresses')
  502. for (seg, addr) in zip(args.segfile, args.segaddr):
  503. data = file(seg, 'rb').read()
  504. image.add_segment(addr, data)
  505. image.entrypoint = args.entrypoint
  506. image.save(args.output)
  507. elif args.operation == 'elf2image':
  508. if args.output is None:
  509. args.output = args.input + '-'
  510. e = ELFFile(args.input)
  511. image = ESPFirmwareImage()
  512. image.entrypoint = e.get_entry_point()
  513. for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
  514. data = e.load_section(section)
  515. image.add_segment(e.get_symbol_addr(start), data)
  516. image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
  517. image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
  518. image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
  519. image.save(args.output + "0x00000.bin")
  520. data = e.load_section(".irom0.text")
  521. off = e.get_symbol_addr("_irom0_text_start") - 0x40200000
  522. assert off >= 0
  523. f = open(args.output + "0x%05x.bin" % off, "wb")
  524. f.write(data)
  525. f.close()
  526. elif args.operation == 'read_mac':
  527. mac = esp.read_mac()
  528. print 'MAC: %s' % ':'.join(map(lambda x: '%02x'%x, mac))
  529. elif args.operation == 'flash_id':
  530. flash_id = esp.flash_id()
  531. print 'Manufacturer: %02x' % (flash_id & 0xff)
  532. print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)
  533. elif args.operation == 'read_flash':
  534. print 'Please wait...'
  535. file(args.filename, 'wb').write(esp.flash_read(args.address, 1024, int(math.ceil(args.size / 1024.)))[:args.size])
  536. elif args.operation == 'erase_flash':
  537. esp.flash_erase()