diff --git a/Makefile b/Makefile index a16f85ce..7de24a3b 100644 --- a/Makefile +++ b/Makefile @@ -75,7 +75,7 @@ else endif endif ############################################################# -ESPTOOL ?= ../tools/esptool.sh +ESPTOOL ?= ../tools/esptool.py CSRCS ?= $(wildcard *.c) diff --git a/tools/NOTICE b/tools/NOTICE new file mode 100644 index 00000000..4a23662a --- /dev/null +++ b/tools/NOTICE @@ -0,0 +1,3 @@ +The esptool.py.bak is from github.com/themadinventor/esptool. +The esptool.py is converted fron python2 to python2/3 by futurize in the package future. + diff --git a/tools/esptool.py b/tools/esptool.py index 130e80f0..cc661182 100755 --- a/tools/esptool.py +++ b/tools/esptool.py @@ -17,6 +17,13 @@ # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301 USA. +from __future__ import division +from __future__ import print_function +from builtins import zip +from builtins import chr +from builtins import range +from builtins import object +from past.utils import old_div import sys import struct import serial @@ -26,7 +33,7 @@ import argparse import os import subprocess -class ESPROM: +class ESPROM(object): # These are the currently known commands supported by the ROM ESP_FLASH_BEGIN = 0x02 @@ -123,12 +130,12 @@ class ESPROM: """ Perform a connection test """ def sync(self): self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20'+32*'\x55') - for i in xrange(7): + for i in range(7): self.command() """ Try connecting repeatedly until successful, or giving up """ def connect(self): - print 'Connecting...' + print('Connecting...') # RTS = CH_PD (i.e reset) # DTR = GPIO0 @@ -139,7 +146,7 @@ class ESPROM: self._port.setDTR(False) self._port.timeout = 0.5 - for i in xrange(10): + for i in range(10): try: self._port.flushInput() self._port.flushOutput() @@ -184,7 +191,7 @@ class ESPROM: """ Start downloading to Flash (performs an erase) """ def flash_begin(self, size, offset): old_tmo = self._port.timeout - num_blocks = (size + ESPROM.ESP_FLASH_BLOCK - 1) / ESPROM.ESP_FLASH_BLOCK + num_blocks = old_div((size + ESPROM.ESP_FLASH_BLOCK - 1), ESPROM.ESP_FLASH_BLOCK) self._port.timeout = 10 if self.command(ESPROM.ESP_FLASH_BEGIN, struct.pack(' 16: raise Exception('Invalid firmware image') - for i in xrange(segments): + for i in range(segments): (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: raise Exception('Suspicious segment %x,%d' % (offset, size)) @@ -259,7 +266,7 @@ class ESPFirmwareImage: f.write(struct.pack('B', checksum)) -class ELFFile: +class ELFFile(object): def __init__(self, name): self.name = name @@ -275,7 +282,7 @@ class ELFFile: tool_nm = "xt-nm" proc = subprocess.Popen([tool_nm, self.name], stdout=subprocess.PIPE) except OSError: - print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?" + print("Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?") sys.exit(1) for l in proc.stdout: fields = l.strip().split() @@ -386,38 +393,38 @@ if __name__ == '__main__': if args.operation == 'load_ram': image = ESPFirmwareImage(args.filename) - print 'RAM boot...' + print('RAM boot...') for (offset, size, data) in image.segments: - print 'Downloading %d bytes at %08x...' % (size, offset), + print('Downloading %d bytes at %08x...' % (size, offset), end=' ') sys.stdout.flush() - esp.mem_begin(size, math.ceil(size / float(esp.ESP_RAM_BLOCK)), esp.ESP_RAM_BLOCK, offset) + esp.mem_begin(size, math.ceil(old_div(size, float(esp.ESP_RAM_BLOCK))), esp.ESP_RAM_BLOCK, offset) seq = 0 while len(data) > 0: esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) data = data[esp.ESP_RAM_BLOCK:] seq += 1 - print 'done!' + print('done!') - print 'All segments done, executing at %08x' % image.entrypoint + print('All segments done, executing at %08x' % image.entrypoint) esp.mem_finish(image.entrypoint) elif args.operation == 'read_mem': - print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address)) + print('0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))) elif args.operation == 'write_mem': esp.write_reg(args.address, args.value, args.mask, 0) - print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address) + print('Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)) elif args.operation == 'dump_mem': f = file(args.filename, 'wb') - for i in xrange(args.size/4): + for i in range(old_div(args.size,4)): d = esp.read_reg(args.address+(i*4)) f.write(struct.pack(' 0: - print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks), + print('\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks), end=' ') sys.stdout.flush() block = image[0:esp.ESP_FLASH_BLOCK] block = block + '\xe0' * (esp.ESP_FLASH_BLOCK-len(block)) esp.flash_block(block, seq) image = image[esp.ESP_FLASH_BLOCK:] seq += 1 - print - print '\nLeaving...' + print() + print('\nLeaving...') esp.flash_finish(False) elif args.operation == 'run': @@ -447,15 +454,15 @@ if __name__ == '__main__': elif args.operation == 'image_info': image = ESPFirmwareImage(args.filename) - print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set' - print '%d segments' % len(image.segments) - print + print(('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set') + print('%d segments' % len(image.segments)) + print() checksum = ESPROM.ESP_CHECKSUM_MAGIC for (idx, (offset, size, data)) in enumerate(image.segments): - print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset) + print('Segment %d: %5d bytes at %08x' % (idx+1, size, offset)) checksum = ESPROM.checksum(data, checksum) - print - print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!') + print() + print('Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')) elif args.operation == 'make_image': image = ESPFirmwareImage() @@ -489,4 +496,4 @@ if __name__ == '__main__': elif args.operation == 'read_mac': mac0 = esp.read_reg(esp.ESP_OTP_MAC0) mac1 = esp.read_reg(esp.ESP_OTP_MAC1) - print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) + print('MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)) diff --git a/tools/esptool.py.bak b/tools/esptool.py.bak new file mode 100755 index 00000000..130e80f0 --- /dev/null +++ b/tools/esptool.py.bak @@ -0,0 +1,492 @@ +#!/usr/bin/env python +# +# ESP8266 ROM Bootloader Utility +# https://github.com/themadinventor/esptool +# +# Copyright (C) 2014 Fredrik Ahlberg +# +# 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 sys +import struct +import serial +import math +import time +import argparse +import os +import subprocess + +class ESPROM: + + # These are the currently known commands supported by the ROM + ESP_FLASH_BEGIN = 0x02 + ESP_FLASH_DATA = 0x03 + ESP_FLASH_END = 0x04 + ESP_MEM_BEGIN = 0x05 + ESP_MEM_END = 0x06 + ESP_MEM_DATA = 0x07 + ESP_SYNC = 0x08 + ESP_WRITE_REG = 0x09 + ESP_READ_REG = 0x0a + + # Maximum block sized for RAM and Flash writes, respectively. + ESP_RAM_BLOCK = 0x1800 + ESP_FLASH_BLOCK = 0x100 + + # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. + ESP_ROM_BAUD = 115200 + + # First byte of the application image + ESP_IMAGE_MAGIC = 0xe9 + + # Initial state for the checksum routine + ESP_CHECKSUM_MAGIC = 0xef + + # OTP ROM addresses + ESP_OTP_MAC0 = 0x3ff00050 + ESP_OTP_MAC1 = 0x3ff00054 + + def __init__(self, port = 0, baud = ESP_ROM_BAUD): + self._port = serial.Serial(port, baud) + + """ Read bytes from the serial port while performing SLIP unescaping """ + def read(self, length = 1): + b = '' + while len(b) < length: + c = self._port.read(1) + if c == '\xdb': + c = self._port.read(1) + if c == '\xdc': + b = b + '\xc0' + elif c == '\xdd': + b = b + '\xdb' + else: + raise Exception('Invalid SLIP escape') + else: + b = b + c + return b + + """ Write bytes to the serial port while performing SLIP escaping """ + def write(self, packet): + buf = '\xc0' + for b in packet: + if b == '\xc0': + buf += '\xdb\xdc' + elif b == '\xdb': + buf += '\xdb\xdd' + else: + buf += b + buf += '\xc0' + self._port.write(buf) + + """ Calculate checksum of a blob, as it is defined by the ROM """ + @staticmethod + def checksum(data, state = ESP_CHECKSUM_MAGIC): + for b in data: + state ^= ord(b) + return state + + """ Send a request and read the response """ + def command(self, op = None, data = None, chk = 0): + if op: + # Construct and send request + pkt = struct.pack(' 16: + raise Exception('Invalid firmware image') + + for i in xrange(segments): + (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: + raise Exception('Suspicious segment %x,%d' % (offset, size)) + self.segments.append((offset, size, f.read(size))) + + # Skip the padding. The checksum is stored in the last byte so that the + # file is a multiple of 16 bytes. + align = 15-(f.tell() % 16) + f.seek(align, 1) + + self.checksum = ord(f.read(1)) + + def add_segment(self, addr, data): + # Data should be aligned on word boundary + l = len(data) + if l % 4: + data += b"\x00" * (4 - l % 4) + self.segments.append((addr, len(data), data)) + + def save(self, filename): + f = file(filename, 'wb') + f.write(struct.pack(' 0: + esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) + data = data[esp.ESP_RAM_BLOCK:] + seq += 1 + print 'done!' + + print 'All segments done, executing at %08x' % image.entrypoint + esp.mem_finish(image.entrypoint) + + elif args.operation == 'read_mem': + print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address)) + + elif args.operation == 'write_mem': + esp.write_reg(args.address, args.value, args.mask, 0) + print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address) + + elif args.operation == 'dump_mem': + f = file(args.filename, 'wb') + for i in xrange(args.size/4): + d = esp.read_reg(args.address+(i*4)) + f.write(struct.pack(' 0: + print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks), + sys.stdout.flush() + block = image[0:esp.ESP_FLASH_BLOCK] + block = block + '\xe0' * (esp.ESP_FLASH_BLOCK-len(block)) + esp.flash_block(block, seq) + image = image[esp.ESP_FLASH_BLOCK:] + seq += 1 + print + print '\nLeaving...' + esp.flash_finish(False) + + elif args.operation == 'run': + esp.run() + + elif args.operation == 'image_info': + image = ESPFirmwareImage(args.filename) + print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set' + print '%d segments' % len(image.segments) + print + checksum = ESPROM.ESP_CHECKSUM_MAGIC + for (idx, (offset, size, data)) in enumerate(image.segments): + print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset) + checksum = ESPROM.checksum(data, checksum) + print + print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!') + + elif args.operation == 'make_image': + image = ESPFirmwareImage() + if len(args.segfile) == 0: + raise Exception('No segments specified') + if len(args.segfile) != len(args.segaddr): + raise Exception('Number of specified files does not match number of specified addresses') + for (seg, addr) in zip(args.segfile, args.segaddr): + data = file(seg, 'rb').read() + image.add_segment(addr, data) + image.entrypoint = args.entrypoint + image.save(args.output) + + elif args.operation == 'elf2image': + if args.output is None: + args.output = args.input + '-' + e = ELFFile(args.input) + image = ESPFirmwareImage() + image.entrypoint = e.get_symbol_addr("call_user_start") + for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")): + data = e.load_section(section) + image.add_segment(e.get_symbol_addr(start), data) + image.save(args.output + "0x00000.bin") + data = e.load_section(".irom0.text") + off = e.get_symbol_addr("_irom0_text_start") - 0x40200000 + assert off >= 0 + f = open(args.output + "0x%05x.bin" % off, "wb") + f.write(data) + f.close() + + elif args.operation == 'read_mac': + mac0 = esp.read_reg(esp.ESP_OTP_MAC0) + mac1 = esp.read_reg(esp.ESP_OTP_MAC1) + print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) diff --git a/tools/esptool.sh b/tools/esptool.sh deleted file mode 100755 index d372c3fa..00000000 --- a/tools/esptool.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -BASEDIR=$(dirname $(readlink -f "$0")) -ret=`python -c 'import sys; print("%i" % (sys.hexversion<0x03000000))'` -if [ $ret -eq 0 ]; then - #Retry python 2 - ret=`python2 -c 'import sys; print("%i" % (sys.hexversion<0x03000000))'` - if [ $ret -eq 0 ]; then - echo "Cannot find python2." - else - #Ok - python2 $BASEDIR/esptool.py $@ - fi -else - #Ok - python $BASEDIR/esptool.py $@ -fi \ No newline at end of file