First test of word displaying functionality
This commit is contained in:
commit
fc46b11390
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
wlancfg.lua
|
12
Readme.md
Normal file
12
Readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Ueber Traffic Light
|
||||
## Setup
|
||||
Generate a wlancfg.lua for your wifi based on the given example wlancfg.lua.example
|
||||
|
||||
Copy the required files to the microcontroller:
|
||||
<pre>
|
||||
sudo ./programESP.sh serial wlancfg.lua.lua wlancfg.lua
|
||||
sudo ./programESP.sh serial init.lua init.lua
|
||||
</pre>
|
||||
|
||||
## Internal Setup
|
||||
* GPIO2 LEDs
|
10
example.lua
Normal file
10
example.lua
Normal file
@ -0,0 +1,10 @@
|
||||
-- Example usage of the word clock
|
||||
dofile("wordclock.lua")
|
||||
|
||||
-- Manually set something
|
||||
leds=display_timestat(15,30)
|
||||
for k,v in pairs(leds) do
|
||||
if (v == 1) then
|
||||
print(k)
|
||||
end
|
||||
end
|
15
os/bl_readMAC.sh
Executable file
15
os/bl_readMAC.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "One parameter required: the device of the serial interface"
|
||||
echo "$0 <device>"
|
||||
echo "e.g.:"
|
||||
echo "$0 ttyUSB0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEVICE=$1
|
||||
|
||||
|
||||
echo "Read the MAC address from bootloader"
|
||||
./esptool.py --port /dev/$DEVICE read_mac
|
606
os/esptool.py
Executable file
606
os/esptool.py
Executable file
@ -0,0 +1,606 @@
|
||||
#!/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 = 0x400
|
||||
|
||||
# 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
|
||||
|
||||
# Sflash stub: an assembly routine to read from spi flash and send to host
|
||||
SFLASH_STUB = "\x80\x3c\x00\x40\x1c\x4b\x00\x40\x21\x11\x00\x40\x00\x80" \
|
||||
"\xfe\x3f\xc1\xfb\xff\xd1\xf8\xff\x2d\x0d\x31\xfd\xff\x41\xf7\xff\x4a" \
|
||||
"\xdd\x51\xf9\xff\xc0\x05\x00\x21\xf9\xff\x31\xf3\xff\x41\xf5\xff\xc0" \
|
||||
"\x04\x00\x0b\xcc\x56\xec\xfd\x06\xff\xff\x00\x00"
|
||||
|
||||
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'+(packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc'))+'\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('<BBHI', 0x00, op, len(data), chk) + data
|
||||
self.write(pkt)
|
||||
|
||||
# Read header of response and parse
|
||||
if self._port.read(1) != '\xc0':
|
||||
raise Exception('Invalid head of packet')
|
||||
hdr = self.read(8)
|
||||
(resp, op_ret, len_ret, val) = struct.unpack('<BBHI', hdr)
|
||||
if resp != 0x01 or (op and op_ret != op):
|
||||
raise Exception('Invalid response')
|
||||
|
||||
# The variable-length body
|
||||
body = self.read(len_ret)
|
||||
|
||||
# Terminating byte
|
||||
if self._port.read(1) != chr(0xc0):
|
||||
raise Exception('Invalid end of packet')
|
||||
|
||||
return val, body
|
||||
|
||||
""" Perform a connection test """
|
||||
def sync(self):
|
||||
self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20'+32*'\x55')
|
||||
for i in xrange(7):
|
||||
self.command()
|
||||
|
||||
""" Try connecting repeatedly until successful, or giving up """
|
||||
def connect(self):
|
||||
print 'Connecting...'
|
||||
|
||||
# RTS = CH_PD (i.e reset)
|
||||
# DTR = GPIO0
|
||||
self._port.setRTS(True)
|
||||
self._port.setDTR(True)
|
||||
self._port.setRTS(False)
|
||||
time.sleep(0.1)
|
||||
self._port.setDTR(False)
|
||||
|
||||
self._port.timeout = 0.5
|
||||
for i in xrange(10):
|
||||
try:
|
||||
self._port.flushInput()
|
||||
self._port.flushOutput()
|
||||
self.sync()
|
||||
self._port.timeout = 5
|
||||
return
|
||||
except:
|
||||
time.sleep(0.1)
|
||||
raise Exception('Failed to connect')
|
||||
|
||||
""" Read memory address in target """
|
||||
def read_reg(self, addr):
|
||||
res = self.command(ESPROM.ESP_READ_REG, struct.pack('<I', addr))
|
||||
if res[1] != "\0\0":
|
||||
raise Exception('Failed to read target memory')
|
||||
return res[0]
|
||||
|
||||
""" Write to memory address in target """
|
||||
def write_reg(self, addr, value, mask, delay_us = 0):
|
||||
if self.command(ESPROM.ESP_WRITE_REG,
|
||||
struct.pack('<IIII', addr, value, mask, delay_us))[1] != "\0\0":
|
||||
raise Exception('Failed to write target memory')
|
||||
|
||||
""" Start downloading an application image to RAM """
|
||||
def mem_begin(self, size, blocks, blocksize, offset):
|
||||
if self.command(ESPROM.ESP_MEM_BEGIN,
|
||||
struct.pack('<IIII', size, blocks, blocksize, offset))[1] != "\0\0":
|
||||
raise Exception('Failed to enter RAM download mode')
|
||||
|
||||
""" Send a block of an image to RAM """
|
||||
def mem_block(self, data, seq):
|
||||
if self.command(ESPROM.ESP_MEM_DATA,
|
||||
struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
|
||||
raise Exception('Failed to write to target RAM')
|
||||
|
||||
""" Leave download mode and run the application """
|
||||
def mem_finish(self, entrypoint = 0):
|
||||
if self.command(ESPROM.ESP_MEM_END,
|
||||
struct.pack('<II', int(entrypoint == 0), entrypoint))[1] != "\0\0":
|
||||
raise Exception('Failed to leave RAM download mode')
|
||||
|
||||
""" 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
|
||||
self._port.timeout = 10
|
||||
if self.command(ESPROM.ESP_FLASH_BEGIN,
|
||||
struct.pack('<IIII', size, num_blocks, ESPROM.ESP_FLASH_BLOCK, offset))[1] != "\0\0":
|
||||
raise Exception('Failed to enter Flash download mode')
|
||||
self._port.timeout = old_tmo
|
||||
|
||||
""" Write block to flash """
|
||||
def flash_block(self, data, seq):
|
||||
if self.command(ESPROM.ESP_FLASH_DATA,
|
||||
struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
|
||||
raise Exception('Failed to write to target Flash')
|
||||
|
||||
""" Leave flash mode and run/reboot """
|
||||
def flash_finish(self, reboot = False):
|
||||
pkt = struct.pack('<I', int(not reboot))
|
||||
if self.command(ESPROM.ESP_FLASH_END, pkt)[1] != "\0\0":
|
||||
raise Exception('Failed to leave Flash mode')
|
||||
|
||||
""" Run application code in flash """
|
||||
def run(self, reboot = False):
|
||||
# Fake flash begin immediately followed by flash end
|
||||
self.flash_begin(0, 0)
|
||||
self.flash_finish(reboot)
|
||||
|
||||
""" Read MAC from OTP ROM """
|
||||
def read_mac(self):
|
||||
mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
|
||||
mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
|
||||
if ((mac1 >> 16) & 0xff) == 0:
|
||||
oui = (0x18, 0xfe, 0x34)
|
||||
elif ((mac1 >> 16) & 0xff) == 1:
|
||||
oui = (0xac, 0xd0, 0x74)
|
||||
else:
|
||||
raise Exception("Unknown OUI")
|
||||
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
|
||||
|
||||
""" Read SPI flash manufacturer and device id """
|
||||
def flash_id(self):
|
||||
self.flash_begin(0, 0)
|
||||
self.write_reg(0x60000240, 0x0, 0xffffffff)
|
||||
self.write_reg(0x60000200, 0x10000000, 0xffffffff)
|
||||
flash_id = esp.read_reg(0x60000240)
|
||||
self.flash_finish(False)
|
||||
return flash_id
|
||||
|
||||
""" Read SPI flash """
|
||||
def flash_read(self, offset, size, count = 1):
|
||||
# Create a custom stub
|
||||
stub = struct.pack('<III', offset, size, count) + self.SFLASH_STUB
|
||||
|
||||
# Trick ROM to initialize SFlash
|
||||
self.flash_begin(0, 0)
|
||||
|
||||
# Download stub
|
||||
self.mem_begin(len(stub), 1, len(stub), 0x40100000)
|
||||
self.mem_block(stub, 0)
|
||||
self.mem_finish(0x4010001c)
|
||||
|
||||
# Fetch the data
|
||||
data = ''
|
||||
for _ in xrange(count):
|
||||
if self._port.read(1) != '\xc0':
|
||||
raise Exception('Invalid head of packet (sflash read)')
|
||||
|
||||
data += self.read(size)
|
||||
|
||||
if self._port.read(1) != chr(0xc0):
|
||||
raise Exception('Invalid end of packet (sflash read)')
|
||||
|
||||
return data
|
||||
|
||||
""" Perform a chip erase of SPI flash """
|
||||
def flash_erase(self):
|
||||
# Trick ROM to initialize SFlash
|
||||
self.flash_begin(0, 0)
|
||||
|
||||
# This is hacky: we don't have a custom stub, instead we trick
|
||||
# the bootloader to jump to the SPIEraseChip() routine and then halt/crash
|
||||
# when it tries to boot an unconfigured system.
|
||||
self.mem_begin(0,0,0,0x40100000)
|
||||
self.mem_finish(0x40004984)
|
||||
|
||||
# Yup - there's no good way to detect if we succeeded.
|
||||
# It it on the other hand unlikely to fail.
|
||||
|
||||
class ESPFirmwareImage:
|
||||
|
||||
def __init__(self, filename = None):
|
||||
self.segments = []
|
||||
self.entrypoint = 0
|
||||
self.flash_mode = 0
|
||||
self.flash_size_freq = 0
|
||||
|
||||
if filename is not None:
|
||||
f = file(filename, 'rb')
|
||||
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))
|
||||
|
||||
# some sanity check
|
||||
if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
|
||||
raise Exception('Invalid firmware image')
|
||||
|
||||
for i in xrange(segments):
|
||||
(offset, size) = struct.unpack('<II', f.read(8))
|
||||
if offset > 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('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments),
|
||||
self.flash_mode, self.flash_size_freq, self.entrypoint))
|
||||
|
||||
checksum = ESPROM.ESP_CHECKSUM_MAGIC
|
||||
for (offset, size, data) in self.segments:
|
||||
f.write(struct.pack('<II', offset, size))
|
||||
f.write(data)
|
||||
checksum = ESPROM.checksum(data, checksum)
|
||||
|
||||
align = 15-(f.tell() % 16)
|
||||
f.seek(align, 1)
|
||||
f.write(struct.pack('B', checksum))
|
||||
|
||||
|
||||
class ELFFile:
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.symbols = None
|
||||
|
||||
def _fetch_symbols(self):
|
||||
if self.symbols is not None:
|
||||
return
|
||||
self.symbols = {}
|
||||
try:
|
||||
tool_nm = "xtensa-lx106-elf-nm"
|
||||
if os.getenv('XTENSA_CORE')=='lx106':
|
||||
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?"
|
||||
sys.exit(1)
|
||||
for l in proc.stdout:
|
||||
fields = l.strip().split()
|
||||
self.symbols[fields[2]] = int(fields[0], 16)
|
||||
|
||||
def get_symbol_addr(self, sym):
|
||||
self._fetch_symbols()
|
||||
return self.symbols[sym]
|
||||
|
||||
def load_section(self, section):
|
||||
tool_objcopy = "xtensa-lx106-elf-objcopy"
|
||||
if os.getenv('XTENSA_CORE')=='lx106':
|
||||
tool_objcopy = "xt-objcopy"
|
||||
subprocess.check_call([tool_objcopy, "--only-section", section, "-Obinary", self.name, ".tmp.section"])
|
||||
f = open(".tmp.section", "rb")
|
||||
data = f.read()
|
||||
f.close()
|
||||
os.remove(".tmp.section")
|
||||
return data
|
||||
|
||||
|
||||
def arg_auto_int(x):
|
||||
return int(x, 0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description = 'ESP8266 ROM Bootloader Utility', prog = 'esptool')
|
||||
|
||||
parser.add_argument(
|
||||
'--port', '-p',
|
||||
help = 'Serial port device',
|
||||
default = '/dev/ttyUSB0')
|
||||
|
||||
parser.add_argument(
|
||||
'--baud', '-b',
|
||||
help = 'Serial port baud rate',
|
||||
type = arg_auto_int,
|
||||
default = ESPROM.ESP_ROM_BAUD)
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
dest = 'operation',
|
||||
help = 'Run esptool {command} -h for additional help')
|
||||
|
||||
parser_load_ram = subparsers.add_parser(
|
||||
'load_ram',
|
||||
help = 'Download an image to RAM and execute')
|
||||
parser_load_ram.add_argument('filename', help = 'Firmware image')
|
||||
|
||||
parser_dump_mem = subparsers.add_parser(
|
||||
'dump_mem',
|
||||
help = 'Dump arbitrary memory to disk')
|
||||
parser_dump_mem.add_argument('address', help = 'Base address', type = arg_auto_int)
|
||||
parser_dump_mem.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
|
||||
parser_dump_mem.add_argument('filename', help = 'Name of binary dump')
|
||||
|
||||
parser_read_mem = subparsers.add_parser(
|
||||
'read_mem',
|
||||
help = 'Read arbitrary memory location')
|
||||
parser_read_mem.add_argument('address', help = 'Address to read', type = arg_auto_int)
|
||||
|
||||
parser_write_mem = subparsers.add_parser(
|
||||
'write_mem',
|
||||
help = 'Read-modify-write to arbitrary memory location')
|
||||
parser_write_mem.add_argument('address', help = 'Address to write', type = arg_auto_int)
|
||||
parser_write_mem.add_argument('value', help = 'Value', type = arg_auto_int)
|
||||
parser_write_mem.add_argument('mask', help = 'Mask of bits to write', type = arg_auto_int)
|
||||
|
||||
parser_write_flash = subparsers.add_parser(
|
||||
'write_flash',
|
||||
help = 'Write a binary blob to flash')
|
||||
parser_write_flash.add_argument('addr_filename', nargs = '+', help = 'Address and binary file to write there, separated by space')
|
||||
parser_write_flash.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
|
||||
choices = ['40m', '26m', '20m', '80m'], default = '40m')
|
||||
parser_write_flash.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
|
||||
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
|
||||
parser_write_flash.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
|
||||
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
|
||||
|
||||
parser_run = subparsers.add_parser(
|
||||
'run',
|
||||
help = 'Run application code in flash')
|
||||
|
||||
parser_image_info = subparsers.add_parser(
|
||||
'image_info',
|
||||
help = 'Dump headers from an application image')
|
||||
parser_image_info.add_argument('filename', help = 'Image file to parse')
|
||||
|
||||
parser_make_image = subparsers.add_parser(
|
||||
'make_image',
|
||||
help = 'Create an application image from binary files')
|
||||
parser_make_image.add_argument('output', help = 'Output image file')
|
||||
parser_make_image.add_argument('--segfile', '-f', action = 'append', help = 'Segment input file')
|
||||
parser_make_image.add_argument('--segaddr', '-a', action = 'append', help = 'Segment base address', type = arg_auto_int)
|
||||
parser_make_image.add_argument('--entrypoint', '-e', help = 'Address of entry point', type = arg_auto_int, default = 0)
|
||||
|
||||
parser_elf2image = subparsers.add_parser(
|
||||
'elf2image',
|
||||
help = 'Create an application image from ELF file')
|
||||
parser_elf2image.add_argument('input', help = 'Input ELF file')
|
||||
parser_elf2image.add_argument('--output', '-o', help = 'Output filename prefix', type = str)
|
||||
parser_elf2image.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
|
||||
choices = ['40m', '26m', '20m', '80m'], default = '40m')
|
||||
parser_elf2image.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
|
||||
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
|
||||
parser_elf2image.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
|
||||
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
|
||||
|
||||
parser_read_mac = subparsers.add_parser(
|
||||
'read_mac',
|
||||
help = 'Read MAC address from OTP ROM')
|
||||
|
||||
parser_flash_id = subparsers.add_parser(
|
||||
'flash_id',
|
||||
help = 'Read SPI flash manufacturer and device ID')
|
||||
|
||||
parser_read_flash = subparsers.add_parser(
|
||||
'read_flash',
|
||||
help = 'Read SPI flash content')
|
||||
parser_read_flash.add_argument('address', help = 'Start address', type = arg_auto_int)
|
||||
parser_read_flash.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
|
||||
parser_read_flash.add_argument('filename', help = 'Name of binary dump')
|
||||
|
||||
parser_erase_flash = subparsers.add_parser(
|
||||
'erase_flash',
|
||||
help = 'Perform Chip Erase on SPI flash')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create the ESPROM connection object, if needed
|
||||
esp = None
|
||||
if args.operation not in ('image_info','make_image','elf2image'):
|
||||
esp = ESPROM(args.port, args.baud)
|
||||
esp.connect()
|
||||
|
||||
# Do the actual work. Should probably be split into separate functions.
|
||||
if args.operation == 'load_ram':
|
||||
image = ESPFirmwareImage(args.filename)
|
||||
|
||||
print 'RAM boot...'
|
||||
for (offset, size, data) in image.segments:
|
||||
print 'Downloading %d bytes at %08x...' % (size, offset),
|
||||
sys.stdout.flush()
|
||||
esp.mem_begin(size, math.ceil(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 '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('<I', d))
|
||||
if f.tell() % 1024 == 0:
|
||||
print '\r%d bytes read... (%d %%)' % (f.tell(), f.tell()*100/args.size),
|
||||
sys.stdout.flush()
|
||||
print 'Done!'
|
||||
|
||||
elif args.operation == 'write_flash':
|
||||
assert len(args.addr_filename) % 2 == 0
|
||||
|
||||
flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
|
||||
flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
|
||||
flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
|
||||
flash_info = struct.pack('BB', flash_mode, flash_size_freq)
|
||||
|
||||
while args.addr_filename:
|
||||
address = int(args.addr_filename[0], 0)
|
||||
filename = args.addr_filename[1]
|
||||
args.addr_filename = args.addr_filename[2:]
|
||||
image = file(filename, 'rb').read()
|
||||
print 'Erasing flash...'
|
||||
blocks = math.ceil(len(image)/float(esp.ESP_FLASH_BLOCK))
|
||||
esp.flash_begin(blocks*esp.ESP_FLASH_BLOCK, address)
|
||||
seq = 0
|
||||
while len(image) > 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]
|
||||
# Fix sflash config data
|
||||
if address == 0 and seq == 0 and block[0] == '\xe9':
|
||||
block = block[0:2] + flash_info + block[4:]
|
||||
# Pad the last block
|
||||
block = block + '\xff' * (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.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
|
||||
image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
|
||||
image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
|
||||
|
||||
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':
|
||||
mac = esp.read_mac()
|
||||
print 'MAC: %s' % ':'.join(map(lambda x: '%02x'%x, mac))
|
||||
|
||||
elif args.operation == 'flash_id':
|
||||
flash_id = esp.flash_id()
|
||||
print 'Manufacturer: %02x' % (flash_id & 0xff)
|
||||
print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)
|
||||
|
||||
elif args.operation == 'read_flash':
|
||||
print 'Please wait...'
|
||||
file(args.filename, 'wb').write(esp.flash_read(args.address, 1024, int(math.ceil(args.size / 1024.)))[:args.size])
|
||||
|
||||
elif args.operation == 'erase_flash':
|
||||
esp.flash_erase()
|
33
os/flash.sh
Executable file
33
os/flash.sh
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "One parameter required: the device of the serial interface"
|
||||
echo "$0 <device>"
|
||||
echo "e.g.:"
|
||||
echo "$0 ttyUSB0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEVICE=$1
|
||||
|
||||
# check the serial connection
|
||||
|
||||
if [ ! -c /dev/$DEVICE ]; then
|
||||
echo "/dev/$DEVICE does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f esptool.py ]; then
|
||||
echo "Cannot found the required tool:"
|
||||
echo "esptool.py"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo ./esptool.py --port /dev/$DEVICE read_mac
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error reading the MAC -> set the device into the bootloader!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo ./esptool.py --port /dev/$DEVICE write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin
|
71
programESP.sh
Normal file
71
programESP.sh
Normal file
@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEVICE=/dev/ttyUSB0
|
||||
SLEEPTIME=0.2
|
||||
TCPPORT=2323
|
||||
|
||||
function usage() {
|
||||
echo "$0 usage:"
|
||||
echo "$0 serial|ip fileOnHost.lua (fileOnESP.lua)"
|
||||
echo ""
|
||||
echo "The flash logic can be done via ethernet or serial"
|
||||
echo "The first filename is mandatory!"
|
||||
echo ""
|
||||
echo "The second filename is the filename on the LUA devic."
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo -e "$0 serial hello.txt\tSends the content of hello.txt to the ESP (directly as if you type it)"
|
||||
echo -e "$0 serial init_example.lua init.lua\tUpdates the init.lua on the ESP"
|
||||
echo " (The init.lua file is executed each time, the ESP starts)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
serial)
|
||||
IP=""
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "Please run as root"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]];then
|
||||
IP=$1
|
||||
else
|
||||
usage
|
||||
fi
|
||||
esac
|
||||
|
||||
|
||||
if [ ! -f $2 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ "$IP" != "" ]; then
|
||||
echo "Using network: $IP "
|
||||
echo "Checking connection ..."
|
||||
ping -c 3 $IP >> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Cannot find ESP at $IP"
|
||||
exit 1
|
||||
fi
|
||||
DEVICE=/dev/tcp/$IP/$TCPPORT
|
||||
fi
|
||||
|
||||
# The flashing logic
|
||||
if [ "$3" == "" ]; then
|
||||
echo "Sending to shell..."
|
||||
cat $2 | while read a; do echo -e "$a\r" >> $DEVICE; echo -e "$a"; sleep $SLEEPTIME; done
|
||||
else
|
||||
echo "Writing $3 on the ESP"
|
||||
echo "========================="
|
||||
echo "" >> $DEVICE; sleep $SLEEPTIME
|
||||
echo "file.open(\"$3\",\"w\")" >> $DEVICE; sleep $SLEEPTIME
|
||||
cat $2 | while read a; do echo "file.writeline([[${a}]])" >> $DEVICE; echo -e "\r" >> $DEVICE; echo "$a"; sleep $SLEEPTIME; done
|
||||
# Close the init file
|
||||
echo "file.close()" >> $DEVICE; sleep $SLEEPTIME
|
||||
echo "========================="
|
||||
echo "now login on ESP and call"
|
||||
echo "node.restart()"
|
||||
fi
|
3
wlancfg.lua.example
Normal file
3
wlancfg.lua.example
Normal file
@ -0,0 +1,3 @@
|
||||
-- Tell the chip to connect to thi access point
|
||||
wifi.setmode(wifi.STATION)
|
||||
wifi.sta.config("SSID","password")
|
126
wordclock.lua
Executable file
126
wordclock.lua
Executable file
@ -0,0 +1,126 @@
|
||||
--
|
||||
|
||||
-- Return the leds to use
|
||||
-- the granuality is 5 minutes
|
||||
function display_timestat(hours, minutes, longmode)
|
||||
if (longmode == nil) then
|
||||
longmode=0
|
||||
end
|
||||
|
||||
-- generate an empty return type
|
||||
local ret = { itis=0, fiveMin=0, tenMin=0, beforeMin=0, threeHour=0, quater=0, after=0, beforeHour=0, half=0, s=0,
|
||||
one=0, two=0, three=0, four=0, five=0, six=0, seven=0, eight=0, nine=0, ten=0, eleven=0, twelve=0,
|
||||
clock=0, sr_nc=0, min1=0, min2=0, min3=0, min4=0 }
|
||||
|
||||
-- return black screen if there is no real time given
|
||||
if (hours == nil or minutes == nil) then
|
||||
return ret
|
||||
end
|
||||
|
||||
-- transcode minutes
|
||||
local minutesLeds = minutes%5
|
||||
minutes=minutes/5
|
||||
|
||||
|
||||
|
||||
-- "It is" only display each half hour and each hour
|
||||
-- or if longmode is set
|
||||
if ((longmode==1)
|
||||
or (minutes==0)
|
||||
or (minutes==6)) then
|
||||
ret.itis=1
|
||||
end
|
||||
|
||||
-- Handle minutes
|
||||
if (minutes > 0) then
|
||||
if (minutes==1) then
|
||||
ret.fiveMin=1
|
||||
ret.after=1
|
||||
elseif (minutes==2) then
|
||||
ret.tenMin=1
|
||||
ret.after=1
|
||||
elseif (minutes==3) then
|
||||
ret.quater=1
|
||||
elseif (minutes==4) then
|
||||
ret.tenMin=1
|
||||
ret.half=1
|
||||
ret.beforeMin=1
|
||||
elseif (minutes==5) then
|
||||
ret.fiveMin=1
|
||||
ret.half=1
|
||||
ret.beforeMin=1
|
||||
elseif (minutes==6) then
|
||||
ret.half=1
|
||||
elseif (minutes==7) then
|
||||
ret.fiveMin=1
|
||||
ret.half=1
|
||||
ret.afterMin=1
|
||||
elseif (minutes==8) then
|
||||
ret.tenMin=1
|
||||
ret.half=1
|
||||
ret.afterMin=1
|
||||
elseif (minutes==9) then
|
||||
ret.quater=1
|
||||
ret.threeHour=1
|
||||
elseif (minutes==10) then
|
||||
ret.tenMin=1
|
||||
ret.beforeHour=1
|
||||
elseif (minutes==11) then
|
||||
ret.fiveMin=1
|
||||
ret.beforeHour=1
|
||||
end
|
||||
|
||||
if (minutes >= 4) then
|
||||
hours=hours+1
|
||||
end
|
||||
else
|
||||
ret.clock=1
|
||||
end
|
||||
-- Display the minutes as as extra gimmic on min1 to min 4 to display the cut number
|
||||
if (minutesLeds==1) then
|
||||
ret.min1=1
|
||||
elseif (minutesLeds==2) then
|
||||
ret.min2=1
|
||||
elseif (minutesLeds==3) then
|
||||
ret.min3=1
|
||||
elseif (minutesLeds==4) then
|
||||
ret.min4=1
|
||||
end
|
||||
|
||||
-- handle hours
|
||||
if (hours > 12) then
|
||||
hours = hours - 12
|
||||
end
|
||||
|
||||
if (hours==0) then
|
||||
hours=12
|
||||
end
|
||||
|
||||
if (hours == 1) then
|
||||
ret.one=1
|
||||
elseif (hours == 2) then
|
||||
ret.two=1
|
||||
elseif (hours == 3) then
|
||||
ret.three=1
|
||||
elseif (hours == 4) then
|
||||
ret.four=1
|
||||
elseif (hours == 5) then
|
||||
ret.five=1
|
||||
elseif (hours == 6) then
|
||||
ret.six=1
|
||||
elseif (hours == 7) then
|
||||
ret.seven=1
|
||||
elseif (hours == 8) then
|
||||
ret.eight=1
|
||||
elseif (hours == 9) then
|
||||
ret.nine=1
|
||||
elseif (hours == 10) then
|
||||
ret.ten=1
|
||||
elseif (hours == 11) then
|
||||
ret.eleven=1
|
||||
elseif (hours == 12) then
|
||||
ret.twelve=1
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
Loading…
Reference in New Issue
Block a user