#!/usr/bin/env python # # ESP8266 LFS Loader Utility # # Copyright (C) 2019 Terry Ellison, NodeMCU Firmware Community Project. drawing # heavily from and including content from esptool.py with full acknowledgement # under GPL 2.0, with said content: Copyright (C) 2014-2016 Fredrik Ahlberg, Angus # Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted. # https://github.com/espressif/esptool # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301 USA. import os import sys sys.path.append(os.path.realpath(os.path.dirname(__file__) + '/toolchains/')) import esptool import io import tempfile import shutil from pprint import pprint import argparse import gzip import copy import inspect import struct import string __version__ = '1.0' __program__ = 'nodemcu-partition.py' ROM0_Seg = 0x010000 FLASH_PAGESIZE = 0x001000 FLASH_BASE_ADDR = 0x40200000 PARTITION_TYPES = { 4: 'RF_CAL', 5: 'PHY_DATA', 6: 'SYSTEM_PARAMETER', 101: 'EAGLEROM', 102: 'IROM0TEXT', 103: 'LFS0', 104: 'LFS1', 105: 'TLSCERT', 106: 'SPIFFS0', 107: 'SPIFFS1'} MAX_PT_SIZE = 20*3 FLASH_SIG = 0xfafaa150 FLASH_SIG_MASK = 0xfffffff0 FLASH_SIG_ABSOLUTE = 0x00000001 WORDSIZE = 4 WORDBITS = 32 PACK_INT = struct.Struct(">= 1 return ''.join([PACK_INT.pack(i) for i in image]) def main(): def arg_auto_int(x): ux = x.upper() if "MB" in ux: return int(ux[:ux.index("MB")]) * 1024 * 1024 elif "KB" in ux: return int(ux[:ux.index("KB")]) * 1024 else: return int(ux, 0) print('%s V%s' %(__program__, __version__)) # ---------- process the arguments ---------- # a = argparse.ArgumentParser( description='%s V%s - ESP8266 NodeMCU Loader Utility' % (__program__, __version__), prog='esplfs') a.add_argument('--port', '-p', help='Serial port device') a.add_argument('--baud', '-b', type=arg_auto_int, help='Serial port baud rate used when flashing/reading') a.add_argument('--lfs-addr', '-la', dest="la", type=arg_auto_int, help='(Overwrite) start address of LFS partition') a.add_argument('--lfs-size', '-ls', dest="ls", type=arg_auto_int, help='(Overwrite) length of LFS partition') a.add_argument('--lfs-file', '-lf', dest="lf", help='LFS image file') a.add_argument('--spiffs-addr', '-sa', dest="sa", type=arg_auto_int, help='(Overwrite) start address of SPIFFS partition') a.add_argument('--spiffs-size', '-ss', dest="ss", type=arg_auto_int, help='(Overwrite) length of SPIFFS partition') a.add_argument('--spiffs-file', '-sf', dest="sf", help='SPIFFS image file') arg = a.parse_args() if arg.lf is not None: if not os.path.exists(arg.lf): raise FatalError("LFS image %s does not exist" % arg.lf) if arg.sf is not None: if not os.path.exists(arg.sf): raise FatalError("SPIFFS image %s does not exist" % arg.sf) base = [] if arg.port is None else ['--port',arg.port] if arg.baud is not None: base.extend(['--baud',arg.baud]) # ---------- Use esptool to read the PT ---------- # tmpdir = tempfile.mkdtemp() pt_file = tmpdir + '/pt.dmp' espargs = base+['--after', 'no_reset', 'read_flash', '--no-progress', str(ROM0_Seg), str(FLASH_PAGESIZE), pt_file] esptool.main(espargs) with open(pt_file,"rb") as f: data = f.read() pt, pt_map, n = load_PT(data, arg) n = n+1 odata = ''.join([PACK_INT.pack(pt[i]) for i in range(0,3*n)]) + \ "\xFF" * len(data[3*4*n:]) # ---------- If the PT has changed then use esptool to rewrite it ---------- # if odata != data: print("PT updated") pt_file = tmpdir + '/opt.dmp' with open(pt_file,"wb") as f: f.write(odata) espargs = base+['--after', 'no_reset', 'write_flash', '--no-progress', str(ROM0_Seg), pt_file] esptool.main(espargs) if arg.lf is not None: i = pt_map['LFS0'] la,ls = pt[i+1], pt[i+2] # ---------- Read and relocate the LFS image ---------- # with gzip.open(arg.lf) as f: lfs = f.read() lfs = relocate_lfs(lfs, la, ls) # ---------- Write to a temp file and use esptool to write it to flash ---------- # img_file = tmpdir + '/lfs.img' espargs = base + ['write_flash', str(la), img_file] with open(img_file,"wb") as f: f.write(lfs) esptool.main(espargs) if arg.sf is not None: sa = pt[pt_map['SPIFFS0']+1] # ---------- Write to a temp file and use esptool to write it to flash ---------- # spiffs_file = arg.sf espargs = base + ['', str(sa), spiffs_file] esptool.main(espargs) # ---------- Clean up temp directory ---------- # espargs = base + ['--after', 'hard_reset', 'flash_id'] esptool.main(espargs) shutil.rmtree(tmpdir) def _main(): main() if __name__ == '__main__': _main()